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.
- package/dist/agents/agents/reasoner.d.ts +8 -0
- package/dist/agents/agents/reasoner.d.ts.map +1 -1
- package/dist/agents/agents/reasoner.js +53 -2
- package/dist/agents/agents/reasoner.js.map +1 -1
- package/dist/agents/agents/writer.d.ts +24 -0
- package/dist/agents/agents/writer.d.ts.map +1 -1
- package/dist/agents/agents/writer.js +194 -0
- package/dist/agents/agents/writer.js.map +1 -1
- package/dist/agents/composite-plan.d.ts +143 -0
- package/dist/agents/composite-plan.d.ts.map +1 -0
- package/dist/agents/composite-plan.js +399 -0
- package/dist/agents/composite-plan.js.map +1 -0
- package/dist/agents/long-form-plan.d.ts +156 -0
- package/dist/agents/long-form-plan.d.ts.map +1 -0
- package/dist/agents/long-form-plan.js +274 -0
- package/dist/agents/long-form-plan.js.map +1 -0
- package/dist/agents/orchestrator.d.ts +107 -0
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +501 -35
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/agents/prompt-assembly.d.ts +8 -0
- package/dist/agents/prompt-assembly.d.ts.map +1 -1
- package/dist/agents/prompt-assembly.js +17 -0
- package/dist/agents/prompt-assembly.js.map +1 -1
- package/dist/cli/chat.d.ts +27 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +133 -8
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/execute.d.ts +12 -0
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +105 -2
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/models.d.ts.map +1 -1
- package/dist/cli/models.js +10 -0
- package/dist/cli/models.js.map +1 -1
- package/dist/cli/nlu.d.ts +8 -0
- package/dist/cli/nlu.d.ts.map +1 -1
- package/dist/cli/nlu.js +57 -0
- package/dist/cli/nlu.js.map +1 -1
- package/dist/cli/trace.d.ts.map +1 -1
- package/dist/cli/trace.js +27 -0
- package/dist/cli/trace.js.map +1 -1
- package/dist/gateway/gateway-log.d.ts +1 -1
- package/dist/gateway/gateway-log.d.ts.map +1 -1
- package/dist/gateway/gateway-log.js.map +1 -1
- package/dist/gateway/registry.d.ts +116 -1
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +575 -52
- package/dist/gateway/registry.js.map +1 -1
- package/dist/inference/model-entitlement.d.ts +46 -0
- package/dist/inference/model-entitlement.d.ts.map +1 -0
- package/dist/inference/model-entitlement.js +98 -0
- package/dist/inference/model-entitlement.js.map +1 -0
- package/dist/inference/tool-call-utils.d.ts.map +1 -1
- package/dist/inference/tool-call-utils.js +70 -1
- package/dist/inference/tool-call-utils.js.map +1 -1
- package/dist/learning/autonomy-policy.d.ts +334 -0
- package/dist/learning/autonomy-policy.d.ts.map +1 -0
- package/dist/learning/autonomy-policy.js +500 -0
- package/dist/learning/autonomy-policy.js.map +1 -0
- package/dist/learning/credential-fingerprint.d.ts +58 -0
- package/dist/learning/credential-fingerprint.d.ts.map +1 -0
- package/dist/learning/credential-fingerprint.js +126 -0
- package/dist/learning/credential-fingerprint.js.map +1 -0
- package/dist/learning/deferred-task.d.ts +159 -0
- package/dist/learning/deferred-task.d.ts.map +1 -0
- package/dist/learning/deferred-task.js +451 -0
- package/dist/learning/deferred-task.js.map +1 -0
- package/dist/learning/deliverable-class.d.ts +130 -0
- package/dist/learning/deliverable-class.d.ts.map +1 -0
- package/dist/learning/deliverable-class.js +432 -0
- package/dist/learning/deliverable-class.js.map +1 -0
- package/dist/learning/long-form.d.ts +252 -0
- package/dist/learning/long-form.d.ts.map +1 -0
- package/dist/learning/long-form.js +510 -0
- package/dist/learning/long-form.js.map +1 -0
- package/dist/learning/model-first-router.d.ts +17 -0
- package/dist/learning/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +35 -0
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-registry.d.ts +96 -4
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +128 -6
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/model-warmup.d.ts +97 -2
- package/dist/learning/model-warmup.d.ts.map +1 -1
- package/dist/learning/model-warmup.js +165 -60
- package/dist/learning/model-warmup.js.map +1 -1
- package/dist/learning/prompt-layers.d.ts +61 -0
- package/dist/learning/prompt-layers.d.ts.map +1 -0
- package/dist/learning/prompt-layers.js +140 -0
- package/dist/learning/prompt-layers.js.map +1 -0
- package/dist/learning/provider-limits.d.ts +66 -0
- package/dist/learning/provider-limits.d.ts.map +1 -0
- package/dist/learning/provider-limits.js +184 -0
- package/dist/learning/provider-limits.js.map +1 -0
- package/dist/learning/reasoning-trace.d.ts +36 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js +36 -2
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/resilient-call.d.ts +36 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +118 -8
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/unattended-job.d.ts +293 -0
- package/dist/learning/unattended-job.d.ts.map +1 -0
- package/dist/learning/unattended-job.js +544 -0
- package/dist/learning/unattended-job.js.map +1 -0
- package/dist/learning/unattended-progress.d.ts +95 -0
- package/dist/learning/unattended-progress.d.ts.map +1 -0
- package/dist/learning/unattended-progress.js +147 -0
- package/dist/learning/unattended-progress.js.map +1 -0
- package/dist/learning/working-state.d.ts +109 -0
- package/dist/learning/working-state.d.ts.map +1 -0
- package/dist/learning/working-state.js +244 -0
- package/dist/learning/working-state.js.map +1 -0
- package/dist/nlu/conversation-gate.d.ts +46 -0
- package/dist/nlu/conversation-gate.d.ts.map +1 -1
- package/dist/nlu/conversation-gate.js +73 -6
- package/dist/nlu/conversation-gate.js.map +1 -1
- package/dist/nlu/intent-confirm.d.ts +82 -0
- package/dist/nlu/intent-confirm.d.ts.map +1 -0
- package/dist/nlu/intent-confirm.js +146 -0
- package/dist/nlu/intent-confirm.js.map +1 -0
- package/dist/nlu/learnings.d.ts +101 -0
- package/dist/nlu/learnings.d.ts.map +1 -0
- package/dist/nlu/learnings.js +283 -0
- package/dist/nlu/learnings.js.map +1 -0
- package/dist/tools/coding-tools.d.ts.map +1 -1
- package/dist/tools/coding-tools.js +95 -19
- package/dist/tools/coding-tools.js.map +1 -1
- package/dist/tools/edit-verification.d.ts +125 -0
- package/dist/tools/edit-verification.d.ts.map +1 -0
- package/dist/tools/edit-verification.js +237 -0
- package/dist/tools/edit-verification.js.map +1 -0
- package/dist/tools/git-tool.d.ts.map +1 -1
- package/dist/tools/git-tool.js +37 -4
- package/dist/tools/git-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +30 -2
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +40 -11
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/run-cli.d.ts.map +1 -1
- package/dist/tools/run-cli.js +40 -13
- package/dist/tools/run-cli.js.map +1 -1
- package/dist/tools/run-terminal.d.ts +6 -1
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +158 -18
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/tool-loop.d.ts +35 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +157 -3
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts +35 -0
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +97 -18
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/chat-retry.d.ts +143 -0
- package/dist/web-dashboard/chat-retry.d.ts.map +1 -0
- package/dist/web-dashboard/chat-retry.js +227 -0
- package/dist/web-dashboard/chat-retry.js.map +1 -0
- package/dist/web-dashboard/server.d.ts +17 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +200 -9
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +81 -4
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/{index-CQW0qv1r.js → index-kCUkORm7.js} +27 -27
- package/src/web-dashboard/public/assets/index-kCUkORm7.js.map +1 -0
- package/src/web-dashboard/public/index.html +1 -1
- 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":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,yDAAyD;AACzD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,CAAC;AAElD,sCAAsC;AACtC,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvD,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,QAAgB,CAAC;AAClD,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,QAAc,CAAC;AAMnD,8CAA8C;AAC9C,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAErD;AAoCD,oFAAoF;AACpF,wBAAgB,iBAAiB,IAAI,YAAY,EAAE,CAUlD;AAmED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAwCzF;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAG5F;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,IAAI,YAAY,EAAE,CAEjD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC;AAE5D,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAmB,EAAE,IAAI,GAAE,aAA0B,GAAG,YAAY,EAAE,CASnG;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAmB,EAAE,IAAI,GAAE,aAA0B,GAAG,YAAY,EAAE,CAIvG;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,YAAY,GAAG,SAAS,CAS1F;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,GAAG,SAAS,CAOrG;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAM1E;AAsGD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAM5E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAa1E;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAevE;AAID,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAOjF;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAgBlF;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAGvD;AAED,yDAAyD;AACzD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
|