@yugenlab/vaayu 0.1.8 → 0.1.10

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 (29) hide show
  1. package/README.md +1 -1
  2. package/chunks/{chunk-7UOXFHEB.js → chunk-77725AR7.js} +416 -397
  3. package/chunks/{chunk-YSC77CKZ.js → chunk-AGK3A7R7.js} +2844 -3208
  4. package/chunks/{chunk-DOQMEQ5S.js → chunk-AS3DJFY3.js} +5 -5
  5. package/chunks/{chunk-NHRBVSN3.js → chunk-HIYHTWFW.js} +44 -9
  6. package/chunks/{chunk-IGBRBFXX.js → chunk-JGI4SDWS.js} +2 -2
  7. package/chunks/{chunk-D3RVJGO7.js → chunk-M7THR63C.js} +48 -74
  8. package/chunks/{chunk-OBYBBGHA.js → chunk-N22M7D4P.js} +118 -106
  9. package/chunks/{chunk-PJEYJQ2C.js → chunk-O4KV7TFP.js} +2 -2
  10. package/chunks/{chunk-S2HDNNC7.js → chunk-OT4G2L46.js} +552 -641
  11. package/chunks/chunk-TND3MU4Z.js +426 -0
  12. package/chunks/{chunk-LVE2EOOH.js → chunk-VJHNE47S.js} +84 -75
  13. package/chunks/{consolidation-indexer-CD6DS2HO.js → consolidation-indexer-VKQ6DNU3.js} +4 -4
  14. package/chunks/{day-consolidation-U3X6P4ZG.js → day-consolidation-BH3QU2SZ.js} +6 -2
  15. package/chunks/{graphrag-LAZSXLLI.js → graphrag-D7OXWAWD.js} +2 -2
  16. package/chunks/{hierarchical-temporal-search-ETXYYJZK.js → hierarchical-temporal-search-PVHVA3NZ.js} +2 -2
  17. package/chunks/{hybrid-search-TX6T3KYH.js → hybrid-search-G2NAJKJ7.js} +4 -4
  18. package/chunks/{periodic-consolidation-4MACZE6S.js → periodic-consolidation-LMYMNS4Q.js} +2 -2
  19. package/chunks/{recall-IUPQCBYP.js → recall-ZNL4DJ2L.js} +3 -3
  20. package/chunks/{search-HHSVHBXC.js → search-35JMSGUT.js} +3 -3
  21. package/chunks/{session-store-NDUDYAC7.js → session-store-3BRPGC6P.js} +2 -2
  22. package/chunks/{src-ZAKUL232.js → src-Y3TGMINC.js} +12 -12
  23. package/chunks/vasana-engine-MU25OQ23.js +30 -0
  24. package/gateway.js +492 -226
  25. package/package.json +1 -1
  26. package/vaayu-mark-npm.png +0 -0
  27. package/chunks/chunk-TEQKXGIK.js +0 -752
  28. package/chunks/vasana-engine-G6BPOFX7.js +0 -10
  29. package/vaayu-mark.png +0 -0
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-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";
10
+ import "./chunks/chunk-AGK3A7R7.js";
11
+ import "./chunks/chunk-AS3DJFY3.js";
12
+ import "./chunks/chunk-77725AR7.js";
13
+ import "./chunks/chunk-M7THR63C.js";
14
+ import "./chunks/chunk-N22M7D4P.js";
15
+ import "./chunks/chunk-JGI4SDWS.js";
16
16
  import "./chunks/chunk-IEKAYVA3.js";
17
17
  import {
18
18
  IMessageAdapter,
@@ -25,10 +25,10 @@ import {
25
25
  } from "./chunks/chunk-MJ74G5RB.js";
26
26
  import {
27
27
  searchSessions
28
- } from "./chunks/chunk-PJEYJQ2C.js";
28
+ } from "./chunks/chunk-O4KV7TFP.js";
29
29
  import "./chunks/chunk-6556EKOB.js";
30
- import "./chunks/chunk-S2HDNNC7.js";
31
- import "./chunks/chunk-LVE2EOOH.js";
30
+ import "./chunks/chunk-OT4G2L46.js";
31
+ import "./chunks/chunk-VJHNE47S.js";
32
32
  import {
33
33
  addTurn,
34
34
  createSession,
@@ -38,9 +38,9 @@ import {
38
38
  listTurnsWithTimestamps,
39
39
  loadSession,
40
40
  updateSessionMeta
41
- } from "./chunks/chunk-NHRBVSN3.js";
41
+ } from "./chunks/chunk-HIYHTWFW.js";
42
42
  import "./chunks/chunk-JAWZ7ANC.js";
43
- import "./chunks/chunk-TEQKXGIK.js";
43
+ import "./chunks/chunk-TND3MU4Z.js";
44
44
  import "./chunks/chunk-YJRXLRTE.js";
45
45
  import "./chunks/chunk-U62ABYKD.js";
46
46
  import "./chunks/chunk-UZ6OIVEC.js";
@@ -18721,8 +18721,7 @@ async function runProviderSlashCommand(params) {
18721
18721
  if (status)
18722
18722
  statusBits.push(status.replace("_", " "));
18723
18723
  if (cooldown) {
18724
- const until = new Date(cooldown.until).toISOString();
18725
- statusBits.push(`cooldown ${cooldown.reason} (${cooldown.failures}x, ${formatAge(until)} left)`);
18724
+ statusBits.push("temporary reroute active");
18726
18725
  }
18727
18726
  const checkedAge = formatAge(health?.checkedAt);
18728
18727
  if (checkedAge)
@@ -18894,15 +18893,15 @@ Use \`/provider list\` to see available providers.`;
18894
18893
  if (!currentProvider)
18895
18894
  return "No active provider to reset.";
18896
18895
  clearProviderCooldown(currentProvider);
18897
- return `Cleared cooldown for \`${currentProvider}\`.`;
18896
+ return `Provider routing state reset for \`${currentProvider}\`.`;
18898
18897
  }
18899
18898
  if (targetRaw === "all" || targetRaw === "*") {
18900
18899
  clearAllProviderCooldowns();
18901
- return "Cleared cooldowns for all providers.";
18900
+ return "Provider routing state reset for all providers.";
18902
18901
  }
18903
18902
  const providerId = resolveProviderAlias(providerArgs.providerId ?? "", providers);
18904
18903
  clearProviderCooldown(providerId);
18905
- return providers.get(providerId) ? `Cleared cooldown for \`${providerId}\`.` : `Cleared cooldown for \`${providerId}\` (provider not currently configured).`;
18904
+ return providers.get(providerId) ? `Provider routing state reset for \`${providerId}\`.` : `Provider routing state reset for \`${providerId}\` (provider not currently configured).`;
18906
18905
  }
18907
18906
  case "help":
18908
18907
  default:
@@ -28380,12 +28379,12 @@ function findBlockedExplicitToolName(params) {
28380
28379
  return isToolAllowed2(toolPolicy, matched.name) ? null : matched.name;
28381
28380
  }
