agent-nuvira 3.1.1 → 3.2.0

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 (172) hide show
  1. package/dist/agents/agents/reasoner.d.ts +8 -0
  2. package/dist/agents/agents/reasoner.d.ts.map +1 -1
  3. package/dist/agents/agents/reasoner.js +53 -2
  4. package/dist/agents/agents/reasoner.js.map +1 -1
  5. package/dist/agents/agents/writer.d.ts +24 -0
  6. package/dist/agents/agents/writer.d.ts.map +1 -1
  7. package/dist/agents/agents/writer.js +194 -0
  8. package/dist/agents/agents/writer.js.map +1 -1
  9. package/dist/agents/composite-plan.d.ts +143 -0
  10. package/dist/agents/composite-plan.d.ts.map +1 -0
  11. package/dist/agents/composite-plan.js +399 -0
  12. package/dist/agents/composite-plan.js.map +1 -0
  13. package/dist/agents/long-form-plan.d.ts +156 -0
  14. package/dist/agents/long-form-plan.d.ts.map +1 -0
  15. package/dist/agents/long-form-plan.js +274 -0
  16. package/dist/agents/long-form-plan.js.map +1 -0
  17. package/dist/agents/orchestrator.d.ts +107 -0
  18. package/dist/agents/orchestrator.d.ts.map +1 -1
  19. package/dist/agents/orchestrator.js +501 -35
  20. package/dist/agents/orchestrator.js.map +1 -1
  21. package/dist/agents/prompt-assembly.d.ts +8 -0
  22. package/dist/agents/prompt-assembly.d.ts.map +1 -1
  23. package/dist/agents/prompt-assembly.js +17 -0
  24. package/dist/agents/prompt-assembly.js.map +1 -1
  25. package/dist/cli/chat.d.ts +27 -0
  26. package/dist/cli/chat.d.ts.map +1 -1
  27. package/dist/cli/chat.js +133 -8
  28. package/dist/cli/chat.js.map +1 -1
  29. package/dist/cli/execute.d.ts +12 -0
  30. package/dist/cli/execute.d.ts.map +1 -1
  31. package/dist/cli/execute.js +105 -2
  32. package/dist/cli/execute.js.map +1 -1
  33. package/dist/cli/models.d.ts.map +1 -1
  34. package/dist/cli/models.js +10 -0
  35. package/dist/cli/models.js.map +1 -1
  36. package/dist/cli/nlu.d.ts +8 -0
  37. package/dist/cli/nlu.d.ts.map +1 -1
  38. package/dist/cli/nlu.js +57 -0
  39. package/dist/cli/nlu.js.map +1 -1
  40. package/dist/cli/trace.d.ts.map +1 -1
  41. package/dist/cli/trace.js +27 -0
  42. package/dist/cli/trace.js.map +1 -1
  43. package/dist/gateway/gateway-log.d.ts +1 -1
  44. package/dist/gateway/gateway-log.d.ts.map +1 -1
  45. package/dist/gateway/gateway-log.js.map +1 -1
  46. package/dist/gateway/registry.d.ts +116 -1
  47. package/dist/gateway/registry.d.ts.map +1 -1
  48. package/dist/gateway/registry.js +575 -52
  49. package/dist/gateway/registry.js.map +1 -1
  50. package/dist/inference/model-entitlement.d.ts +46 -0
  51. package/dist/inference/model-entitlement.d.ts.map +1 -0
  52. package/dist/inference/model-entitlement.js +98 -0
  53. package/dist/inference/model-entitlement.js.map +1 -0
  54. package/dist/inference/tool-call-utils.d.ts.map +1 -1
  55. package/dist/inference/tool-call-utils.js +70 -1
  56. package/dist/inference/tool-call-utils.js.map +1 -1
  57. package/dist/learning/autonomy-policy.d.ts +334 -0
  58. package/dist/learning/autonomy-policy.d.ts.map +1 -0
  59. package/dist/learning/autonomy-policy.js +500 -0
  60. package/dist/learning/autonomy-policy.js.map +1 -0
  61. package/dist/learning/credential-fingerprint.d.ts +58 -0
  62. package/dist/learning/credential-fingerprint.d.ts.map +1 -0
  63. package/dist/learning/credential-fingerprint.js +126 -0
  64. package/dist/learning/credential-fingerprint.js.map +1 -0
  65. package/dist/learning/deferred-task.d.ts +159 -0
  66. package/dist/learning/deferred-task.d.ts.map +1 -0
  67. package/dist/learning/deferred-task.js +451 -0
  68. package/dist/learning/deferred-task.js.map +1 -0
  69. package/dist/learning/deliverable-class.d.ts +130 -0
  70. package/dist/learning/deliverable-class.d.ts.map +1 -0
  71. package/dist/learning/deliverable-class.js +432 -0
  72. package/dist/learning/deliverable-class.js.map +1 -0
  73. package/dist/learning/long-form.d.ts +252 -0
  74. package/dist/learning/long-form.d.ts.map +1 -0
  75. package/dist/learning/long-form.js +510 -0
  76. package/dist/learning/long-form.js.map +1 -0
  77. package/dist/learning/model-first-router.d.ts +17 -0
  78. package/dist/learning/model-first-router.d.ts.map +1 -1
  79. package/dist/learning/model-first-router.js +35 -0
  80. package/dist/learning/model-first-router.js.map +1 -1
  81. package/dist/learning/model-registry.d.ts +96 -4
  82. package/dist/learning/model-registry.d.ts.map +1 -1
  83. package/dist/learning/model-registry.js +128 -6
  84. package/dist/learning/model-registry.js.map +1 -1
  85. package/dist/learning/model-warmup.d.ts +97 -2
  86. package/dist/learning/model-warmup.d.ts.map +1 -1
  87. package/dist/learning/model-warmup.js +165 -60
  88. package/dist/learning/model-warmup.js.map +1 -1
  89. package/dist/learning/prompt-layers.d.ts +61 -0
  90. package/dist/learning/prompt-layers.d.ts.map +1 -0
  91. package/dist/learning/prompt-layers.js +140 -0
  92. package/dist/learning/prompt-layers.js.map +1 -0
  93. package/dist/learning/provider-limits.d.ts +66 -0
  94. package/dist/learning/provider-limits.d.ts.map +1 -0
  95. package/dist/learning/provider-limits.js +184 -0
  96. package/dist/learning/provider-limits.js.map +1 -0
  97. package/dist/learning/reasoning-trace.d.ts +36 -1
  98. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  99. package/dist/learning/reasoning-trace.js +36 -2
  100. package/dist/learning/reasoning-trace.js.map +1 -1
  101. package/dist/learning/resilient-call.d.ts +36 -1
  102. package/dist/learning/resilient-call.d.ts.map +1 -1
  103. package/dist/learning/resilient-call.js +118 -8
  104. package/dist/learning/resilient-call.js.map +1 -1
  105. package/dist/learning/unattended-job.d.ts +293 -0
  106. package/dist/learning/unattended-job.d.ts.map +1 -0
  107. package/dist/learning/unattended-job.js +544 -0
  108. package/dist/learning/unattended-job.js.map +1 -0
  109. package/dist/learning/unattended-progress.d.ts +95 -0
  110. package/dist/learning/unattended-progress.d.ts.map +1 -0
  111. package/dist/learning/unattended-progress.js +147 -0
  112. package/dist/learning/unattended-progress.js.map +1 -0
  113. package/dist/learning/working-state.d.ts +109 -0
  114. package/dist/learning/working-state.d.ts.map +1 -0
  115. package/dist/learning/working-state.js +244 -0
  116. package/dist/learning/working-state.js.map +1 -0
  117. package/dist/nlu/conversation-gate.d.ts +46 -0
  118. package/dist/nlu/conversation-gate.d.ts.map +1 -1
  119. package/dist/nlu/conversation-gate.js +73 -6
  120. package/dist/nlu/conversation-gate.js.map +1 -1
  121. package/dist/nlu/intent-confirm.d.ts +82 -0
  122. package/dist/nlu/intent-confirm.d.ts.map +1 -0
  123. package/dist/nlu/intent-confirm.js +146 -0
  124. package/dist/nlu/intent-confirm.js.map +1 -0
  125. package/dist/nlu/learnings.d.ts +101 -0
  126. package/dist/nlu/learnings.d.ts.map +1 -0
  127. package/dist/nlu/learnings.js +283 -0
  128. package/dist/nlu/learnings.js.map +1 -0
  129. package/dist/tools/coding-tools.d.ts.map +1 -1
  130. package/dist/tools/coding-tools.js +95 -19
  131. package/dist/tools/coding-tools.js.map +1 -1
  132. package/dist/tools/edit-verification.d.ts +125 -0
  133. package/dist/tools/edit-verification.d.ts.map +1 -0
  134. package/dist/tools/edit-verification.js +237 -0
  135. package/dist/tools/edit-verification.js.map +1 -0
  136. package/dist/tools/git-tool.d.ts.map +1 -1
  137. package/dist/tools/git-tool.js +37 -4
  138. package/dist/tools/git-tool.js.map +1 -1
  139. package/dist/tools/registry.d.ts +30 -2
  140. package/dist/tools/registry.d.ts.map +1 -1
  141. package/dist/tools/registry.js +40 -11
  142. package/dist/tools/registry.js.map +1 -1
  143. package/dist/tools/run-cli.d.ts.map +1 -1
  144. package/dist/tools/run-cli.js +40 -13
  145. package/dist/tools/run-cli.js.map +1 -1
  146. package/dist/tools/run-terminal.d.ts +6 -1
  147. package/dist/tools/run-terminal.d.ts.map +1 -1
  148. package/dist/tools/run-terminal.js +158 -18
  149. package/dist/tools/run-terminal.js.map +1 -1
  150. package/dist/tools/tool-loop.d.ts +35 -0
  151. package/dist/tools/tool-loop.d.ts.map +1 -1
  152. package/dist/tools/tool-loop.js +157 -3
  153. package/dist/tools/tool-loop.js.map +1 -1
  154. package/dist/web-dashboard/chat-console.d.ts +35 -0
  155. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  156. package/dist/web-dashboard/chat-console.js +97 -18
  157. package/dist/web-dashboard/chat-console.js.map +1 -1
  158. package/dist/web-dashboard/chat-retry.d.ts +143 -0
  159. package/dist/web-dashboard/chat-retry.d.ts.map +1 -0
  160. package/dist/web-dashboard/chat-retry.js +227 -0
  161. package/dist/web-dashboard/chat-retry.js.map +1 -0
  162. package/dist/web-dashboard/server.d.ts +17 -0
  163. package/dist/web-dashboard/server.d.ts.map +1 -1
  164. package/dist/web-dashboard/server.js +200 -9
  165. package/dist/web-dashboard/server.js.map +1 -1
  166. package/dist/web-dashboard/src/types.d.ts +81 -4
  167. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  168. package/package.json +1 -1
  169. package/src/web-dashboard/public/assets/{index-CQW0qv1r.js → index-kCUkORm7.js} +27 -27
  170. package/src/web-dashboard/public/assets/index-kCUkORm7.js.map +1 -0
  171. package/src/web-dashboard/public/index.html +1 -1
  172. package/src/web-dashboard/public/assets/index-CQW0qv1r.js.map +0 -1
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Credential Fingerprint — notice when the user's keys change, and re-probe.
3
+ *
4
+ * WHY THIS EXISTS. The routing pool can only contain models a probe has
5
+ * VERIFIED, and a probe only ever ran on a cold start or a maintenance command.
6
+ * So a purchase made mid-session — the exact case where a user expects the new
7
+ * models to appear — changed nothing: the credential was fine, the catalog was
8
+ * stale, and the next run would have picked the models up only if it happened to
9
+ * cold-start. There is no per-model entitlement API to ask ("may I buy
10
+ * `meta-llama/...`?" is not a question OpenRouter answers); the only honest
11
+ * signal is *"we sent one token with this key and it answered"*. But it is
12
+ * genuinely cheap to notice that the KEY SET changed and force that probe
13
+ * instead of waiting for an accident.
14
+ *
15
+ * WHAT IS STORED: a SHA-256 digest of the credential SHAPE — which providers are
16
+ * configured, a digest of each key, each base URL, each env-var presence. Never
17
+ * a key, not even truncated, and the digest is one-way, so the file is safe to
18
+ * read, copy or commit by accident. Its only job is equality.
19
+ */
20
+ import { createHash } from 'node:crypto';
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
22
+ import { dirname, join } from 'node:path';
23
+ import { envBuff, resolveNuviraHome } from '../config/paths.js';
24
+ import { CATALOG_PROVIDER_IDS, catalogEnvVar, getCatalogProvider } from '../inference/provider-catalog.js';
25
+ /** Sidecar file (under the memory dir) holding the last-seen credential shape. */
26
+ export const CREDENTIAL_FINGERPRINT_FILENAME = 'credential-fingerprint.json';
27
+ const DEFAULT_MEMORY_DIR = join(resolveNuviraHome(), 'memory');
28
+ function memoryDir() {
29
+ return envBuff('MEMORY_DIR') || DEFAULT_MEMORY_DIR;
30
+ }
31
+ /** Path of the fingerprint sidecar (exported so tests can redirect it). */
32
+ export function credentialFingerprintPath() {
33
+ return join(memoryDir(), CREDENTIAL_FINGERPRINT_FILENAME);
34
+ }
35
+ /** One-way digest of a secret — never the secret itself. */
36
+ function digest(value) {
37
+ return createHash('sha256').update(value).digest('hex').slice(0, 16);
38
+ }
39
+ /**
40
+ * The credential SHAPE, as a list of comparable lines.
41
+ *
42
+ * Exported (and separate from the hashing) so a test — or a support call — can
43
+ * see exactly which inputs are considered without needing to reverse a digest.
44
+ * The lines carry digests, never keys.
45
+ */
46
+ export function credentialShapeInputs(configManager) {
47
+ const lines = [];
48
+ for (const provider of [...CATALOG_PROVIDER_IDS].sort()) {
49
+ const parts = [provider];
50
+ // 1. Config-resolved key (vault refs resolved by getProviderConfig, so a
51
+ // key that moved from plaintext into the vault is NOT a change).
52
+ let configKey;
53
+ let baseUrl;
54
+ try {
55
+ const { config } = configManager.getProviderConfig(provider);
56
+ configKey = typeof config?.apiKey === 'string' ? config.apiKey : undefined;
57
+ baseUrl = typeof config?.baseUrl === 'string' ? config.baseUrl : undefined;
58
+ }
59
+ catch {
60
+ // A provider the manager cannot describe contributes only its env state.
61
+ }
62
+ if (configKey)
63
+ parts.push(`cfg:${digest(configKey)}`);
64
+ if (baseUrl)
65
+ parts.push(`url:${baseUrl}`);
66
+ // 2. The standard env var — presence AND digest, so replacing a key in the
67
+ // environment is a change while an unrelated env tweak is not.
68
+ const envVar = catalogEnvVar(provider);
69
+ if (envVar) {
70
+ const fromEnv = process.env[envVar];
71
+ if (fromEnv)
72
+ parts.push(`env:${digest(fromEnv)}`);
73
+ }
74
+ // 3. Reachability class: keyless runners appear/disappear from the probe
75
+ // set when their catalog entry changes, not when a key changes.
76
+ const entry = getCatalogProvider(provider);
77
+ if (entry?.keyless)
78
+ parts.push('keyless');
79
+ lines.push(parts.join('|'));
80
+ }
81
+ return lines;
82
+ }
83
+ /** SHA-256 digest of the credential shape. Safe to log. */
84
+ export function credentialFingerprint(configManager) {
85
+ return digest(credentialShapeInputs(configManager).join('\n'));
86
+ }
87
+ /**
88
+ * Compare the current credential shape against the last one recorded and RECORD
89
+ * the new one.
90
+ *
91
+ * Recording on every call is what makes this fire once per change rather than
92
+ * once per cycle: the caller sees `changed: true` a single time and can force a
93
+ * probe, and every later call in the same process is a no-op. `firstRun` is
94
+ * reported separately because "no previous record" is not evidence of a change —
95
+ * a fresh machine must not be treated as though a purchase just landed.
96
+ */
97
+ export function detectCredentialChange(configManager, options = {}) {
98
+ const path = options.path ?? credentialFingerprintPath();
99
+ const fingerprint = credentialFingerprint(configManager);
100
+ let previous;
101
+ try {
102
+ if (existsSync(path)) {
103
+ const raw = JSON.parse(readFileSync(path, 'utf-8'));
104
+ if (typeof raw?.fingerprint === 'string')
105
+ previous = raw.fingerprint;
106
+ }
107
+ }
108
+ catch {
109
+ // A corrupt sidecar is treated as absent — the worst case is one extra
110
+ // catalog probe, which is cheap and idempotent.
111
+ }
112
+ try {
113
+ mkdirSync(dirname(path), { recursive: true });
114
+ writeFileSync(path, JSON.stringify({ fingerprint, at: Date.now() }), 'utf-8');
115
+ }
116
+ catch {
117
+ // Best-effort: failing to record must never break a run.
118
+ }
119
+ return {
120
+ changed: previous !== undefined && previous !== fingerprint,
121
+ firstRun: previous === undefined,
122
+ fingerprint,
123
+ previous,
124
+ };
125
+ }
126
+ //# sourceMappingURL=credential-fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-fingerprint.js","sourceRoot":"","sources":["../../src/learning/credential-fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Deferred retry queue — the MECHANISM behind "Reply *yes* and I will keep
3
+ * trying until it is done."
4
+ *
5
+ * THE BUG THIS CLOSES. `renderModelBreadthReport` ends every failed turn with
6
+ * that offer, and it went out live to WhatsApp
7
+ * ("A model frees up in about 44s … Reply *yes* …"). Nothing parsed the "yes",
8
+ * stored the task, or re-ran it when a model came back — so a sender who
9
+ * followed the instruction got silence, which is worse than never being asked.
10
+ * A promise the agent cannot keep is a defect, not a courtesy.
11
+ *
12
+ * WHY A STORE INSTEAD OF A TIMER IN THE FAILURE PATH: the model that frees up
13
+ * is often minutes away (a quota window), and a messaging transport's turn is
14
+ * long over by then — there is no in-process stack to sit on. The task is
15
+ * therefore persisted (surviving a gateway restart, which is the normal case
16
+ * for a quota wait), and a periodic drain claims whatever is due.
17
+ *
18
+ * Deliberately a LEAF module (node builtins + path resolution only): the
19
+ * gateway, the CLI and the dashboard all need it, and a shared queue that
20
+ * dragged the routing graph in would be unusable from the dashboard.
21
+ */
22
+ /** Which engine the ask needs when it is finally run. */
23
+ export type DeferredAskKind = 'chat' | 'pipeline';
24
+ /** Lifecycle of one deferred task. */
25
+ export type DeferredTaskStatus = 'pending' | 'running';
26
+ /** One failed ask waiting for a model to come back. */
27
+ export interface DeferredTask {
28
+ id: string;
29
+ /** Messaging platform (`whatsapp`, `telegram`, …) — the reply goes back here. */
30
+ platform: string;
31
+ /** The contact/channel to reply to. */
32
+ channelId: string;
33
+ /** Human sender label, replayed into the retry's origin context. */
34
+ from?: string;
35
+ senderId?: string;
36
+ isGroup?: boolean;
37
+ /** The ORIGINAL ask, verbatim — a retry must run exactly what was asked. */
38
+ text: string;
39
+ kind: DeferredAskKind;
40
+ createdAt: number;
41
+ /** Epoch ms of the last retry attempt (0 = none yet). */
42
+ lastAttemptAt: number;
43
+ /** How many retry attempts have run (never counts the original turn). */
44
+ attempts: number;
45
+ status: DeferredTaskStatus;
46
+ /** Earliest epoch ms the next attempt may run (from the report's free-up ETA). */
47
+ notBefore: number;
48
+ /** Stop retrying after this (a queue that never ends is not a service). */
49
+ deadline: number;
50
+ /**
51
+ * The sender explicitly said "yes".
52
+ *
53
+ * A task is queued optimistically the moment a turn fails (the ask was a real
54
+ * request, so completing it is what the user wants), but its persistence is
55
+ * proportional to CONSENT: an unconfirmed task retries a few times over half
56
+ * an hour, while a confirmed one keeps going for the full horizon. Nobody is
57
+ * enrolled in a six-hour retry loop they never agreed to.
58
+ */
59
+ confirmed?: boolean;
60
+ lastError?: string;
61
+ }
62
+ /** Everything the queue needs to remember an ask. */
63
+ export interface DeferTaskInput {
64
+ platform: string;
65
+ channelId: string;
66
+ text: string;
67
+ kind: DeferredAskKind;
68
+ from?: string;
69
+ senderId?: string;
70
+ isGroup?: boolean;
71
+ /** How long the failure report said until a model frees (absent = unknown). */
72
+ nextFreeInMs?: number;
73
+ /** The failure line the sender saw, for context in later reports. */
74
+ lastError?: string;
75
+ }
76
+ /** Confirmed horizon — "yes, keep trying until it is done". */
77
+ export declare const DEFERRED_TASK_TTL_MS: number;
78
+ /** Optimistic horizon — queued because the ask was real, but never confirmed. */
79
+ export declare const UNCONFIRMED_TASK_TTL_MS: number;
80
+ /** How many attempts this task is allowed. */
81
+ export declare function attemptCap(task: DeferredTask): number;
82
+ /** Read the queue. Best-effort: a corrupt file is an empty queue, never a throw. */
83
+ export declare function loadDeferredTasks(): DeferredTask[];
84
+ /** Clamp a free-up hint into a sane retry wait. */
85
+ export declare function retryWaitMs(nextFreeInMs?: number): number;
86
+ /**
87
+ * Record a failed ask for retry, or refresh the pending task for that
88
+ * conversation.
89
+ *
90
+ * The UPDATE path deliberately preserves `attempts` and `createdAt`: the retry
91
+ * that just failed re-enters this function (it goes through the same failure
92
+ * branch), and resetting the counters there would make the attempt cap and TTL
93
+ * meaningless — the task would retry forever.
94
+ *
95
+ * @returns the stored task and whether it was created (vs refreshed).
96
+ */
97
+ export declare function deferTask(input: DeferTaskInput): {
98
+ task: DeferredTask;
99
+ created: boolean;
100
+ };
101
+ /** The live task for a conversation (newest first), if any. */
102
+ export declare function getPendingTask(platform: string, channelId: string): DeferredTask | undefined;
103
+ /** Every task currently waiting (for status surfaces, newest first). */
104
+ export declare function listPendingTasks(): DeferredTask[];
105
+ /**
106
+ * One drain OWNS a subset of the queue.
107
+ *
108
+ * The store is shared by every process that can serve a channel (the gateway
109
+ * for WhatsApp/Telegram, the dashboard server for its own chat), so each drain
110
+ * declares what it owns. Without this the gateway would claim a `dashboard`
111
+ * task and try to deliver it to a messaging platform — and then remove it.
112
+ */
113
+ export type TaskOwnership = (task: DeferredTask) => boolean;
114
+ /** Tasks whose next attempt is due and whose TTL has not elapsed. */
115
+ export declare function dueTasks(now?: number, owns?: TaskOwnership): DeferredTask[];
116
+ /** Tasks that ran out of attempts or TTL — the sender must be told, not ghosted. */
117
+ export declare function expiredTasks(now?: number, owns?: TaskOwnership): DeferredTask[];
118
+ /**
119
+ * The sender said yes: extend this task to the full horizon and keep going.
120
+ * Returns the confirmed task (or undefined when it had already expired).
121
+ */
122
+ export declare function confirmTask(id: string, now?: number): DeferredTask | undefined;
123
+ /** Apply a partial patch to one task by id. Returns the patched task. */
124
+ export declare function updateDeferredTask(id: string, patch: Partial<DeferredTask>): DeferredTask | undefined;
125
+ /** Drop a task (on success, on a cancel reply, or when it expires). */
126
+ export declare function removeDeferredTask(id: string): void;
127
+ /** Drop every task for a conversation (`stop`, `no`, `cancel`). */
128
+ export declare function cancelTasksFor(platform: string, channelId: string): number;
129
+ /**
130
+ * Normalize a reply for phrase matching: lowercase, emoji/punctuation stripped,
131
+ * whitespace collapsed. `"Yes, please! 🙏"` → `"yes please"`.
132
+ */
133
+ export declare function normalizeRetryAnswer(text: string | null | undefined): string;
134
+ /**
135
+ * Is this message the sender ACCEPTING the retry offer?
136
+ *
137
+ * Two gates, both required:
138
+ * 1. the whole message must be short (≤ 6 words) — anything longer is a new
139
+ * request that merely happens to start with "yes", and swallowing it would
140
+ * lose the user's actual ask;
141
+ * 2. it must be an exact accept phrase, or a short message carrying an accept
142
+ * token and NO decline token ("yes, keep trying" accepts; "no, do the
143
+ * other thing" does not).
144
+ *
145
+ * A message that fails either gate falls through to normal handling — the
146
+ * pending task simply stays queued, so the sender can accept later.
147
+ */
148
+ export declare function isRetryAcceptance(text: string | null | undefined): boolean;
149
+ /** Is this message the sender cancelling the retry offer? */
150
+ export declare function isRetryDecline(text: string | null | undefined): boolean;
151
+ /** Confirmation sent the moment an offer is accepted. */
152
+ export declare function acceptedLine(task: DeferredTask, now?: number): string;
153
+ /** The line sent when a retry gives up (TTL or attempt cap reached). */
154
+ export declare function abandonedLine(task: DeferredTask, now?: number): string;
155
+ /** The line sent when a retry attempt starts, so an unexpected reply is explained. */
156
+ export declare function retryingLine(task: DeferredTask): string;
157
+ /** Count of live tasks (status surfaces / dashboard). */
158
+ export declare function pendingTaskCount(): number;
159
+ //# sourceMappingURL=deferred-task.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred-task.d.ts","sourceRoot":"","sources":["../../src/learning/deferred-task.ts"],"names":[],"mappings":"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"}