@adhdev/daemon-core 0.9.82-rc.422 → 0.9.82-rc.424
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/index.js +42 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -6
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-ledger.d.ts +1 -1
- package/dist/providers/cli-provider-instance.d.ts +13 -0
- package/package.json +2 -2
- package/src/mesh/mesh-event-forwarding.ts +5 -0
- package/src/mesh/mesh-ledger.ts +44 -1
- package/src/providers/cli-provider-instance.ts +37 -2
|
@@ -58,7 +58,7 @@ export interface MeshWorkerResultArtifact {
|
|
|
58
58
|
errors: string[];
|
|
59
59
|
nextAction?: string;
|
|
60
60
|
requiresUserAction: boolean;
|
|
61
|
-
source: 'explicit_metadata' | 'final_summary_json' | 'default';
|
|
61
|
+
source: 'explicit_metadata' | 'final_summary_json' | 'parseable_answer' | 'default';
|
|
62
62
|
}
|
|
63
63
|
export interface MeshTaskCompletionEvidence {
|
|
64
64
|
source: 'agent_status_event';
|
|
@@ -16,6 +16,19 @@ type PersistableCliHistoryMessage = {
|
|
|
16
16
|
senderName?: string;
|
|
17
17
|
receivedAt?: number;
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* NOTIF Defect-2a: the REPORTED short-generating duration, anchored on the IMMUTABLE turn
|
|
21
|
+
* start. generatingStartedAt is reset to 0 on every mid-turn waiting_approval/idle blip and
|
|
22
|
+
* re-armed on the next →generating, so a long turn that blips would otherwise measure only the
|
|
23
|
+
* final 1.5-2.5s sliver. engine.currentTurnStartedAt (set once at onTurnStarted, surviving
|
|
24
|
+
* mid-turn blips until the next turn starts) is preferred; generatingStartedAt is the fallback
|
|
25
|
+
* for turns that never recorded an engine turn start. Returns 0 when neither anchor is set.
|
|
26
|
+
* Pure / unit-testable.
|
|
27
|
+
*/
|
|
28
|
+
export declare function computeTurnAnchoredDurationMs(engineTurnStartedAt: number | undefined, generatingStartedAt: number, now: number): {
|
|
29
|
+
durationMs: number;
|
|
30
|
+
anchor: 'turn-start' | 'generatingStartedAt' | 'none';
|
|
31
|
+
};
|
|
19
32
|
export declare function buildCliStructuredInputPrompt(input: InputEnvelope, options?: {
|
|
20
33
|
materializeDir?: string;
|
|
21
34
|
}): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.9.82-rc.
|
|
3
|
+
"version": "0.9.82-rc.424",
|
|
4
4
|
"description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"author": "vilmire",
|
|
47
47
|
"license": "AGPL-3.0-or-later",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@adhdev/mesh-shared": "0.9.82-rc.
|
|
49
|
+
"@adhdev/mesh-shared": "0.9.82-rc.424",
|
|
50
50
|
"@adhdev/session-host-core": "*",
|
|
51
51
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
52
52
|
"ajv": "^8.20.0",
|
|
@@ -1174,6 +1174,11 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
1174
1174
|
: undefined,
|
|
1175
1175
|
evidence: completionEvidence,
|
|
1176
1176
|
// B2: evidenceLevel lets coordinator know when completion evidence is insufficient.
|
|
1177
|
+
// NOTIF Defect-2b: ONLY source==='default' (no parseable answer at all) is
|
|
1178
|
+
// 'insufficient'. 'parseable_answer' (a real JSON answer that just isn't
|
|
1179
|
+
// worker-result-shaped, e.g. a MAGI envelope) is concrete evidence and must
|
|
1180
|
+
// resolve to 'sufficient' — resolveWorkerResult now upgrades that case so a
|
|
1181
|
+
// complete, valid answer is no longer mislabelled insufficient/reviewRecommended.
|
|
1177
1182
|
...(completionEvidence
|
|
1178
1183
|
? completionEvidence.workerResult.source === 'default'
|
|
1179
1184
|
? { evidenceLevel: 'insufficient', reviewRecommended: true }
|
package/src/mesh/mesh-ledger.ts
CHANGED
|
@@ -126,7 +126,14 @@ export interface MeshWorkerResultArtifact {
|
|
|
126
126
|
errors: string[];
|
|
127
127
|
nextAction?: string;
|
|
128
128
|
requiresUserAction: boolean;
|
|
129
|
-
|
|
129
|
+
// NOTIF Defect-2b: `parseable_answer` = the final summary held a parseable JSON
|
|
130
|
+
// ANSWER (e.g. a MAGI claim_audit / rca envelope) that is NOT worker-result-shaped
|
|
131
|
+
// (no status + changedFiles/errors/…). It is still concrete evidence that the worker
|
|
132
|
+
// produced a real, parseable answer — so it must NOT be labelled evidenceLevel
|
|
133
|
+
// 'insufficient' — but it is NOT a self-attributing worker result, so it is deliberately
|
|
134
|
+
// distinct from 'final_summary_json' and stays subject to the direct-dispatch grace gate
|
|
135
|
+
// in mesh-events-stale.ts (which keys on `!== 'final_summary_json'`).
|
|
136
|
+
source: 'explicit_metadata' | 'final_summary_json' | 'parseable_answer' | 'default';
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
export interface MeshTaskCompletionEvidence {
|
|
@@ -508,6 +515,35 @@ export function normalizeMeshWorkerResult(input?: Record<string, unknown>, sourc
|
|
|
508
515
|
};
|
|
509
516
|
}
|
|
510
517
|
|
|
518
|
+
/**
|
|
519
|
+
* NOTIF Defect-2b: does the summary contain ANY parseable JSON object answer (not just a
|
|
520
|
+
* worker-result-shaped one)? Some providers (and every MAGI replica) emit a complete, valid
|
|
521
|
+
* answer as a JSON envelope that has no `status`/`changedFiles` worker-result fields, so
|
|
522
|
+
* extractJsonObjectFromSummary returns undefined and the completion is mislabelled
|
|
523
|
+
* source='default' → evidenceLevel='insufficient' even though a real answer was produced.
|
|
524
|
+
* This is a conservative existence check: it only returns true when a JSON object actually
|
|
525
|
+
* parses out of the summary (raw or fenced), so an empty / prose-only / unparseable summary
|
|
526
|
+
* still resolves to 'default'.
|
|
527
|
+
*/
|
|
528
|
+
function summaryHasParseableJsonAnswer(summary?: string): boolean {
|
|
529
|
+
const text = readNonEmptyString(summary);
|
|
530
|
+
if (!text) return false;
|
|
531
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
532
|
+
const candidates = [fenced?.[1], text].filter(Boolean) as string[];
|
|
533
|
+
for (const candidate of candidates) {
|
|
534
|
+
const trimmed = candidate.trim();
|
|
535
|
+
if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) continue;
|
|
536
|
+
try {
|
|
537
|
+
const parsed = JSON.parse(trimmed);
|
|
538
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
539
|
+
&& Object.keys(parsed).length > 0) {
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
} catch { /* try next candidate */ }
|
|
543
|
+
}
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
|
|
511
547
|
function resolveWorkerResult(opts: BuildTaskCompletionEvidenceOptions): MeshWorkerResultArtifact {
|
|
512
548
|
if (opts.workerResult && typeof opts.workerResult === 'object') {
|
|
513
549
|
return normalizeMeshWorkerResult(opts.workerResult, 'explicit_metadata');
|
|
@@ -516,6 +552,13 @@ function resolveWorkerResult(opts: BuildTaskCompletionEvidenceOptions): MeshWork
|
|
|
516
552
|
if (parsed) {
|
|
517
553
|
return normalizeMeshWorkerResult(parsed, 'final_summary_json');
|
|
518
554
|
}
|
|
555
|
+
// NOTIF Defect-2b: no worker-result-shaped JSON, but a parseable JSON answer IS present
|
|
556
|
+
// (the common MAGI / answer-only case). Treat it as concrete evidence so the completion is
|
|
557
|
+
// not labelled 'insufficient', while keeping the worker-result fields empty (status stays
|
|
558
|
+
// 'unknown') — we only know an answer parsed, not its task outcome.
|
|
559
|
+
if (summaryHasParseableJsonAnswer(opts.finalSummary)) {
|
|
560
|
+
return normalizeMeshWorkerResult(undefined, 'parseable_answer');
|
|
561
|
+
}
|
|
519
562
|
return normalizeMeshWorkerResult(undefined, 'default');
|
|
520
563
|
}
|
|
521
564
|
|
|
@@ -249,6 +249,28 @@ function isCliGeneratingLikeStatus(status: unknown): boolean {
|
|
|
249
249
|
return status === 'generating' || status === 'streaming' || status === 'no_progress' || status === 'long_generating' || status === 'starting';
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* NOTIF Defect-2a: the REPORTED short-generating duration, anchored on the IMMUTABLE turn
|
|
254
|
+
* start. generatingStartedAt is reset to 0 on every mid-turn waiting_approval/idle blip and
|
|
255
|
+
* re-armed on the next →generating, so a long turn that blips would otherwise measure only the
|
|
256
|
+
* final 1.5-2.5s sliver. engine.currentTurnStartedAt (set once at onTurnStarted, surviving
|
|
257
|
+
* mid-turn blips until the next turn starts) is preferred; generatingStartedAt is the fallback
|
|
258
|
+
* for turns that never recorded an engine turn start. Returns 0 when neither anchor is set.
|
|
259
|
+
* Pure / unit-testable.
|
|
260
|
+
*/
|
|
261
|
+
export function computeTurnAnchoredDurationMs(
|
|
262
|
+
engineTurnStartedAt: number | undefined,
|
|
263
|
+
generatingStartedAt: number,
|
|
264
|
+
now: number,
|
|
265
|
+
): { durationMs: number; anchor: 'turn-start' | 'generatingStartedAt' | 'none' } {
|
|
266
|
+
const engineStart = typeof engineTurnStartedAt === 'number' && Number.isFinite(engineTurnStartedAt)
|
|
267
|
+
? engineTurnStartedAt
|
|
268
|
+
: 0;
|
|
269
|
+
if (engineStart > 0) return { durationMs: now - engineStart, anchor: 'turn-start' };
|
|
270
|
+
if (generatingStartedAt > 0) return { durationMs: now - generatingStartedAt, anchor: 'generatingStartedAt' };
|
|
271
|
+
return { durationMs: 0, anchor: 'none' };
|
|
272
|
+
}
|
|
273
|
+
|
|
252
274
|
export function buildCliStructuredInputPrompt(
|
|
253
275
|
input: InputEnvelope,
|
|
254
276
|
options: { materializeDir?: string } = {},
|
|
@@ -2375,8 +2397,21 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
2375
2397
|
// Still emit agent:generating_completed so mesh orchestration can record
|
|
2376
2398
|
// task_completed for direct dispatches that complete faster than the debounce.
|
|
2377
2399
|
if (this.generatingDebouncePending) {
|
|
2378
|
-
|
|
2379
|
-
|
|
2400
|
+
// NOTIF Defect-2a: shortDurationMs is the REPORTED turn duration, so it must be
|
|
2401
|
+
// measured from the IMMUTABLE turn start — not generatingStartedAt, which is
|
|
2402
|
+
// reset to 0 on every mid-turn waiting_approval/idle blip (see :1864/1885/2397/
|
|
2403
|
+
// 2503/2521) and re-armed on the next →generating, so a long turn that blipped
|
|
2404
|
+
// would measure only the final 1.5-2.5s sliver. engine.currentTurnStartedAt is
|
|
2405
|
+
// stamped once at onTurnStarted and persists past mid-turn blips until the next
|
|
2406
|
+
// turn starts, so it captures the true turn length. generatingStartedAt remains
|
|
2407
|
+
// the fallback (and the debounce itself stays a pure UI-suppression signal,
|
|
2408
|
+
// decoupled from the reported duration).
|
|
2409
|
+
const { durationMs: shortDurationMs, anchor: durationAnchor } = computeTurnAnchoredDurationMs(
|
|
2410
|
+
(this.adapter as any)?.currentTurnStartedAt,
|
|
2411
|
+
this.generatingStartedAt,
|
|
2412
|
+
now,
|
|
2413
|
+
);
|
|
2414
|
+
LOG.info('CLI', `[${this.type}] suppressed short generating (${shortDurationMs}ms, anchor=${durationAnchor})`);
|
|
2380
2415
|
if (this.generatingDebounceTimer) { clearTimeout(this.generatingDebounceTimer); this.generatingDebounceTimer = null; }
|
|
2381
2416
|
// Emit completion for mesh task association even though the UI generating
|
|
2382
2417
|
// started/completed pair is suppressed (too short for visible UI update).
|