28382
28381
  function shouldRunPlanner(params) {
28383
- const { trimmed, isPureGreeting: isPureGreeting2, isPureAck: isPureAck2, assistantName, looksLikeWeatherAsk: looksLikeWeatherAsk2, looksLikeLanDevicesAsk: looksLikeLanDevicesAsk2, hasNluSignal } = params;
28382
+ const { trimmed, isPureGreeting: isPureGreeting2, isPureAck: isPureAck2, assistantName, looksLikeWeatherAsk: looksLikeWeatherAsk2, looksLikeLanDevicesAsk: looksLikeLanDevicesAsk2, actionabilityKind, hasNluSignal } = params;
28384
28383
  const skipPlanner = isPureGreeting2(trimmed, assistantName) || isPureAck2(trimmed, assistantName);
28385
28384
  if (skipPlanner)
28386
28385
  return false;
28387
28386
  const tokens = trimmed.split(/\s+/).filter(Boolean);
28388
- if (hasNluSignal) {
28387
+ if (hasNluSignal || actionabilityKind === "tool" || actionabilityKind === "command") {
28389
28388
  return true;
28390
28389
  }
28391
28390
  if (tokens.length <= 2) {
@@ -28850,17 +28849,20 @@ async function runPlannerWithFallback(params) {
28850
28849
  addPlannerAttempt(entry.providerId, configuredModel ?? plannerModel);
28851
28850
  }
28852
28851
  const plannerMaxAttempts = resolvePlannerMaxAttempts(config);
28853
- const limitedPlannerAttempts = plannerAttempts.slice(0, plannerMaxAttempts);
28854
- if (plannerAttempts.length > limitedPlannerAttempts.length) {
28852
+ const candidatePlannerAttempts = plannerAttempts;
28853
+ if (candidatePlannerAttempts.length > plannerMaxAttempts) {
28855
28854
  logger.info("planner_attempts_limited", {
28856
- totalCandidates: plannerAttempts.length,
28855
+ totalCandidates: candidatePlannerAttempts.length,
28857
28856
  maxAttempts: plannerMaxAttempts
28858
28857
  });
28859
28858
  }
28860
28859
  let plan = null;
28861
28860
  let plannerResult = null;
28862
28861
  let plannerError;
28863
- for (const attempt of limitedPlannerAttempts) {
28862
+ let attemptedPlannerCount = 0;
28863
+ for (const attempt of candidatePlannerAttempts) {
28864
+ if (attemptedPlannerCount >= plannerMaxAttempts)
28865
+ break;
28864
28866
  const cooldown = getProviderCooldown(attempt.providerId);
28865
28867
  if (cooldown) {
28866
28868
  plannerError = new Error(`Provider ${attempt.providerId} cooling down (${cooldown.reason})`);
@@ -28886,6 +28888,7 @@ async function runPlannerWithFallback(params) {
28886
28888
  const attemptProvider = getProvider(attempt.providerId);
28887
28889
  if (!attemptProvider)
28888
28890
  continue;
28891
+ attemptedPlannerCount += 1;
28889
28892
  plannerProvider = attemptProvider;
28890
28893
  plannerProviderId = attempt.providerId;
28891
28894
  plannerModel = attempt.model;
@@ -29289,6 +29292,7 @@ async function handleToolPlanning(params) {
29289
29292
  assistantName: profile.assistantName,
29290
29293
  looksLikeWeatherAsk: looksLikeWeatherAsk2,
29291
29294
  looksLikeLanDevicesAsk,
29295
+ actionabilityKind: routingResult.actionability?.kind,
29292
29296
  hasNluSignal: Boolean(nluResult?.intent) || Boolean(nluResult?.toolHints?.length)
29293
29297
  }) && !hasDeterministicPlan) {
29294
29298
  return null;
@@ -30159,7 +30163,7 @@ async function resolveProviderAndModel(params) {
30159
30163
  });
30160
30164
  }
30161
30165
  }
30162
- const shouldPreferToolCapableProvider = Boolean(toolPresence?.hasTools) && toolPresence?.actionability === "tool";
30166
+ const shouldPreferToolCapableProvider = Boolean(toolPresence?.hasTools) && (toolPresence?.actionability === "tool" || toolPresence?.actionability === "command");
30163
30167
  if (shouldPreferToolCapableProvider) {
30164
30168
  const currentProviderType = providers.get(resolvedProviderId)?.type;
30165
30169
  const currentPriority = getFallbackPriority(currentProviderType);
@@ -31591,7 +31595,7 @@ function sumSignals(signals) {
31591
31595
  return total;
31592
31596
  }
31593
31597
  function buildCandidate(params) {
31594
- const { candidate, providers, complexitySignal, actionabilityKind, policyLabel, hasTools } = params;
31598
+ const { candidate, providers, complexitySignal, actionabilityKind, policyLabel, hasTools, coolingProviderIds, providerHealth } = params;
31595
31599
  const signals = [];
31596
31600
  const pushSignal = (name, weight, value, note) => {
31597
31601
  signals.push({
@@ -31628,6 +31632,13 @@ function buildCandidate(params) {
31628
31632
  if (!providers.get(candidate.decision.target.providerId)) {
31629
31633
  pushSignal("provider_missing_penalty", 0.6, -1);
31630
31634
  }
31635
+ if (coolingProviderIds?.has(candidate.decision.target.providerId)) {
31636
+ pushSignal("provider_cooldown_penalty", 0.8, -1);
31637
+ }
31638
+ const health = providerHealth?.[candidate.decision.target.providerId];
31639
+ if (health && health.status !== "ok") {
31640
+ pushSignal("provider_health_penalty", 0.8, -1, health.status);
31641
+ }
31631
31642
  return {
31632
31643
  source: candidate.source,
31633
31644
  target: candidate.decision.target,
@@ -31661,7 +31672,9 @@ function scoreRoutingDecision(params) {
31661
31672
  complexitySignal: params.complexitySignal,
31662
31673
  actionabilityKind: params.actionabilityKind,
31663
31674
  policyLabel: params.policyLabel,
31664
- hasTools: params.hasTools
31675
+ hasTools: params.hasTools,
31676
+ coolingProviderIds: params.coolingProviderIds,
31677
+ providerHealth: params.providerHealth
31665
31678
  }));
31666
31679
  scored.sort((a, b) => {
31667
31680
  if (b.score !== a.score)
@@ -31882,7 +31895,9 @@ async function resolveRoutingDecision(input) {
31882
31895
  complexitySignal,
31883
31896
  actionabilityKind: actionability.kind,
31884
31897
  policyLabel: policyClassifier.policy,
31885
- hasTools
31898
+ hasTools,
31899
+ coolingProviderIds: new Set(listProviderCooldowns().map((entry) => entry.providerId)),
31900
+ providerHealth: runtime.providerHealth
31886
31901
  }) : { decision: null, trace: null };
31887
31902
  const routingDecision = autoRouting ? scoringResult.decision ?? margaRoutingDecision ?? heuristicRoutingDecision : null;
31888
31903
  const earlyRoutingResult = {
@@ -32449,11 +32464,11 @@ async function runChatWithFallback(params) {
32449
32464
  listProviders: listProviders2
32450
32465
  });
32451
32466
  const maxAttempts = resolveChatMaxAttempts(config);
32452
- const attempts = builtAttempts.slice(0, maxAttempts);
32453
- if (builtAttempts.length > attempts.length) {
32467
+ const attempts = builtAttempts;
32468
+ if (attempts.length > maxAttempts) {
32454
32469
  logger.info("provider_attempts_limited", {
32455
32470
  sessionId,
32456
- totalCandidates: builtAttempts.length,
32471
+ totalCandidates: attempts.length,
32457
32472
  maxAttempts
32458
32473
  });
32459
32474
  }
@@ -32478,6 +32493,8 @@ async function runChatWithFallback(params) {
32478
32493
  let attemptedProviderCount = 0;
32479
32494
  const lastAnthropicCall = lastAnthropicCallAt.get(sessionId);
32480
32495
  for (const attempt of attempts) {
32496
+ if (attemptedProviderCount >= maxAttempts)
32497
+ break;
32481
32498
  const provider = getProvider(attempt.providerId);
32482
32499
  if (!provider) {
32483
32500
  lastError = new Error("Provider not found");
@@ -33103,7 +33120,19 @@ function storeSemanticResponseCache(params) {
33103
33120
  return true;
33104
33121
  }
33105
33122
 
33106
- // apps/gateway/dist/agent/loop-chat-result.js
33123
+ // apps/gateway/dist/agent/smalltalk-fallback.js
33124
+ function inferSmalltalkActionability(actionability, messageText, profile, heuristic) {
33125
+ if (actionability.kind === "smalltalk")
33126
+ return actionability;
33127
+ const normalized = (messageText ?? "").trim();
33128
+ if (normalized && heuristic.isPureGreeting(normalized, profile.assistantName)) {
33129
+ return { kind: "smalltalk", reason: "smalltalk_greeting" };
33130
+ }
33131
+ if (normalized && heuristic.isPureAck(normalized, profile.assistantName)) {
33132
+ return { kind: "smalltalk", reason: "smalltalk_ack" };
33133
+ }
33134
+ return actionability;
33135
+ }
33107
33136
  function resolveSmalltalkProviderFallback(params) {
33108
33137
  const { actionability, escalation, buildSmalltalkReply: buildSmalltalkReply2, profile, channel, locale } = params;
33109
33138
  if (actionability.kind !== "smalltalk")
@@ -33114,6 +33143,8 @@ function resolveSmalltalkProviderFallback(params) {
33114
33143
  const model = kind === "ack" ? "smalltalk.ack" : "smalltalk.greeting";
33115
33144
  return { model, content: buildSmalltalkReply2(profile, kind, channel, locale) };
33116
33145
  }
33146
+
33147
+ // apps/gateway/dist/agent/loop-chat-result.js
33117
33148
  async function handleChatPhase(input) {
33118
33149
  const { deps, session, payload, runSignal, runId, routingDecision, routingResult, actionability, margaDecision, resolvedProviderId, resolvedModel, semanticCacheCategory, semanticCacheRule, routingText, context, retrievalHits, retrievalDecision, normalizedOutboundMeta, combinedSystem, resolveModelAlias: resolveModelAlias2, normalizeModelId: normalizeModelId2, listProviderModels, profile, locale, toolPolicy, budgetFallbackTarget, maybeAppendSmritiMemorySafe, allowMemory, memoryAllowed, memoryManager, stripModelThinking: stripModelThinking2 } = input;
33119
33150
  const { runtime, formatProviderError: formatProviderError2, lastAnthropicCallAt } = deps;
@@ -33229,7 +33260,8 @@ async function handleChatPhase(input) {
33229
33260
  });
33230
33261
  if (!chatResult.ok) {
33231
33262
  const escalation = chatResult.escalation;
33232
- if (escalation.reason !== "request_aborted" && actionability.kind !== "smalltalk") {
33263
+ const effectiveActionability = inferSmalltalkActionability(actionability, payload.message.text, profile, { isPureGreeting: deps.isPureGreeting, isPureAck: deps.isPureAck });
33264
+ if (escalation.reason !== "request_aborted" && effectiveActionability.kind !== "smalltalk") {
33233
33265
  const degradedToolResult = await handleToolPlanning({
33234
33266
  session,
33235
33267
  message: payload.message,
@@ -33282,7 +33314,7 @@ async function handleChatPhase(input) {
33282
33314
  }
33283
33315
  }
33284
33316
  const smalltalkFallback = resolveSmalltalkProviderFallback({
33285
- actionability,
33317
+ actionability: effectiveActionability,
33286
33318
  escalation,
33287
33319
  buildSmalltalkReply: deps.buildSmalltalkReply,
33288
33320
  profile,
@@ -38768,8 +38800,18 @@ var nluSchema = external_exports.object({
38768
38800
  embeddingThreshold: external_exports.number().min(0).max(1).default(0.62),
38769
38801
  // GLiNER v2.1 endpoint for language-agnostic NER slot filling.
38770
38802
  glinerEndpoint: external_exports.string().default("http://localhost:8501"),
38803
+ // GLiNER API path (supports FastAPI adapters like /gliner-2).
38804
+ glinerPath: external_exports.string().default("/gliner-2"),
38771
38805
  // When true, use GLiNER for non-English entity extraction.
38772
38806
  glinerEnabled: external_exports.boolean().default(true),
38807
+ // GLiNER task field for schema-driven adapters.
38808
+ glinerTask: external_exports.string().default("entity_extraction"),
38809
+ // GLiNER model field passed to adapter.
38810
+ glinerModel: external_exports.string().default("gliner-large-v2.1"),
38811
+ // Minimum score threshold for accepted entities.
38812
+ glinerThreshold: external_exports.number().min(0).max(1).default(0.4),
38813
+ // Optional additional request headers (for auth/proxy adapters).
38814
+ glinerHeaders: external_exports.record(external_exports.string()).default({}),
38773
38815
  // GLiNER request timeout in ms.
38774
38816
  glinerTimeoutMs: external_exports.number().int().min(100).max(1e4).default(800),
38775
38817
  // Circuit-breaker cooldown in ms after GLiNER failures/timeouts.
@@ -39488,9 +39530,36 @@ function applyNluEnv(params) {
39488
39530
  if (process.env.VAAYU_NLU_GLINER_ENDPOINT) {
39489
39531
  nlu.glinerEndpoint = process.env.VAAYU_NLU_GLINER_ENDPOINT;
39490
39532
  }
39533
+ if (process.env.VAAYU_NLU_GLINER_PATH) {
39534
+ nlu.glinerPath = process.env.VAAYU_NLU_GLINER_PATH;
39535
+ }
39491
39536
  if (process.env.VAAYU_NLU_GLINER_ENABLED) {
39492
39537
  nlu.glinerEnabled = process.env.VAAYU_NLU_GLINER_ENABLED === "true";
39493
39538
  }
39539
+ if (process.env.VAAYU_NLU_GLINER_TASK) {
39540
+ nlu.glinerTask = process.env.VAAYU_NLU_GLINER_TASK;
39541
+ }
39542
+ if (process.env.VAAYU_NLU_GLINER_MODEL) {
39543
+ nlu.glinerModel = process.env.VAAYU_NLU_GLINER_MODEL;
39544
+ }
39545
+ if (process.env.VAAYU_NLU_GLINER_THRESHOLD) {
39546
+ const parsed = Number(process.env.VAAYU_NLU_GLINER_THRESHOLD);
39547
+ if (Number.isFinite(parsed)) {
39548
+ nlu.glinerThreshold = parsed;
39549
+ }
39550
+ }
39551
+ if (process.env.VAAYU_NLU_GLINER_HEADERS) {
39552
+ try {
39553
+ const parsed = JSON.parse(process.env.VAAYU_NLU_GLINER_HEADERS);
39554
+ if (parsed && typeof parsed === "object") {
39555
+ const filteredEntries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
39556
+ if (filteredEntries.length > 0) {
39557
+ nlu.glinerHeaders = Object.fromEntries(filteredEntries);
39558
+ }
39559
+ }
39560
+ } catch {
39561
+ }
39562
+ }
39494
39563
  if (process.env.VAAYU_NLU_GLINER_TIMEOUT_MS) {
39495
39564
  const parsed = Number.parseInt(process.env.VAAYU_NLU_GLINER_TIMEOUT_MS, 10);
39496
39565
  if (Number.isFinite(parsed)) {
@@ -50551,13 +50620,9 @@ async function handleSlashStatus(ctx, commandName, _commandArgs) {
50551
50620
  const activeCooldowns = listProviderCooldowns();
50552
50621
  if (activeCooldowns.length) {
50553
50622
  out.push("");
50554
- out.push("**Provider Cooldowns**");
50555
- for (const cooldown of activeCooldowns.slice(0, 5)) {
50556
- out.push(`- ${cooldown.providerId}: \`${cooldown.reason}\` \`${Math.max(1, Math.ceil((cooldown.until - Date.now()) / 1e3))}s\` failures=\`${cooldown.failures}\``);
50557
- }
50558
- if (activeCooldowns.length > 5) {
50559
- out.push(`- +${activeCooldowns.length - 5} more`);
50560
- }
50623
+ out.push("**Provider Routing**");
50624
+ out.push(`- temporary reroutes active: \`${activeCooldowns.length}\``);
50625
+ out.push("- gateway is auto-switching providers in the background.");
50561
50626
  }
50562
50627
  if (ollamaHealth || ollamaEntry) {
50563
50628
  const baseUrl = ollamaHealth?.baseUrl ?? ollamaEntry?.baseUrl ?? "http://127.0.0.1:11434";
@@ -52809,9 +52874,48 @@ If this should be allowed, enable it with /tool enable ${params.toolName} or in
52809
52874
  }
52810
52875
 
52811
52876
  // apps/gateway/dist/channel/plaintext-format.js
52812
- function formatPlainTextReply(content) {
52877
+ var sanitizeInline = (value) => value.replace(/\r\n/g, " ").replace(/[\r\n\t]+/g, " ").replace(/\u0000/g, "").replace(/\s+/g, " ").trim();
52878
+ var buildCollectModelLabel = (options) => {
52879
+ if (!options)
52880
+ return "";
52881
+ const providerId = sanitizeInline(options.providerId ?? "");
52882
+ const model = sanitizeInline(options.model ?? "");
52883
+ if (providerId && model)
52884
+ return `${providerId}/${model}`;
52885
+ return providerId || model;
52886
+ };
52887
+ function formatCollectReply(content, options) {
52888
+ const lines = ["Collect reply"];
52889
+ const assistant = sanitizeInline(options.assistantName ?? "");
52890
+ const tone = sanitizeInline(options.tone ?? "");
52891
+ const sessionId = sanitizeInline(options.sessionId ?? "");
52892
+ const userId = sanitizeInline(options.userId ?? "");
52893
+ const queueMode = sanitizeInline(options.collectMode?.queueMode ?? "");
52894
+ const model = buildCollectModelLabel(options.collectMode);
52895
+ if (assistant)
52896
+ lines.push(`Assistant: ${assistant}`);
52897
+ if (tone)
52898
+ lines.push(`Tone: ${tone}`);
52899
+ if (queueMode)
52900
+ lines.push(`Queue: ${queueMode}`);
52901
+ if (sessionId)
52902
+ lines.push(`Session: ${sessionId}`);
52903
+ if (userId)
52904
+ lines.push(`User: ${userId}`);
52905
+ if (model)
52906
+ lines.push(`Model: ${model}`);
52907
+ if (!content)
52908
+ return lines.join("\n");
52909
+ return `${lines.join("\n")}
52910
+
52911
+ ${content}`;
52912
+ }
52913
+ function formatPlainTextReply(content, options = {}) {
52813
52914
  const normalized = normalizeAgentReply(content);
52814
- return normalized.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/_(.+?)_/g, "$1").replace(/`(.+?)`/g, "$1").replace(/```[\s\S]*?```/g, (match) => match.replace(/```\w*\n?/g, "").replace(/```/g, "")).replace(/^#{1,6}\s+/gm, "").trim();
52915
+ const cleaned = normalized.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/_(.+?)_/g, "$1").replace(/`(.+?)`/g, "$1").replace(/```[\s\S]*?```/g, (match) => match.replace(/```\w*\n?/g, "").replace(/```/g, "")).replace(/^#{1,6}\s+/gm, "").trim();
52916
+ if (!options.collectMode?.enabled)
52917
+ return cleaned;
52918
+ return formatCollectReply(cleaned, options);
52815
52919
  }
52816
52920
  function truncatePlainText(text, maxChars) {
52817
52921
  if (text.length <= maxChars)
@@ -52824,7 +52928,10 @@ var DM_MAX_CHARS = 1e4;
52824
52928
  var TWEET_MAX_CHARS = 280;
52825
52929
  async function sendTwitterDmReply(params) {
52826
52930
  const { ctx, conversationId, content } = params;
52827
- const plain = formatPlainTextReply(content);
52931
+ const plain = formatPlainTextReply(content, {
52932
+ assistantName: ctx.assistantName,
52933
+ ...params.formatOptions ?? {}
52934
+ });
52828
52935
  const text = truncatePlainText(plain, DM_MAX_CHARS);
52829
52936
  try {
52830
52937
  await ctx.adapter.sendDm(conversationId, text);
@@ -52837,7 +52944,10 @@ async function sendTwitterDmReply(params) {
52837
52944
  }
52838
52945
  async function sendTwitterTweetReply(params) {
52839
52946
  const { ctx, content, replyToId } = params;
52840
- const plain = formatPlainTextReply(content);
52947
+ const plain = formatPlainTextReply(content, {
52948
+ assistantName: ctx.assistantName,
52949
+ ...params.formatOptions ?? {}
52950
+ });
52841
52951
  const text = truncatePlainText(plain, TWEET_MAX_CHARS);
52842
52952
  try {
52843
52953
  await ctx.adapter.sendTweet(text, replyToId);
@@ -52949,7 +53059,10 @@ function setupTwitter(deps) {
52949
53059
  var WA_MAX_CHARS = 4096;
52950
53060
  async function sendWhatsAppReply(params) {
52951
53061
  const { ctx, to, content } = params;
52952
- const plain = formatPlainTextReply(content);
53062
+ const plain = formatPlainTextReply(content, {
53063
+ assistantName: ctx.assistantName,
53064
+ ...params.formatOptions ?? {}
53065
+ });
52953
53066
  const text = truncatePlainText(plain, WA_MAX_CHARS);
52954
53067
  try {
52955
53068
  await ctx.adapter.sendText(to, text);
@@ -53044,7 +53157,10 @@ function setupWhatsApp(deps) {
53044
53157
  // apps/gateway/dist/channel/imessage-outbound.js
53045
53158
  async function sendIMessageReply(params) {
53046
53159
  const { ctx, chatGuid, content } = params;
53047
- const plain = formatPlainTextReply(content);
53160
+ const plain = formatPlainTextReply(content, {
53161
+ assistantName: ctx.assistantName,
53162
+ ...params.formatOptions ?? {}
53163
+ });
53048
53164
  try {
53049
53165
  await ctx.adapter.sendText(chatGuid, plain);
53050
53166
  } catch (error) {
@@ -55649,136 +55765,6 @@ function fuzzyHasKeyword(text, keywords) {
55649
55765
  return false;
55650
55766
  }
55651
55767
 
55652
- // packages/nlu/src/rules/location.ts
55653
- var cleanLocation = (value) => {
55654
- let cleaned = value.trim();
55655
- if (!cleaned) return cleaned;
55656
- cleaned = cleaned.replace(/^[\s"']+/, "").replace(/[\s"']+$/, "");
55657
- cleaned = cleaned.replace(/^[,.;:]+/, "").replace(/[,.;:]+$/, "");
55658
- cleaned = cleaned.replace(/[?.!]+$/, "");
55659
- cleaned = cleaned.replace(/\s+/g, " ").trim();
55660
- cleaned = cleaned.replace(/^(please|pls)\s+/i, "");
55661
- cleaned = cleaned.replace(/^(in|at|for|as|to)\s+/i, "");
55662
- cleaned = cleaned.replace(/^[a-z]\.\s*/i, "");
55663
- return cleaned.trim();
55664
- };
55665
- var extractLocation = (text) => {
55666
- const trimmed = text.trim();
55667
- if (!trimmed) return void 0;
55668
- const prepositionMatch = trimmed.match(/\b(?:in|at|for)\s+([^.;\n]+)$/i);
55669
- if (prepositionMatch?.[1]) {
55670
- const candidate = cleanLocation(prepositionMatch[1]);
55671
- return candidate || void 0;
55672
- }
55673
- const weatherMatch = trimmed.match(
55674
- /\b(?:weather|forecast|temperature)\b(?:\s+(?:in|at|for))?\s+(.+)/i
55675
- );
55676
- if (weatherMatch?.[1]) {
55677
- let candidate = weatherMatch[1];
55678
- candidate = candidate.replace(
55679
- /\b(?:for|next)\s+\d{1,2}\s*(?:days|day|hours|hour)\b[\s\S]*$/i,
55680
- ""
55681
- );
55682
- candidate = candidate.replace(/\b\d{1,2}\s*(?:days|day|hours|hour)\b[\s\S]*$/i, "");
55683
- candidate = candidate.replace(/\b(?:today|tomorrow|this week|this weekend)\b[\s\S]*$/i, "");
55684
- const cleaned = cleanLocation(candidate);
55685
- return cleaned || void 0;
55686
- }
55687
- return void 0;
55688
- };
55689
- var extractDays = (text) => {
55690
- const match = normalizeText5(text).match(/\b(\d{1,2})\s*(?:days|day)\b/i);
55691
- const raw = match?.[1];
55692
- if (!raw) return void 0;
55693
- const value = Number.parseInt(raw, 10);
55694
- return Number.isFinite(value) ? value : void 0;
55695
- };
55696
- var extractHours = (text) => {
55697
- const match = normalizeText5(text).match(/\b(\d{1,2})\s*(?:hours|hour)\b/i);
55698
- const raw = match?.[1];
55699
- if (!raw) return void 0;
55700
- const value = Number.parseInt(raw, 10);
55701
- return Number.isFinite(value) ? value : void 0;
55702
- };
55703
-
55704
- // packages/nlu/src/rules/intents.ts
55705
- var isWeatherIntent2 = (text) => /\b(weather|forecast|temperature|rain|snow|sunrise|sunset|uv|wind)\b/i.test(text) || fuzzyHasKeyword(text, [
55706
- "weather",
55707
- "forecast",
55708
- "temperature",
55709
- "rain",
55710
- "snow",
55711
- "sunrise",
55712
- "sunset",
55713
- "uv",
55714
- "wind"
55715
- ]);
55716
- var isWeatherBriefingIntent = (text) => /\b(weather\s+briefing|weather\s+summary|daily\s+summary|briefing|summary)\b/i.test(text) || fuzzyHasKeyword(text, ["briefing", "summary"]);
55717
- var isSunMoonIntent = (text) => /\b(panchangam|moonrise|moonset|moon\s*phase|tithi|nakshatra)\b/i.test(text) || fuzzyHasKeyword(text, ["panchangam", "moonrise", "moonset", "moonphase", "tithi", "nakshatra"]);
55718
- var isLocationSetIntent = (text) => /\b(i am in|i'm in|my location is|set my location|save my location)\b/i.test(text);
55719
- var isHomeSetIntent = (text) => /\bhome\s+(?:is|as|to)\b/i.test(text);
55720
- var isReminderAddIntent = (text) => /\b(remind me|set (?:a )?reminder|add (?:a )?reminder)\b/i.test(text);
55721
- var isReminderListIntent = (text) => /\b(my reminders|list reminders|show reminders|what are my reminders)\b/i.test(text);
55722
- var isReminderCompleteIntent = (text) => /\b(?:complete|done|finish|mark(?:\s+as)?\s+done)\b[\s\S]{0,24}\b(?:reminder|task)\b/i.test(text);
55723
- var isReminderDeleteIntent = (text) => /\b(?:delete|remove|cancel)\b[\s\S]{0,24}\b(?:reminder|task)\b/i.test(text);
55724
- var isBmiIntent = (text) => /\bbmi\b/i.test(text);
55725
- var isPlayIntent = (text) => /\b(play|start|queue)\b/i.test(text) && /\b(song|music|playlist)\b/i.test(text);
55726
- var isPreferenceIntent = (text) => /\bi like\b|\bprefer\b/i.test(text);
55727
- var isGreetingIntent = (text) => {
55728
- const trimmed = text.trim();
55729
- if (!trimmed) return false;
55730
- return /^(hi|hello|hey|yo|namaste|hola|good\s+(morning|afternoon|evening))\b/i.test(trimmed);
55731
- };
55732
- var isTranscribeIntent = (text) => /\btranscrib(e|ing)|voice note|audio transcription|speech to text\b/i.test(text) || fuzzyHasKeyword(text, ["transcribe", "transcribing", "transcription"]);
55733
- var isNotesSearchIntent = (text) => /\b(search|find|lookup|look up)\b[\s\S]*\bnotes?\b/i.test(text) || fuzzyHasKeyword(text, ["notes", "note", "search", "find", "lookup"]);
55734
- var isNotesCreateIntent = (text) => /\b(note|notes)\b[\s\S]*\b(create|new|add|save)\b/i.test(text) || /\bcreate\b[\s\S]*\bnote\b/i.test(text);
55735
- var isLanDevicesIntent2 = (text) => {
55736
- const hasDevices = /\bdevices?\b/i.test(text) || fuzzyHasKeyword(text, ["device", "devices"]);
55737
- if (!hasDevices) return false;
55738
- return /\b(router|wifi|wi-?fi|wlan|lan|network|connected)\b/i.test(text) || fuzzyHasKeyword(text, ["router", "wifi", "network", "connected", "lan", "wlan"]);
55739
- };
55740
- var isRailJourneyIntent = (text) => {
55741
- const hasRailKeyword = /\b(train|trains|rail|railway|journey|journeys|route|routes|schedule|schedules|departure|arrivals?)\b/i.test(
55742
- text
55743
- ) || fuzzyHasKeyword(text, [
55744
- "train",
55745
- "trains",
55746
- "rail",
55747
- "journey",
55748
- "journeys",
55749
- "schedule",
55750
- "departure",
55751
- "arrivals"
55752
- ]);
55753
- if (!hasRailKeyword) return false;
55754
- return /\bfrom\b[\s\S]{0,60}\bto\b/i.test(text) || /\bto\b[\s\S]{0,60}\b(?:tomorrow|today|tonight|next|depart|arrival|arrive)\b/i.test(text) || /\b(?:tomorrow|today|tonight|next|depart|arrival|arrive|how long|duration|takes?)\b/i.test(text) || /\b(von|nach)\b[\s\S]{0,60}\b(?:zug|bahn|fahrplan)\b/i.test(text);
55755
- };
55756
- var isSystemTimeIntent = (text) => /\b(?:what(?:'s| is)?\s+the\s+time|current\s+time|time\s+now|time\s+is\s+it|show\s+time|clock)\b/i.test(text);
55757
- var isPlacesSearchIntent = (text) => {
55758
- const hasPlaceCategory = /\b(hospitals?|clinics?|pharmac(?:y|ies)|restaurants?|cafes?|coffee|banks?|atm|hotels?|gas\s+stations?|petrol\s+pumps?|supermarkets?)\b/i.test(
55759
- text
55760
- ) || fuzzyHasKeyword(text, [
55761
- "hospital",
55762
- "hospitals",
55763
- "clinic",
55764
- "pharmacy",
55765
- "restaurant",
55766
- "cafe",
55767
- "coffee",
55768
- "bank",
55769
- "atm",
55770
- "hotel",
55771
- "gasstation",
55772
- "supermarket"
55773
- ]);
55774
- if (!hasPlaceCategory) return false;
55775
- const hasSearchCue = /\b(nearest|nearby|closest|near me|around me|find|search|show|list|get|locate|discover)\b/i.test(
55776
- text
55777
- ) || fuzzyHasKeyword(text, ["nearest", "nearby", "closest", "find", "search", "locate"]);
55778
- return hasSearchCue;
55779
- };
55780
- var isMemoryRecallIntent = (text) => /\b(?:what\s+do\s+you\s+remember|remember(?:\s+anything)?|recall|search\s+(?:my\s+)?memory|find\s+(?:in\s+)?(?:my\s+)?memory)\b/i.test(text);
55781
-
55782
55768
  // packages/nlu/src/rules/extractors.ts
55783
55769
  function extractNotesQuery(text) {
55784
55770
  const match = text.match(/\b(?:search|find|lookup|look up)\b\s*(?:my\s+)?notes?\s*(?:for|about)?\s*([^\n]+)$/i);
@@ -55966,6 +55952,136 @@ function extractRailJourneyPayload(text, fallbackFrom) {
55966
55952
  return { from, to, departureAt };
55967
55953
  }
55968
55954
 
55955
+ // packages/nlu/src/rules/intents.ts
55956
+ var isWeatherIntent2 = (text) => /\b(weather|forecast|temperature|rain|snow|sunrise|sunset|uv|wind)\b/i.test(text) || fuzzyHasKeyword(text, [
55957
+ "weather",
55958
+ "forecast",
55959
+ "temperature",
55960
+ "rain",
55961
+ "snow",
55962
+ "sunrise",
55963
+ "sunset",
55964
+ "uv",
55965
+ "wind"
55966
+ ]);
55967
+ var isWeatherBriefingIntent = (text) => /\b(weather\s+briefing|weather\s+summary|daily\s+summary|briefing|summary)\b/i.test(text) || fuzzyHasKeyword(text, ["briefing", "summary"]);
55968
+ var isSunMoonIntent = (text) => /\b(panchangam|moonrise|moonset|moon\s*phase|tithi|nakshatra)\b/i.test(text) || fuzzyHasKeyword(text, ["panchangam", "moonrise", "moonset", "moonphase", "tithi", "nakshatra"]);
55969
+ var isLocationSetIntent = (text) => /\b(i am in|i'm in|my location is|set my location|save my location)\b/i.test(text);
55970
+ var isHomeSetIntent = (text) => /\bhome\s+(?:is|as|to)\b/i.test(text);
55971
+ var isReminderAddIntent = (text) => /\b(remind me|set (?:a )?reminder|add (?:a )?reminder)\b/i.test(text);
55972
+ var isReminderListIntent = (text) => /\b(my reminders|list reminders|show reminders|what are my reminders)\b/i.test(text);
55973
+ var isReminderCompleteIntent = (text) => /\b(?:complete|done|finish|mark(?:\s+as)?\s+done)\b[\s\S]{0,24}\b(?:reminder|task)\b/i.test(text);
55974
+ var isReminderDeleteIntent = (text) => /\b(?:delete|remove|cancel)\b[\s\S]{0,24}\b(?:reminder|task)\b/i.test(text);
55975
+ var isBmiIntent = (text) => /\bbmi\b/i.test(text);
55976
+ var isPlayIntent = (text) => /\b(play|start|queue)\b/i.test(text) && /\b(song|music|playlist)\b/i.test(text);
55977
+ var isPreferenceIntent = (text) => /\bi like\b|\bprefer\b/i.test(text);
55978
+ var isGreetingIntent = (text) => {
55979
+ const trimmed = text.trim();
55980
+ if (!trimmed) return false;
55981
+ return /^(hi|hello|hey|yo|namaste|hola|good\s+(morning|afternoon|evening))\b/i.test(trimmed);
55982
+ };
55983
+ var isTranscribeIntent = (text) => /\btranscrib(e|ing)|voice note|audio transcription|speech to text\b/i.test(text) || fuzzyHasKeyword(text, ["transcribe", "transcribing", "transcription"]);
55984
+ var isNotesSearchIntent = (text) => /\b(search|find|lookup|look up)\b[\s\S]*\bnotes?\b/i.test(text) || fuzzyHasKeyword(text, ["notes", "note", "search", "find", "lookup"]);
55985
+ var isNotesCreateIntent = (text) => /\b(note|notes)\b[\s\S]*\b(create|new|add|save)\b/i.test(text) || /\bcreate\b[\s\S]*\bnote\b/i.test(text);
55986
+ var isLanDevicesIntent2 = (text) => {
55987
+ const hasDevices = /\bdevices?\b/i.test(text) || fuzzyHasKeyword(text, ["device", "devices"]);
55988
+ if (!hasDevices) return false;
55989
+ return /\b(router|wifi|wi-?fi|wlan|lan|network|connected)\b/i.test(text) || fuzzyHasKeyword(text, ["router", "wifi", "network", "connected", "lan", "wlan"]);
55990
+ };
55991
+ var isRailJourneyIntent = (text) => {
55992
+ const hasRailKeyword = /\b(train|trains|rail|railway|journey|journeys|route|routes|schedule|schedules|departure|arrivals?)\b/i.test(
55993
+ text
55994
+ ) || fuzzyHasKeyword(text, [
55995
+ "train",
55996
+ "trains",
55997
+ "rail",
55998
+ "journey",
55999
+ "journeys",
56000
+ "schedule",
56001
+ "departure",
56002
+ "arrivals"
56003
+ ]);
56004
+ if (!hasRailKeyword) return false;
56005
+ return /\bfrom\b[\s\S]{0,60}\bto\b/i.test(text) || /\bto\b[\s\S]{0,60}\b(?:tomorrow|today|tonight|next|depart|arrival|arrive)\b/i.test(text) || /\b(?:tomorrow|today|tonight|next|depart|arrival|arrive|how long|duration|takes?)\b/i.test(text) || /\b(von|nach)\b[\s\S]{0,60}\b(?:zug|bahn|fahrplan)\b/i.test(text);
56006
+ };
56007
+ var isSystemTimeIntent = (text) => /\b(?:what(?:'s| is)?\s+the\s+time|current\s+time|time\s+now|time\s+is\s+it|show\s+time|clock)\b/i.test(text);
56008
+ var isPlacesSearchIntent = (text) => {
56009
+ const hasPlaceCategory = /\b(hospitals?|clinics?|pharmac(?:y|ies)|restaurants?|cafes?|coffee|banks?|atm|hotels?|gas\s+stations?|petrol\s+pumps?|supermarkets?)\b/i.test(
56010
+ text
56011
+ ) || fuzzyHasKeyword(text, [
56012
+ "hospital",
56013
+ "hospitals",
56014
+ "clinic",
56015
+ "pharmacy",
56016
+ "restaurant",
56017
+ "cafe",
56018
+ "coffee",
56019
+ "bank",
56020
+ "atm",
56021
+ "hotel",
56022
+ "gasstation",
56023
+ "supermarket"
56024
+ ]);
56025
+ if (!hasPlaceCategory) return false;
56026
+ const hasSearchCue = /\b(nearest|nearby|closest|near me|around me|find|search|show|list|get|locate|discover)\b/i.test(
56027
+ text
56028
+ ) || fuzzyHasKeyword(text, ["nearest", "nearby", "closest", "find", "search", "locate"]);
56029
+ return hasSearchCue;
56030
+ };
56031
+ var isMemoryRecallIntent = (text) => /\b(?:what\s+do\s+you\s+remember|remember(?:\s+anything)?|recall|search\s+(?:my\s+)?memory|find\s+(?:in\s+)?(?:my\s+)?memory)\b/i.test(text);
56032
+
56033
+ // packages/nlu/src/rules/location.ts
56034
+ var cleanLocation = (value) => {
56035
+ let cleaned = value.trim();
56036
+ if (!cleaned) return cleaned;
56037
+ cleaned = cleaned.replace(/^[\s"']+/, "").replace(/[\s"']+$/, "");
56038
+ cleaned = cleaned.replace(/^[,.;:]+/, "").replace(/[,.;:]+$/, "");
56039
+ cleaned = cleaned.replace(/[?.!]+$/, "");
56040
+ cleaned = cleaned.replace(/\s+/g, " ").trim();
56041
+ cleaned = cleaned.replace(/^(please|pls)\s+/i, "");
56042
+ cleaned = cleaned.replace(/^(in|at|for|as|to)\s+/i, "");
56043
+ cleaned = cleaned.replace(/^[a-z]\.\s*/i, "");
56044
+ return cleaned.trim();
56045
+ };
56046
+ var extractLocation = (text) => {
56047
+ const trimmed = text.trim();
56048
+ if (!trimmed) return void 0;
56049
+ const prepositionMatch = trimmed.match(/\b(?:in|at|for)\s+([^.;\n]+)$/i);
56050
+ if (prepositionMatch?.[1]) {
56051
+ const candidate = cleanLocation(prepositionMatch[1]);
56052
+ return candidate || void 0;
56053
+ }
56054
+ const weatherMatch = trimmed.match(
56055
+ /\b(?:weather|forecast|temperature)\b(?:\s+(?:in|at|for))?\s+(.+)/i
56056
+ );
56057
+ if (weatherMatch?.[1]) {
56058
+ let candidate = weatherMatch[1];
56059
+ candidate = candidate.replace(
56060
+ /\b(?:for|next)\s+\d{1,2}\s*(?:days|day|hours|hour)\b[\s\S]*$/i,
56061
+ ""
56062
+ );
56063
+ candidate = candidate.replace(/\b\d{1,2}\s*(?:days|day|hours|hour)\b[\s\S]*$/i, "");
56064
+ candidate = candidate.replace(/\b(?:today|tomorrow|this week|this weekend)\b[\s\S]*$/i, "");
56065
+ const cleaned = cleanLocation(candidate);
56066
+ return cleaned || void 0;
56067
+ }
56068
+ return void 0;
56069
+ };
56070
+ var extractDays = (text) => {
56071
+ const match = normalizeText5(text).match(/\b(\d{1,2})\s*(?:days|day)\b/i);
56072
+ const raw = match?.[1];
56073
+ if (!raw) return void 0;
56074
+ const value = Number.parseInt(raw, 10);
56075
+ return Number.isFinite(value) ? value : void 0;
56076
+ };
56077
+ var extractHours = (text) => {
56078
+ const match = normalizeText5(text).match(/\b(\d{1,2})\s*(?:hours|hour)\b/i);
56079
+ const raw = match?.[1];
56080
+ if (!raw) return void 0;
56081
+ const value = Number.parseInt(raw, 10);
56082
+ return Number.isFinite(value) ? value : void 0;
56083
+ };
56084
+
55969
56085
  // packages/nlu/src/rules/reflection.ts
55970
56086
  var buildReflection = (intent) => {
55971
56087
  if (intent.startsWith("weather")) {
@@ -56003,11 +56119,9 @@ var buildReflection = (intent) => {
56003
56119
  };
56004
56120
  };
56005
56121
 
56006
- // packages/nlu/src/rules.ts
56007
- function interpretRules(request) {
56008
- const rawText = request.text ?? "";
56009
- const normalized = normalizeText5(rawText);
56010
- if (!normalized) return null;
56122
+ // packages/nlu/src/rules/intent-matchers-primary.ts
56123
+ function matchPrimaryIntent(input) {
56124
+ const { request, rawText, normalized } = input;
56011
56125
  if (isGreetingIntent(rawText)) {
56012
56126
  return {
56013
56127
  intent: "smalltalk.greeting",
@@ -56231,11 +56345,7 @@ function interpretRules(request) {
56231
56345
  toolHints: query ? [
56232
56346
  {
56233
56347
  name: "location.places.search",
56234
- input: {
56235
- query,
56236
- ...near ? { near } : {},
56237
- limit: 8
56238
- }
56348
+ input: { query, ...near ? { near } : {}, limit: 8 }
56239
56349
  }
56240
56350
  ] : [],
56241
56351
  clarificationNeeded: !query,
@@ -56249,6 +56359,12 @@ function interpretRules(request) {
56249
56359
  source: "rules"
56250
56360
  };
56251
56361
  }
56362
+ return null;
56363
+ }
56364
+
56365
+ // packages/nlu/src/rules/intent-matchers-secondary.ts
56366
+ function matchSecondaryIntent(input) {
56367
+ const { request, rawText } = input;
56252
56368
  if (isWeatherIntent2(rawText)) {
56253
56369
  const days = extractDays(rawText);
56254
56370
  const hours = extractHours(rawText);
@@ -56263,9 +56379,7 @@ function interpretRules(request) {
56263
56379
  const toolInput = {
56264
56380
  location: location ?? request.context?.currentLocation ?? request.context?.lastLocation
56265
56381
  };
56266
- if (days) {
56267
- toolInput.days = days;
56268
- }
56382
+ if (days) toolInput.days = days;
56269
56383
  if (hours) {
56270
56384
  toolInput.hourly = true;
56271
56385
  toolInput.hours = hours;
@@ -56275,12 +56389,7 @@ function interpretRules(request) {
56275
56389
  confidence: 0.82,
56276
56390
  entities,
56277
56391
  memoryHints: ["currentLocation", "homeLocation"],
56278
- toolHints: [
56279
- {
56280
- name: toolName,
56281
- input: toolInput
56282
- }
56283
- ],
56392
+ toolHints: [{ name: toolName, input: toolInput }],
56284
56393
  notes: ["location_fallback_from_profile"],
56285
56394
  reflection: buildReflection(intent),
56286
56395
  source: "rules"
@@ -56384,9 +56493,7 @@ function interpretRules(request) {
56384
56493
  if (isNotesSearchIntent(rawText)) {
56385
56494
  const query = extractNotesQuery(rawText);
56386
56495
  const entities = [];
56387
- if (query) {
56388
- entities.push({ type: "query", value: query, confidence: 0.78 });
56389
- }
56496
+ if (query) entities.push({ type: "query", value: query, confidence: 0.78 });
56390
56497
  return {
56391
56498
  intent: "notes.search",
56392
56499
  confidence: query ? 0.78 : 0.6,
@@ -56411,12 +56518,7 @@ function interpretRules(request) {
56411
56518
  intent: "notes.create",
56412
56519
  confidence: parsed.title ? 0.76 : 0.58,
56413
56520
  entities,
56414
- toolHints: parsed.title ? [
56415
- {
56416
- name: "notes.apple.create",
56417
- input: { title: parsed.title, ...parsed.body ? { body: parsed.body } : {} }
56418
- }
56419
- ] : [],
56521
+ toolHints: parsed.title ? [{ name: "notes.apple.create", input: { title: parsed.title, ...parsed.body ? { body: parsed.body } : {} } }] : [],
56420
56522
  clarificationNeeded: !parsed.title,
56421
56523
  reflection: {
56422
56524
  summary: "User wants to create a note.",
@@ -56427,6 +56529,19 @@ function interpretRules(request) {
56427
56529
  source: "rules"
56428
56530
  };
56429
56531
  }
56532
+ return null;
56533
+ }
56534
+
56535
+ // packages/nlu/src/rules.ts
56536
+ var MATCHERS = [matchPrimaryIntent, matchSecondaryIntent];
56537
+ function interpretRules(request) {
56538
+ const rawText = request.text ?? "";
56539
+ const normalized = normalizeText5(rawText);
56540
+ if (!normalized) return null;
56541
+ for (const match of MATCHERS) {
56542
+ const resolved = match({ request, rawText, normalized });
56543
+ if (resolved) return resolved;
56544
+ }
56430
56545
  return {
56431
56546
  intent: "unknown",
56432
56547
  confidence: 0.2,
@@ -57339,8 +57454,12 @@ var INTENT_ENTITY_LABELS = {
57339
57454
  "notes.create": ["topic"]
57340
57455
  };
57341
57456
  var DEFAULT_GLINER_ENDPOINT = "http://localhost:8501";
57457
+ var DEFAULT_GLINER_PATH = "/gliner-2";
57342
57458
  var DEFAULT_GLINER_TIMEOUT_MS = 800;
57343
57459
  var DEFAULT_GLINER_COOLDOWN_MS = 6e4;
57460
+ var DEFAULT_GLINER_TASK = "entity_extraction";
57461
+ var DEFAULT_GLINER_MODEL = "gliner-large-v2.1";
57462
+ var DEFAULT_GLINER_THRESHOLD = 0.4;
57344
57463
  var glinerCircuitOpenUntil = 0;
57345
57464
  function fillSlotsWithRegex(text, intent) {
57346
57465
  const entities = [];
@@ -57414,22 +57533,94 @@ function fillSlotsWithRegex(text, intent) {
57414
57533
  }
57415
57534
  return { entities: [], confidence: 0.8, needsLlmFallback: false };
57416
57535
  }
57417
- async function fillSlotsWithGliner(text, intent, endpoint, timeoutMs, cooldownMs) {
57536
+ function normalizeGlinerUrl(endpoint, glinerPath) {
57537
+ const base = endpoint.replace(/\/$/, "");
57538
+ const path50 = glinerPath.startsWith("/") ? glinerPath : `/${glinerPath}`;
57539
+ return `${base}${path50}`;
57540
+ }
57541
+ function normalizeGlinerEntity(entry, labelHint) {
57542
+ if (typeof entry === "string") {
57543
+ const text2 = entry.trim();
57544
+ if (!text2) return null;
57545
+ return {
57546
+ text: text2,
57547
+ label: labelHint ?? "entity",
57548
+ score: 0.7,
57549
+ start: 0,
57550
+ end: text2.length
57551
+ };
57552
+ }
57553
+ if (!entry || typeof entry !== "object") return null;
57554
+ const obj = entry;
57555
+ const rawText = obj.text ?? obj.value ?? obj.name;
57556
+ if (typeof rawText !== "string" || !rawText.trim()) return null;
57557
+ const text = rawText.trim();
57558
+ const labelRaw = obj.label ?? obj.type ?? labelHint ?? "entity";
57559
+ const label = typeof labelRaw === "string" && labelRaw.trim() ? labelRaw.trim() : "entity";
57560
+ const score = typeof obj.score === "number" && Number.isFinite(obj.score) ? obj.score : 0.7;
57561
+ const start = typeof obj.start === "number" && Number.isFinite(obj.start) ? obj.start : 0;
57562
+ const end = typeof obj.end === "number" && Number.isFinite(obj.end) ? obj.end : start + text.length;
57563
+ return { text, label, score, start, end };
57564
+ }
57565
+ function coerceGlinerEntities(payload) {
57566
+ if (Array.isArray(payload)) {
57567
+ return payload.map((entry) => normalizeGlinerEntity(entry)).filter((entry) => entry != null);
57568
+ }
57569
+ if (!payload || typeof payload !== "object") return [];
57570
+ const obj = payload;
57571
+ const directEntities = obj.entities;
57572
+ if (Array.isArray(directEntities)) {
57573
+ return directEntities.map((entry) => normalizeGlinerEntity(entry)).filter((entry) => entry != null);
57574
+ }
57575
+ if (directEntities && typeof directEntities === "object") {
57576
+ const rows = [];
57577
+ for (const [label, values] of Object.entries(directEntities)) {
57578
+ if (!Array.isArray(values)) continue;
57579
+ for (const value of values) {
57580
+ const normalized = normalizeGlinerEntity(value, label);
57581
+ if (normalized) rows.push(normalized);
57582
+ }
57583
+ }
57584
+ return rows;
57585
+ }
57586
+ const dataPayload = obj.data;
57587
+ if (dataPayload) return coerceGlinerEntities(dataPayload);
57588
+ return [];
57589
+ }
57590
+ async function fillSlotsWithGliner(params) {
57591
+ const {
57592
+ text,
57593
+ intent,
57594
+ endpoint,
57595
+ glinerPath,
57596
+ timeoutMs,
57597
+ cooldownMs,
57598
+ task,
57599
+ model,
57600
+ threshold,
57601
+ headers
57602
+ } = params;
57418
57603
  if (glinerCircuitOpenUntil > Date.now()) {
57419
57604
  return null;
57420
57605
  }
57421
57606
  const labels = INTENT_ENTITY_LABELS[intent];
57422
57607
  if (!labels?.length) return null;
57423
57608
  try {
57424
- const url = `${endpoint.replace(/\/$/, "")}/predict`;
57609
+ const url = normalizeGlinerUrl(endpoint, glinerPath);
57425
57610
  const response = await fetch(url, {
57426
57611
  method: "POST",
57427
- headers: { "content-type": "application/json" },
57612
+ headers: {
57613
+ "content-type": "application/json",
57614
+ ...headers ?? {}
57615
+ },
57428
57616
  body: JSON.stringify({
57429
57617
  text,
57430
57618
  labels,
57431
- model: "gliner-large-v2.1",
57432
- threshold: 0.4
57619
+ task,
57620
+ model,
57621
+ threshold,
57622
+ // Keep schema+labels together so GLiNER2 adapters can use either shape.
57623
+ schema: labels.map((label) => ({ label, description: `Extract ${label}` }))
57433
57624
  }),
57434
57625
  signal: AbortSignal.timeout(timeoutMs)
57435
57626
  });
@@ -57438,13 +57629,14 @@ async function fillSlotsWithGliner(text, intent, endpoint, timeoutMs, cooldownMs
57438
57629
  return null;
57439
57630
  }
57440
57631
  const data2 = await response.json().catch(() => null);
57441
- const rawEntities = Array.isArray(data2) ? data2 : Array.isArray(data2?.entities) ? data2.entities : [];
57632
+ const rawEntities = coerceGlinerEntities(data2);
57442
57633
  if (rawEntities.length === 0) return null;
57443
- const entities = rawEntities.filter((e) => e.score >= 0.4).map((e) => ({
57634
+ const entities = rawEntities.filter((e) => e.score >= threshold).map((e) => ({
57444
57635
  type: GLINER_LABEL_TO_ENTITY_TYPE[e.label.toLowerCase()] ?? e.label.toLowerCase(),
57445
57636
  value: e.text,
57446
57637
  confidence: e.score
57447
57638
  }));
57639
+ if (entities.length === 0) return null;
57448
57640
  glinerCircuitOpenUntil = 0;
57449
57641
  return {
57450
57642
  entities,
@@ -57470,6 +57662,7 @@ async function fillSlots(params) {
57470
57662
  }
57471
57663
  const useGliner = config?.useGliner ?? true;
57472
57664
  const glinerEndpoint = config?.glinerEndpoint ?? DEFAULT_GLINER_ENDPOINT;
57665
+ const glinerPath = config?.glinerPath ?? DEFAULT_GLINER_PATH;
57473
57666
  const glinerTimeoutMs = Math.max(
57474
57667
  100,
57475
57668
  Math.min(1e4, config?.glinerTimeoutMs ?? DEFAULT_GLINER_TIMEOUT_MS)
@@ -57478,13 +57671,26 @@ async function fillSlots(params) {
57478
57671
  0,
57479
57672
  Math.min(3e5, config?.glinerCooldownMs ?? DEFAULT_GLINER_COOLDOWN_MS)
57480
57673
  );
57674
+ const glinerThreshold = Math.max(
57675
+ 0,
57676
+ Math.min(1, config?.glinerThreshold ?? DEFAULT_GLINER_THRESHOLD)
57677
+ );
57678
+ const glinerTask = config?.glinerTask?.trim() || DEFAULT_GLINER_TASK;
57679
+ const glinerModel = config?.glinerModel?.trim() || DEFAULT_GLINER_MODEL;
57481
57680
  if (useGliner) {
57482
57681
  const glinerResult = await fillSlotsWithGliner(
57483
- text,
57484
- intent,
57485
- glinerEndpoint,
57486
- glinerTimeoutMs,
57487
- glinerCooldownMs
57682
+ {
57683
+ text,
57684
+ intent,
57685
+ endpoint: glinerEndpoint,
57686
+ glinerPath,
57687
+ timeoutMs: glinerTimeoutMs,
57688
+ cooldownMs: glinerCooldownMs,
57689
+ task: glinerTask,
57690
+ model: glinerModel,
57691
+ threshold: glinerThreshold,
57692
+ headers: config?.glinerHeaders
57693
+ }
57488
57694
  );
57489
57695
  if (glinerResult) {
57490
57696
  return glinerResult;
@@ -57808,7 +58014,12 @@ async function enrichWithSlotFill(result, text, lang, config) {
57808
58014
  lang,
57809
58015
  config: {
57810
58016
  glinerEndpoint: config.nlu?.glinerEndpoint,
58017
+ glinerPath: config.nlu?.glinerPath,
57811
58018
  useGliner: config.nlu?.glinerEnabled,
58019
+ glinerTask: config.nlu?.glinerTask,
58020
+ glinerModel: config.nlu?.glinerModel,
58021
+ glinerThreshold: config.nlu?.glinerThreshold,
58022
+ glinerHeaders: config.nlu?.glinerHeaders,
57812
58023
  glinerTimeoutMs: config.nlu?.glinerTimeoutMs,
57813
58024
  glinerCooldownMs: config.nlu?.glinerCooldownMs
57814
58025
  }
@@ -59389,7 +59600,7 @@ import { spawn as spawn6 } from "node:child_process";
59389
59600
  var _chitraguptaMemory = null;
59390
59601
  async function getChitraguptaMemory() {
59391
59602
  if (!_chitraguptaMemory) {
59392
- _chitraguptaMemory = await import("./chunks/src-ZAKUL232.js");
59603
+ _chitraguptaMemory = await import("./chunks/src-Y3TGMINC.js");
59393
59604
  }
59394
59605
  return _chitraguptaMemory;
59395
59606
  }
@@ -60850,7 +61061,13 @@ function setupGatewayStores(params) {
60850
61061
  assistantName: getProfile?.()?.assistantName ?? "Vaayu"
60851
61062
  },
60852
61063
  conversationId: chatId,
60853
- content
61064
+ content,
61065
+ formatOptions: {
61066
+ tone: options?.tone,
61067
+ sessionId: options?.sessionId,
61068
+ userId: options?.userId,
61069
+ collectMode: options?.collectMode
61070
+ }
60854
61071
  });
60855
61072
  return;
60856
61073
  }
@@ -60862,7 +61079,13 @@ function setupGatewayStores(params) {
60862
61079
  assistantName: getProfile?.()?.assistantName ?? "Vaayu"
60863
61080
  },
60864
61081
  to: chatId,
60865
- content
61082
+ content,
61083
+ formatOptions: {
61084
+ tone: options?.tone,
61085
+ sessionId: options?.sessionId,
61086
+ userId: options?.userId,
61087
+ collectMode: options?.collectMode
61088
+ }
60866
61089
  });
60867
61090
  return;
60868
61091
  }
@@ -60874,7 +61097,13 @@ function setupGatewayStores(params) {
60874
61097
  assistantName: getProfile?.()?.assistantName ?? "Vaayu"
60875
61098
  },
60876
61099
  chatGuid: chatId,
60877
- content
61100
+ content,
61101
+ formatOptions: {
61102
+ tone: options?.tone,
61103
+ sessionId: options?.sessionId,
61104
+ userId: options?.userId,
61105
+ collectMode: options?.collectMode
61106
+ }
60878
61107
  });
60879
61108
  return;
60880
61109
  }
@@ -61729,6 +61958,13 @@ async function rehydrateSessionInbox(params) {
61729
61958
  }
61730
61959
 
61731
61960
  // apps/gateway/dist/gateway/session-inbox-worker.js
61961
+ var asOptionalString = (value) => {
61962
+ if (typeof value !== "string")
61963
+ return void 0;
61964
+ const trimmed = value.trim();
61965
+ return trimmed ? trimmed : void 0;
61966
+ };
61967
+ var isCollectPlainTextChannel = (channel) => channel === "twitter" || channel === "whatsapp" || channel === "imessage";
61732
61968
  function buildDefaultsForChannel(runtime, record) {
61733
61969
  if (record.channel === "telegram") {
61734
61970
  const telegramConfig = runtime.config.channels.telegram;
@@ -61759,7 +61995,7 @@ ${deterministicLine}${retrievalLine}${budgetLine}` : "";
61759
61995
  return replyPrefix ? `${replyPrefix}${content}` : content;
61760
61996
  }
61761
61997
  async function sendInboxReply(params) {
61762
- const { runtime, record, content, routing, getTelegramAdapter } = params;
61998
+ const { runtime, record, content, routing, collectMode, getTelegramAdapter } = params;
61763
61999
  if (!record.channel || !record.chatId)
61764
62000
  return;
61765
62001
  const reply = buildReplyText(runtime, content, routing);
@@ -61793,6 +62029,15 @@ async function sendInboxReply(params) {
61793
62029
  });
61794
62030
  return;
61795
62031
  }
62032
+ if (isCollectPlainTextChannel(record.channel) && collectMode?.enabled) {
62033
+ await runtime.sendChannelMessage(record.channel, record.chatId, reply, {
62034
+ tone: "default",
62035
+ sessionId: record.sessionId ?? void 0,
62036
+ userId: record.userId ?? void 0,
62037
+ collectMode
62038
+ });
62039
+ return;
62040
+ }
61796
62041
  await runtime.sendChannelMessage(record.channel, record.chatId, reply);
61797
62042
  }
61798
62043
  function createSessionInboxWorker(params) {
@@ -61882,6 +62127,12 @@ function createSessionInboxWorker(params) {
61882
62127
  record,
61883
62128
  content: result.response.content,
61884
62129
  routing: result.routing,
62130
+ collectMode: queueMode === "collect" && isCollectPlainTextChannel(record.channel) ? {
62131
+ enabled: true,
62132
+ queueMode: "collect",
62133
+ providerId: asOptionalString(result.routing?.selected?.providerId) ?? asOptionalString(metadata.providerId),
62134
+ model: asOptionalString(result.routing?.selected?.model) ?? (asOptionalString(result.response?.model)?.startsWith("system.") ? void 0 : asOptionalString(result.response?.model)) ?? asOptionalString(metadata.model)
62135
+ } : void 0,
61885
62136
  getTelegramAdapter
61886
62137
  });
61887
62138
  await updateSessionInbox(record.id, {
@@ -62500,7 +62751,7 @@ async function restoreStorage(params) {
62500
62751
  // packages/backup/src/qdrant.js
62501
62752
  import fs46 from "node:fs";
62502
62753
  import path47 from "node:path";
62503
- var DEFAULT_COLLECTION2 = "smriti-memory";
62754
+ var DEFAULT_COLLECTION2 = "vaayu-smriti";
62504
62755
  var DEFAULT_TIMEOUT_MS3 = 8e3;
62505
62756
  function buildHeaders(apiKey) {
62506
62757
  const headers = { "content-type": "application/json" };
@@ -62607,7 +62858,6 @@ function createBackupManager(params) {
62607
62858
  const id = createSnapshotId();
62608
62859
  const startedAt = nowIso4();
62609
62860
  const snapshotDir = path49.join(localDir, id);
62610
- ensureDir2(snapshotDir);
62611
62861
  const manifest = {
62612
62862
  id,
62613
62863
  startedAt,
@@ -62615,6 +62865,7 @@ function createBackupManager(params) {
62615
62865
  errors: reason ? [`reason:${reason}`] : []
62616
62866
  };
62617
62867
  try {
62868
+ ensureDir2(snapshotDir);
62618
62869
  const storageResult = await backupStorage({
62619
62870
  storage,
62620
62871
  snapshotDir,
@@ -62648,8 +62899,15 @@ function createBackupManager(params) {
62648
62899
  manifest.errors?.push(error instanceof Error ? error.message : String(error));
62649
62900
  } finally {
62650
62901
  manifest.endedAt = nowIso4();
62651
- saveBackupManifest(snapshotDir, manifest);
62652
- updateIndex(localDir, manifest, config.keepLast, config.keepDays);
62902
+ try {
62903
+ saveBackupManifest(snapshotDir, manifest);
62904
+ updateIndex(localDir, manifest, config.keepLast, config.keepDays);
62905
+ } catch (persistError) {
62906
+ logger.warn("backup_manifest_persist_failed", {
62907
+ snapshotDir,
62908
+ error: persistError instanceof Error ? persistError.message : String(persistError)
62909
+ });
62910
+ }
62653
62911
  lastRun = manifest;
62654
62912
  running = false;
62655
62913
  }
@@ -62666,11 +62924,19 @@ function createBackupManager(params) {
62666
62924
  if (!config.enabled)
62667
62925
  return;
62668
62926
  if (shouldRun(lastStorageRunAt, config.intervalMinutes)) {
62669
- void run("scheduled");
62927
+ void run("scheduled").catch((error) => {
62928
+ logger.warn("backup_scheduled_run_failed", {
62929
+ error: error instanceof Error ? error.message : String(error)
62930
+ });
62931
+ });
62670
62932
  }
62671
62933
  }, Math.max(1e4, config.intervalMinutes * 6e4));
62672
62934
  if (config.runOnStart) {
62673
- void run("startup");
62935
+ void run("startup").catch((error) => {
62936
+ logger.warn("backup_startup_run_failed", {
62937
+ error: error instanceof Error ? error.message : String(error)
62938
+ });
62939
+ });
62674
62940
  }
62675
62941
  };
62676
62942
  const stop = () => {