@memnexus-ai/cli 1.7.235 → 1.7.237
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/commands/memories.d.ts +6 -0
- package/dist/commands/memories.d.ts.map +1 -1
- package/dist/commands/memories.js +135 -13
- package/dist/commands/memories.js.map +1 -1
- package/dist/lib/api-client.d.ts +17 -1
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +42 -11
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/renderable-retrieval.d.ts +54 -0
- package/dist/lib/renderable-retrieval.d.ts.map +1 -1
- package/dist/lib/renderable-retrieval.js +117 -4
- package/dist/lib/renderable-retrieval.js.map +1 -1
- package/dist/lib/retry.d.ts +32 -0
- package/dist/lib/retry.d.ts.map +1 -1
- package/dist/lib/retry.js +89 -5
- package/dist/lib/retry.js.map +1 -1
- package/package.json +2 -2
|
@@ -27,6 +27,12 @@ export declare function recordDeletion(guardPath: string, now: number): void;
|
|
|
27
27
|
* happened and how to override.
|
|
28
28
|
*/
|
|
29
29
|
export declare function checkBulkDeleteGuard(guardPath: string, now: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* One-line cause for a recall/digest HTTP failure, or null when the status is
|
|
32
|
+
* not one the recall path reports itself (those fall through to handleError).
|
|
33
|
+
* `elapsedMs` covers every attempt, so "after N s" is what the caller waited.
|
|
34
|
+
*/
|
|
35
|
+
export declare function describeRecallFailure(error: unknown, elapsedMs: number): string | null;
|
|
30
36
|
/**
|
|
31
37
|
* Parse the --code-context JSON flag.
|
|
32
38
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memories.d.ts","sourceRoot":"","sources":["../../src/commands/memories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"memories.d.ts","sourceRoot":"","sources":["../../src/commands/memories.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,7 @@ exports.getBulkDeleteGuardPath = getBulkDeleteGuardPath;
|
|
|
41
41
|
exports.readDeleteGuardTimestamps = readDeleteGuardTimestamps;
|
|
42
42
|
exports.recordDeletion = recordDeletion;
|
|
43
43
|
exports.checkBulkDeleteGuard = checkBulkDeleteGuard;
|
|
44
|
+
exports.describeRecallFailure = describeRecallFailure;
|
|
44
45
|
exports.parseCodeContextFlag = parseCodeContextFlag;
|
|
45
46
|
exports.parseBatchIds = parseBatchIds;
|
|
46
47
|
exports.isValidIsoDate = isValidIsoDate;
|
|
@@ -196,6 +197,43 @@ const RECALL_MAX_MS = (() => {
|
|
|
196
197
|
// code needs setting.
|
|
197
198
|
const EXIT_FULL_TIMEOUT = 5;
|
|
198
199
|
const EXIT_DEGRADED_RESULT = 6;
|
|
200
|
+
/**
|
|
201
|
+
* One-line cause for a recall/digest HTTP failure, or null when the status is
|
|
202
|
+
* not one the recall path reports itself (those fall through to handleError).
|
|
203
|
+
* `elapsedMs` covers every attempt, so "after N s" is what the caller waited.
|
|
204
|
+
*/
|
|
205
|
+
function describeRecallFailure(error, elapsedMs) {
|
|
206
|
+
const status = (0, retry_1.httpStatus)(error);
|
|
207
|
+
const secs = `${(elapsedMs / 1000).toFixed(1)}s`;
|
|
208
|
+
const rawReason = (0, retry_1.errorBody)(error)?.reason;
|
|
209
|
+
const reason = typeof rawReason === 'string' ? (0, errors_1.sanitizeServerText)(rawReason, 64) : '';
|
|
210
|
+
switch (status) {
|
|
211
|
+
case 503:
|
|
212
|
+
if (reason === 'deadline_exceeded') {
|
|
213
|
+
return (`Recall failed: the server's digest deadline was exceeded after ${secs} ` +
|
|
214
|
+
`(HTTP 503 deadline_exceeded). Not retried: each retry starts another LLM synthesis.`);
|
|
215
|
+
}
|
|
216
|
+
return `Recall failed: the digest service was unavailable after ${secs} (HTTP 503${reason ? ` ${reason}` : ''}). Not retried.`;
|
|
217
|
+
case 500:
|
|
218
|
+
return (`Recall failed: the server errored while generating the digest after ${secs} (HTTP 500). ` +
|
|
219
|
+
`Not retried. A common cause is the LLM provider rate-limiting digest synthesis.`);
|
|
220
|
+
case 429: {
|
|
221
|
+
const hinted = (0, retry_1.getRetryAfterMs)(error);
|
|
222
|
+
const hint = hinted === null
|
|
223
|
+
? // Only the body field is visible: the SDK drops response headers,
|
|
224
|
+
// so a Retry-After HEADER may have been sent and is not seen here.
|
|
225
|
+
'the server sent no retryAfter in the response body'
|
|
226
|
+
: `the server asked to retry after ${Math.round(hinted / 1000)}s`;
|
|
227
|
+
return `Recall failed: rate limited after ${secs} (HTTP 429; ${hint}).`;
|
|
228
|
+
}
|
|
229
|
+
case 502:
|
|
230
|
+
case 504:
|
|
231
|
+
case 408:
|
|
232
|
+
return `Recall failed: gateway/transport error after ${secs} (HTTP ${status}).`;
|
|
233
|
+
default:
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
199
237
|
/** True when an error is the SDK aborting the digest call at the ceiling. */
|
|
200
238
|
function isRecallTimeoutError(error) {
|
|
201
239
|
const e = error;
|
|
@@ -554,6 +592,19 @@ function retryRead(fn) {
|
|
|
554
592
|
onRetry: emitRetryNotice,
|
|
555
593
|
});
|
|
556
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Wrap the recall/digest call (POST /api/memories/digest). Every attempt runs a
|
|
597
|
+
* server-side LLM synthesis, so this uses the narrower recall policy — at most
|
|
598
|
+
* one retry, never on 503/500, 429 only with a server Retry-After — instead of
|
|
599
|
+
* retryRead. See withRecallRetry in lib/retry.ts and GH #5570.
|
|
600
|
+
*/
|
|
601
|
+
function retryRecall(fn) {
|
|
602
|
+
return (0, retry_1.withRecallRetry)(fn, {
|
|
603
|
+
sleep: retry_1.sleep,
|
|
604
|
+
maxRetries: retry_1.SINGLE_SHOT_MAX_RETRIES,
|
|
605
|
+
onRetry: emitRetryNotice,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
557
608
|
/**
|
|
558
609
|
* Wrap a non-idempotent single-shot write (plain POST create, non-CAS update).
|
|
559
610
|
* Retries ONLY 429 (server rejected before processing — no duplicate risk);
|
|
@@ -2519,8 +2570,15 @@ function registerMemoriesCommands(program) {
|
|
|
2519
2570
|
const search = renderable_retrieval_1.RenderableSearchResult.fromApiResponse(searchData);
|
|
2520
2571
|
// The headline is the first thing a caller reads and was unconditional:
|
|
2521
2572
|
// "Found N results" over an incomplete gather reads as a full answer.
|
|
2522
|
-
|
|
2523
|
-
|
|
2573
|
+
// (#5450) A suppressed result set is the same failure mode as a degraded
|
|
2574
|
+
// one from the caller's point of view — a short or empty answer that is
|
|
2575
|
+
// not evidence of absence — but it arrives with every branch healthy, so
|
|
2576
|
+
// it needs its own check. The headline is the first thing read, so it
|
|
2577
|
+
// carries the count of discarded results rather than a success glyph.
|
|
2578
|
+
if (search.health.degraded || search.suppression.suppressed) {
|
|
2579
|
+
spinner?.warn(`Found ${search.results.length} results` +
|
|
2580
|
+
`${(0, renderable_retrieval_1.degradationHeadlineSuffix)(search.health)}` +
|
|
2581
|
+
`${(0, renderable_retrieval_1.suppressionHeadlineSuffix)(search.suppression)}`);
|
|
2524
2582
|
}
|
|
2525
2583
|
else {
|
|
2526
2584
|
spinner?.succeed(`Found ${search.results.length} results`);
|
|
@@ -2532,15 +2590,32 @@ function registerMemoriesCommands(program) {
|
|
|
2532
2590
|
if (degradedLine) {
|
|
2533
2591
|
console.error(chalk_1.default.yellow(degradedLine));
|
|
2534
2592
|
}
|
|
2593
|
+
// Anchor-gate suppression marker (#5450) — stderr, same placement and
|
|
2594
|
+
// for the same reason: it must reach the caller in every output mode,
|
|
2595
|
+
// including --format json, where stdout has to stay byte-identical to
|
|
2596
|
+
// what a machine caller already parses.
|
|
2597
|
+
const suppressedLine = (0, renderable_retrieval_1.suppressionWarningLine)(search.suppression);
|
|
2598
|
+
if (suppressedLine) {
|
|
2599
|
+
console.error(chalk_1.default.yellow(suppressedLine));
|
|
2600
|
+
}
|
|
2535
2601
|
// v4.21 FR-7: gate the exit code so a scripted caller can tell "partial
|
|
2536
2602
|
// answer" (6) from a complete result (0), matching recall/digest/status.
|
|
2537
|
-
//
|
|
2538
|
-
//
|
|
2539
|
-
//
|
|
2540
|
-
//
|
|
2541
|
-
//
|
|
2542
|
-
//
|
|
2543
|
-
|
|
2603
|
+
// A zero-result-but-degraded search (the worst case: "nothing found" that
|
|
2604
|
+
// is actually incomplete) exits 6, while a zero-result COMPLETE search
|
|
2605
|
+
// stays 0. Set via process.exitCode (NOT process.exit) so the buffered
|
|
2606
|
+
// stdout/JSON of every output branch below flushes first. The stderr
|
|
2607
|
+
// warning, headline suffix, and --json/--yaml health shape are unchanged.
|
|
2608
|
+
//
|
|
2609
|
+
// (#5450) DELIBERATE CONTRACT CHANGE: this gate was keyed strictly on
|
|
2610
|
+
// health.degraded, so a suppressed empty exited 0 and a wrapper branching
|
|
2611
|
+
// on $? saw a clean pass — the pre-fix silence surviving through the one
|
|
2612
|
+
// channel the rest of this fix does not reach. A suppressed empty IS the
|
|
2613
|
+
// worst case this gate's own comment describes, arriving by a different
|
|
2614
|
+
// route, so the contract's stated intent already covers it. A caller
|
|
2615
|
+
// treating 6 as "retry" will now retry on a suppressed empty, which is
|
|
2616
|
+
// the correct response: re-running with different wording is the
|
|
2617
|
+
// documented remedy.
|
|
2618
|
+
if (search.health.degraded || search.suppression.suppressed) {
|
|
2544
2619
|
process.exitCode = EXIT_DEGRADED_RESULT;
|
|
2545
2620
|
}
|
|
2546
2621
|
// Surface extraction failures (#2862). Failed memories are invisible to
|
|
@@ -2606,6 +2681,10 @@ function registerMemoriesCommands(program) {
|
|
|
2606
2681
|
if (llmMarker) {
|
|
2607
2682
|
console.log(llmMarker);
|
|
2608
2683
|
}
|
|
2684
|
+
const llmSuppressed = (0, renderable_retrieval_1.suppressionSummaryLine)(search.suppression);
|
|
2685
|
+
if (llmSuppressed) {
|
|
2686
|
+
console.log(llmSuppressed);
|
|
2687
|
+
}
|
|
2609
2688
|
(0, formatters_1.printOutput)(llmData, 'llm', undefined, {
|
|
2610
2689
|
totalCount: search.total,
|
|
2611
2690
|
previewLength: Math.min(previewLength, 100), // Shorter preview for LLM
|
|
@@ -2626,6 +2705,10 @@ function registerMemoriesCommands(program) {
|
|
|
2626
2705
|
if (compactMarker) {
|
|
2627
2706
|
console.log(chalk_1.default.yellow(compactMarker));
|
|
2628
2707
|
}
|
|
2708
|
+
const compactSuppressed = (0, renderable_retrieval_1.suppressionSummaryLine)(search.suppression);
|
|
2709
|
+
if (compactSuppressed) {
|
|
2710
|
+
console.log(chalk_1.default.yellow(compactSuppressed));
|
|
2711
|
+
}
|
|
2629
2712
|
(0, formatters_1.printOutput)(compactData, 'compact');
|
|
2630
2713
|
}
|
|
2631
2714
|
else if (effectiveFormat === 'table' || !effectiveFormat) {
|
|
@@ -2683,6 +2766,10 @@ function registerMemoriesCommands(program) {
|
|
|
2683
2766
|
if (tableMarker) {
|
|
2684
2767
|
console.log(chalk_1.default.yellow(tableMarker));
|
|
2685
2768
|
}
|
|
2769
|
+
const tableSuppressed = (0, renderable_retrieval_1.suppressionSummaryLine)(search.suppression);
|
|
2770
|
+
if (tableSuppressed) {
|
|
2771
|
+
console.log(chalk_1.default.yellow(tableSuppressed));
|
|
2772
|
+
}
|
|
2686
2773
|
// Show temporal filters if applied
|
|
2687
2774
|
const temporal = search.temporalMetadata;
|
|
2688
2775
|
if (temporal?.temporalFieldsIncluded) {
|
|
@@ -3443,6 +3530,7 @@ function registerDigestCommand(memories) {
|
|
|
3443
3530
|
.option('--show-sources', 'Display source memory IDs')
|
|
3444
3531
|
.option('--format <format>', 'Output format (json|yaml|llm)')
|
|
3445
3532
|
.action(async (options) => {
|
|
3533
|
+
let callStartedAt;
|
|
3446
3534
|
try {
|
|
3447
3535
|
if (!options.query) {
|
|
3448
3536
|
throw (0, errors_1.validationError)('--query is required');
|
|
@@ -3470,13 +3558,16 @@ function registerDigestCommand(memories) {
|
|
|
3470
3558
|
// 30s default to the 180s ceiling. The SDK aborts the fetch via AbortController
|
|
3471
3559
|
// when this elapses (verified in @memnexus-ai/typescript-sdk http client), so
|
|
3472
3560
|
// the call fast-fails instead of hanging (KI-77 client half).
|
|
3473
|
-
|
|
3561
|
+
// Single-attempt transport: the SDK's own retry layer is disabled for this
|
|
3562
|
+
// call so retryRecall is the only retry policy (GH #5570).
|
|
3563
|
+
const sdk = (0, api_client_1.getSingleAttemptSdk)();
|
|
3474
3564
|
const prevTimeout = sdk.config?.timeoutMs ?? 30000;
|
|
3475
3565
|
if (sdk.config)
|
|
3476
3566
|
sdk.config.timeoutMs = RECALL_MAX_MS;
|
|
3477
3567
|
let response;
|
|
3568
|
+
callStartedAt = Date.now();
|
|
3478
3569
|
try {
|
|
3479
|
-
response = await
|
|
3570
|
+
response = await retryRecall(() => sdk.memories.generateMemoryDigest(body));
|
|
3480
3571
|
}
|
|
3481
3572
|
finally {
|
|
3482
3573
|
if (sdk.config)
|
|
@@ -3532,6 +3623,21 @@ function registerDigestCommand(memories) {
|
|
|
3532
3623
|
displayDigest(digest, metadata, sources, options, keyFacts, entities, effectiveStateBreakdown, renderable.health);
|
|
3533
3624
|
}
|
|
3534
3625
|
catch (error) {
|
|
3626
|
+
// GH #5570: name the cause of a server-side failure and point at the
|
|
3627
|
+
// retrieval path that needs no LLM synthesis. Exit 5 is the code
|
|
3628
|
+
// handleError already used for every one of these statuses. Checked
|
|
3629
|
+
// BEFORE the client-ceiling branch: an HTTP 504 carries the message
|
|
3630
|
+
// "HTTP 504: Gateway Timeout", which isRecallTimeoutError would otherwise
|
|
3631
|
+
// misreport as the CLI's own 180s ceiling (same exit code, wrong cause).
|
|
3632
|
+
const cause = callStartedAt === undefined
|
|
3633
|
+
? null
|
|
3634
|
+
: describeRecallFailure(error, Date.now() - callStartedAt);
|
|
3635
|
+
if (cause !== null) {
|
|
3636
|
+
console.error(chalk_1.default.red(`\n❌ ${cause}`));
|
|
3637
|
+
console.error(chalk_1.default.yellow('\n💡 Workaround: retrieve the memories directly, without synthesis:'));
|
|
3638
|
+
console.error(chalk_1.default.yellow(' mx memories search --query "<query>" --id-only | mx memories get --stdin'));
|
|
3639
|
+
process.exit(5);
|
|
3640
|
+
}
|
|
3535
3641
|
// KI-77: name the ceiling and give a narrower-query fix instead of the SDK's
|
|
3536
3642
|
// opaque "operation was aborted" so the user knows what happened and how to recover.
|
|
3537
3643
|
if (isRecallTimeoutError(error)) {
|
|
@@ -3850,8 +3956,17 @@ function registerRecapCommand(memories) {
|
|
|
3850
3956
|
});
|
|
3851
3957
|
}
|
|
3852
3958
|
const truncated = results.length >= fetchLimit;
|
|
3853
|
-
|
|
3854
|
-
|
|
3959
|
+
// (#5450) recap calls the same searchMemoriesGet endpoint as `search`, so
|
|
3960
|
+
// it sits behind the same fulltext-anchor gate and can be handed `[]` with
|
|
3961
|
+
// every branch healthy. It read `health` only, so a suppressed empty
|
|
3962
|
+
// printed "No memories found in the last 24h" with no marker anywhere —
|
|
3963
|
+
// and recap is a command agents run for the prior-art gate this fix
|
|
3964
|
+
// protects. Mirrored from the `search` handler above.
|
|
3965
|
+
const recapSuppression = renderable.suppression;
|
|
3966
|
+
if (health.degraded || recapSuppression.suppressed) {
|
|
3967
|
+
spinner.warn(`Found ${results.length} memories` +
|
|
3968
|
+
`${(0, renderable_retrieval_1.degradationHeadlineSuffix)(health)}` +
|
|
3969
|
+
`${(0, renderable_retrieval_1.suppressionHeadlineSuffix)(recapSuppression)}`);
|
|
3855
3970
|
}
|
|
3856
3971
|
else {
|
|
3857
3972
|
spinner.succeed(`Found ${results.length} memories`);
|
|
@@ -3862,6 +3977,13 @@ function registerRecapCommand(memories) {
|
|
|
3862
3977
|
if (recapDegraded) {
|
|
3863
3978
|
console.error(chalk_1.default.yellow(recapDegraded));
|
|
3864
3979
|
}
|
|
3980
|
+
// Same placement and the same reason for the suppression marker: stderr,
|
|
3981
|
+
// BEFORE the zero-result return below, so it survives --format json and
|
|
3982
|
+
// the early exit that a suppressed empty takes.
|
|
3983
|
+
const recapSuppressed = (0, renderable_retrieval_1.suppressionWarningLine)(recapSuppression);
|
|
3984
|
+
if (recapSuppressed) {
|
|
3985
|
+
console.error(chalk_1.default.yellow(recapSuppressed));
|
|
3986
|
+
}
|
|
3865
3987
|
if (results.length === 0) {
|
|
3866
3988
|
console.log(chalk_1.default.yellow(`\nNo memories found in the last ${options.recent}.`));
|
|
3867
3989
|
return;
|