@pellux/goodvibes-agent 1.2.0 → 1.4.1
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/CHANGELOG.md +194 -0
- package/dist/package/{ast-grep-napi.linux-x64-gnu-swtppvy9.node → ast-grep-napi.linux-x64-gnu-mkk8xwww.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ttfcdtap.node → ast-grep-napi.linux-x64-musl-ryqtgdv6.node} +0 -0
- package/dist/package/main.js +65740 -57156
- package/docs/README.md +3 -3
- package/docs/connected-host.md +2 -2
- package/docs/getting-started.md +11 -9
- package/docs/tools-and-commands.md +12 -10
- package/docs/voice-and-live-tts.md +2 -2
- package/package.json +1 -1
- package/release/release-notes.md +15 -144
- package/release/release-readiness.json +36 -36
- package/src/agent/competitive-feature-inventory.ts +42 -44
- package/src/agent/setup-wizard-artifact-receipts.ts +366 -0
- package/src/agent/setup-wizard.ts +267 -24
- package/src/cli/tui-startup.ts +2 -2
- package/src/input/agent-workspace-activation.ts +2 -2
- package/src/input/agent-workspace-categories.ts +2 -2
- package/src/input/agent-workspace-onboarding-categories.ts +4 -4
- package/src/input/agent-workspace-onboarding-finish.ts +21 -0
- package/src/input/agent-workspace-settings.ts +47 -1
- package/src/input/agent-workspace-setup-snapshot.ts +17 -6
- package/src/input/agent-workspace-setup.ts +20 -26
- package/src/input/agent-workspace-snapshot.ts +16 -3
- package/src/input/agent-workspace-types.ts +5 -2
- package/src/input/agent-workspace.ts +21 -6
- package/src/input/handler.ts +67 -5
- package/src/input/setup-wizard-live-receipts.ts +76 -0
- package/src/renderer/agent-workspace-context-lines.ts +17 -33
- package/src/renderer/agent-workspace.ts +434 -21
- package/src/runtime/tool-permission-safety.ts +1 -1
- package/src/tools/agent-harness-agent-orchestration-policy.ts +75 -0
- package/src/tools/agent-harness-agent-orchestration.ts +216 -128
- package/src/tools/agent-harness-autonomy-live-records.ts +154 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +1 -1
- package/src/tools/agent-harness-autonomy-queue.ts +19 -8
- package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
- package/src/tools/agent-harness-background-processes.ts +8 -4
- package/src/tools/agent-harness-browser-cockpit-route.ts +188 -34
- package/src/tools/agent-harness-browser-control.ts +12 -4
- package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -0
- package/src/tools/agent-harness-device-live-read-models.ts +366 -0
- package/src/tools/agent-harness-execution-posture.ts +3 -0
- package/src/tools/agent-harness-interactive-runtime-records.ts +421 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +71 -1
- package/src/tools/agent-harness-local-model-endpoints.ts +469 -354
- package/src/tools/agent-harness-local-model-smoke.ts +277 -0
- package/src/tools/agent-harness-local-model-url.ts +78 -0
- package/src/tools/agent-harness-media-posture.ts +27 -12
- package/src/tools/agent-harness-memory-external-providers.ts +796 -0
- package/src/tools/agent-harness-memory-posture.ts +253 -137
- package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
- package/src/tools/agent-harness-memory-refinement.ts +340 -0
- package/src/tools/agent-harness-mode-catalog.ts +4 -2
- package/src/tools/agent-harness-model-provider-health.ts +139 -42
- package/src/tools/agent-harness-model-readiness.ts +31 -5
- package/src/tools/agent-harness-model-routing-types.ts +61 -0
- package/src/tools/agent-harness-model-routing.ts +31 -6
- package/src/tools/agent-harness-pairing-posture.ts +30 -9
- package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +81 -15
- package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
- package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
- package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
- package/src/tools/agent-harness-personal-ops-records.ts +176 -224
- package/src/tools/agent-harness-personal-ops-types.ts +19 -1
- package/src/tools/agent-harness-personal-ops.ts +18 -11
- package/src/tools/agent-harness-remote-read-models.ts +541 -0
- package/src/tools/agent-harness-research-briefing.ts +26 -7
- package/src/tools/agent-harness-research-live-read-models.ts +500 -0
- package/src/tools/agent-harness-research-runs.ts +15 -3
- package/src/tools/agent-harness-research-workflow.ts +92 -19
- package/src/tools/agent-harness-setup-model-helpers.ts +1 -0
- package/src/tools/agent-harness-setup-posture.ts +7 -7
- package/src/tools/agent-harness-setup-smoke.ts +26 -1
- package/src/tools/agent-harness-tool-schema.ts +23 -1
- package/src/tools/agent-harness-tool-types.ts +5 -0
- package/src/tools/agent-harness-tool.ts +9 -1
- package/src/tools/agent-harness-workspace-actions.ts +1 -1
- package/src/tools/agent-memory-tool.ts +40 -1
- package/src/tools/agent-model-compare-run.ts +13 -0
- package/src/tools/agent-research-runner.ts +367 -0
- package/src/tools/agent-research-tool.ts +7 -179
- package/src/tools/agent-route-planner-candidates-surfaces.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -2,10 +2,12 @@ import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifact
|
|
|
2
2
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
3
3
|
import { buildAgentWorkspaceRuntimeSnapshot } from '../input/agent-workspace-snapshot.ts';
|
|
4
4
|
import { previewHarnessText } from './agent-harness-text.ts';
|
|
5
|
-
import { hasMethod } from './agent-harness-personal-ops-discovery.ts';
|
|
6
5
|
import { redactedPersonalOpsText } from './agent-harness-personal-ops-runner.ts';
|
|
6
|
+
import { personalOpsRecordCertification } from './agent-harness-personal-ops-certification.ts';
|
|
7
7
|
import type { PersonalOpsConnectorSignal, PersonalOpsConnectorTool, PersonalOpsLane, PersonalOpsLaneId, PersonalOpsLiveRecord, PersonalOpsRecordFreshness, PersonalOpsStatus, PersonalOpsWorkflow, PersonalOpsWorkflowStatus } from './agent-harness-personal-ops-types.ts';
|
|
8
8
|
|
|
9
|
+
type PersonalOpsEffectReceiptLaneId = Extract<PersonalOpsLaneId, 'inbox' | 'calendar' | 'tasks' | 'reminders'>;
|
|
10
|
+
|
|
9
11
|
export function laneStatusRank(status: PersonalOpsStatus): number {
|
|
10
12
|
if (status === 'ready') return 4;
|
|
11
13
|
if (status === 'partial') return 3;
|
|
@@ -61,6 +63,15 @@ export function searchText(lane: PersonalOpsLane): string {
|
|
|
61
63
|
record.freshness.refreshRoute ?? '',
|
|
62
64
|
record.freshness.policy,
|
|
63
65
|
].join('\n') : '',
|
|
66
|
+
record.certification ? [
|
|
67
|
+
record.certification.schemaStatus,
|
|
68
|
+
record.certification.schemaVersion ?? '',
|
|
69
|
+
record.certification.publicationGuarantee ?? '',
|
|
70
|
+
record.certification.publisher ?? '',
|
|
71
|
+
record.certification.provenance?.join('\n') ?? '',
|
|
72
|
+
record.certification.receiptIds?.join('\n') ?? '',
|
|
73
|
+
record.certification.missingSignals.join('\n'),
|
|
74
|
+
].join('\n') : '',
|
|
64
75
|
]).join('\n') ?? '',
|
|
65
76
|
].join('\n').toLowerCase();
|
|
66
77
|
}
|
|
@@ -70,7 +81,7 @@ export function describeLiveRecord(record: PersonalOpsLiveRecord, includeParamet
|
|
|
70
81
|
id: record.id,
|
|
71
82
|
label: record.label,
|
|
72
83
|
status: record.status,
|
|
73
|
-
summary: previewHarnessText(record.summary, includeParameters ?
|
|
84
|
+
summary: previewHarnessText(record.summary, includeParameters ? 240 : 96),
|
|
74
85
|
userRoute: previewHarnessText(record.userRoute, includeParameters ? 140 : 96),
|
|
75
86
|
modelRoute: previewHarnessText(record.modelRoute, includeParameters ? 140 : 96),
|
|
76
87
|
...(record.tags && record.tags.length > 0 ? { tags: record.tags.slice(0, includeParameters ? 12 : 4) } : {}),
|
|
@@ -85,6 +96,7 @@ export function describeLiveRecord(record: PersonalOpsLiveRecord, includeParamet
|
|
|
85
96
|
...(includeParameters && typeof record.reviewRecordCount === 'number' ? { reviewRecordCount: record.reviewRecordCount } : {}),
|
|
86
97
|
...(includeParameters && record.reviewLabels && record.reviewLabels.length > 0 ? { reviewLabels: record.reviewLabels } : {}),
|
|
87
98
|
...(includeParameters && record.sourceTool ? { sourceTool: record.sourceTool } : {}),
|
|
99
|
+
...(includeParameters && record.certification ? { certification: record.certification } : {}),
|
|
88
100
|
...(includeParameters && record.freshness ? { freshness: record.freshness } : {}),
|
|
89
101
|
...(includeParameters && record.followUpRoutes && record.followUpRoutes.length > 0 ? { followUpRoutes: record.followUpRoutes } : {}),
|
|
90
102
|
};
|
|
@@ -279,6 +291,14 @@ export function artifactMetadataStringArray(artifact: ArtifactDescriptor, key: s
|
|
|
279
291
|
return [];
|
|
280
292
|
}
|
|
281
293
|
|
|
294
|
+
const PERSONAL_OPS_EFFECT_RECEIPT_PURPOSES = new Set([
|
|
295
|
+
'personal-ops-provider-effect-receipt',
|
|
296
|
+
'personal-ops-effect-receipt',
|
|
297
|
+
'personal-ops-connector-effect-receipt',
|
|
298
|
+
'agent-personal-ops-effect-receipt',
|
|
299
|
+
'connected-host-personal-ops-effect-receipt',
|
|
300
|
+
]);
|
|
301
|
+
|
|
282
302
|
export function safeRecordIdPart(value: string): string {
|
|
283
303
|
return value
|
|
284
304
|
.toLowerCase()
|
|
@@ -287,6 +307,24 @@ export function safeRecordIdPart(value: string): string {
|
|
|
287
307
|
.slice(0, 80) || 'item';
|
|
288
308
|
}
|
|
289
309
|
|
|
310
|
+
function artifactCreatedAtIso(artifact: ArtifactDescriptor): string {
|
|
311
|
+
return typeof artifact.createdAt === 'number' && Number.isFinite(artifact.createdAt)
|
|
312
|
+
? new Date(artifact.createdAt).toISOString()
|
|
313
|
+
: '';
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function metadataCreatedAtIso(artifact: ArtifactDescriptor): string {
|
|
317
|
+
const explicit = artifactMetadataString(artifact, 'createdAt')
|
|
318
|
+
|| artifactMetadataString(artifact, 'recordedAt')
|
|
319
|
+
|| artifactMetadataString(artifact, 'completedAt')
|
|
320
|
+
|| artifactMetadataString(artifact, 'timestamp');
|
|
321
|
+
if (explicit) {
|
|
322
|
+
const parsed = Date.parse(explicit);
|
|
323
|
+
if (Number.isFinite(parsed)) return new Date(parsed).toISOString();
|
|
324
|
+
}
|
|
325
|
+
return artifactCreatedAtIso(artifact);
|
|
326
|
+
}
|
|
327
|
+
|
|
290
328
|
export function savedReviewArtifacts(context: CommandContext, laneId: 'inbox' | 'calendar'): readonly ArtifactDescriptor[] {
|
|
291
329
|
const store = context.platform.artifactStore;
|
|
292
330
|
if (!store?.list) return [];
|
|
@@ -305,6 +343,141 @@ export function savedReviewArtifacts(context: CommandContext, laneId: 'inbox' |
|
|
|
305
343
|
}
|
|
306
344
|
}
|
|
307
345
|
|
|
346
|
+
function savedProviderEffectReceiptArtifacts(context: CommandContext, laneId: PersonalOpsEffectReceiptLaneId): readonly ArtifactDescriptor[] {
|
|
347
|
+
const store = context.platform.artifactStore;
|
|
348
|
+
if (!store?.list) return [];
|
|
349
|
+
try {
|
|
350
|
+
return store.list(100)
|
|
351
|
+
.filter((artifact) => PERSONAL_OPS_EFFECT_RECEIPT_PURPOSES.has(artifactMetadataString(artifact, 'purpose')))
|
|
352
|
+
.filter((artifact) => artifactMetadataString(artifact, 'laneId') === laneId)
|
|
353
|
+
.sort((left, right) => {
|
|
354
|
+
const leftCreated = typeof left.createdAt === 'number' ? left.createdAt : 0;
|
|
355
|
+
const rightCreated = typeof right.createdAt === 'number' ? right.createdAt : 0;
|
|
356
|
+
return rightCreated - leftCreated;
|
|
357
|
+
})
|
|
358
|
+
.slice(0, 10);
|
|
359
|
+
} catch {
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function normalizedEffectReceiptStatus(artifact: ArtifactDescriptor): string {
|
|
365
|
+
const raw = (artifactMetadataString(artifact, 'status')
|
|
366
|
+
|| artifactMetadataString(artifact, 'outcome')
|
|
367
|
+
|| artifactMetadataString(artifact, 'result')).toLowerCase();
|
|
368
|
+
if (!raw) return 'unknown';
|
|
369
|
+
if (['ok', 'ready', 'success', 'succeeded', 'complete', 'completed', 'sent', 'archived', 'labeled', 'updated', 'accepted', 'declined'].includes(raw)) return 'succeeded';
|
|
370
|
+
if (['blocked', 'needs-review', 'needs_setup', 'needs-setup'].includes(raw)) return 'blocked';
|
|
371
|
+
if (['fail', 'failed', 'error', 'errored'].includes(raw)) return 'failed';
|
|
372
|
+
if (['running', 'pending', 'in-progress', 'in_progress'].includes(raw)) return 'running';
|
|
373
|
+
return raw;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function providerEffectSubjectId(artifact: ArtifactDescriptor): string {
|
|
377
|
+
return artifactMetadataString(artifact, 'subjectId')
|
|
378
|
+
|| artifactMetadataString(artifact, 'threadId')
|
|
379
|
+
|| artifactMetadataString(artifact, 'messageId')
|
|
380
|
+
|| artifactMetadataString(artifact, 'eventId')
|
|
381
|
+
|| artifactMetadataString(artifact, 'taskId')
|
|
382
|
+
|| artifactMetadataString(artifact, 'reminderId')
|
|
383
|
+
|| artifactMetadataString(artifact, 'scheduleId')
|
|
384
|
+
|| artifactMetadataString(artifact, 'providerRecordId')
|
|
385
|
+
|| artifactMetadataString(artifact, 'targetId');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function effectReceiptLaneLabel(laneId: PersonalOpsEffectReceiptLaneId): string {
|
|
389
|
+
if (laneId === 'inbox') return 'Inbox';
|
|
390
|
+
if (laneId === 'calendar') return 'Calendar';
|
|
391
|
+
if (laneId === 'tasks') return 'Task';
|
|
392
|
+
return 'Reminder';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function effectReceiptCapability(laneId: PersonalOpsEffectReceiptLaneId): string {
|
|
396
|
+
if (laneId === 'inbox') return 'inbox-effect-receipt';
|
|
397
|
+
if (laneId === 'calendar') return 'calendar-effect-receipt';
|
|
398
|
+
if (laneId === 'tasks') return 'task-effect-receipt';
|
|
399
|
+
return 'reminder-effect-receipt';
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function savedProviderEffectReceiptRecords(
|
|
403
|
+
context: CommandContext,
|
|
404
|
+
laneId: PersonalOpsEffectReceiptLaneId,
|
|
405
|
+
): readonly PersonalOpsLiveRecord[] {
|
|
406
|
+
return savedProviderEffectReceiptArtifacts(context, laneId).map((artifact) => {
|
|
407
|
+
const laneLabel = effectReceiptLaneLabel(laneId);
|
|
408
|
+
const lowerLaneLabel = laneLabel.toLowerCase();
|
|
409
|
+
const providerId = artifactMetadataString(artifact, 'providerId') || artifactMetadataString(artifact, 'provider') || 'provider';
|
|
410
|
+
const operation = artifactMetadataString(artifact, 'operation') || artifactMetadataString(artifact, 'action') || `${laneId}-effect`;
|
|
411
|
+
const status = normalizedEffectReceiptStatus(artifact);
|
|
412
|
+
const sourceTool = artifactMetadataString(artifact, 'sourceTool') || artifactMetadataString(artifact, 'qualifiedName');
|
|
413
|
+
const subjectId = providerEffectSubjectId(artifact);
|
|
414
|
+
const receiptId = artifactMetadataString(artifact, 'receiptId') || artifact.id;
|
|
415
|
+
const createdAt = metadataCreatedAtIso(artifact);
|
|
416
|
+
const failureReason = artifactMetadataString(artifact, 'failureReason') || artifactMetadataString(artifact, 'error');
|
|
417
|
+
const redaction = artifactMetadataString(artifact, 'redaction') || artifactMetadataString(artifact, 'redactionPolicy') || 'metadata-only';
|
|
418
|
+
const nextRoute = artifactMetadataString(artifact, 'nextRoute')
|
|
419
|
+
|| `personal_ops action:"lane" laneId:"${laneId}" includeParameters:true`;
|
|
420
|
+
const artifactRoute = `agent_artifacts show artifactId:"${artifact.id}" includeContent:false`;
|
|
421
|
+
const operationLabel = operation.replace(/[-_]+/g, ' ');
|
|
422
|
+
const certification = personalOpsRecordCertification({
|
|
423
|
+
record: artifactMetadata(artifact),
|
|
424
|
+
sourcePath: sourceTool || artifactRoute,
|
|
425
|
+
durableId: subjectId || receiptId,
|
|
426
|
+
recordKind: `${lowerLaneLabel} provider-effect receipt`,
|
|
427
|
+
hasConfirmedEffectRoute: true,
|
|
428
|
+
requireReceipt: true,
|
|
429
|
+
});
|
|
430
|
+
return {
|
|
431
|
+
id: `provider-effect-receipt:${artifact.id}`,
|
|
432
|
+
label: `${laneLabel} effect receipt: ${operationLabel}`,
|
|
433
|
+
status,
|
|
434
|
+
summary: [
|
|
435
|
+
`Confirmed ${lowerLaneLabel} provider-effect receipt ${receiptId} reports ${operation} ${status}.`,
|
|
436
|
+
providerId ? `Provider ${providerId}.` : '',
|
|
437
|
+
subjectId ? `Subject ${previewHarnessText(redactedPersonalOpsText(subjectId), 96)}.` : '',
|
|
438
|
+
`Redaction ${redaction}.`,
|
|
439
|
+
failureReason ? `Failure ${previewHarnessText(redactedPersonalOpsText(failureReason), 140)}.` : '',
|
|
440
|
+
sourceTool ? `Source ${sourceTool}.` : '',
|
|
441
|
+
createdAt ? `Recorded ${createdAt}.` : '',
|
|
442
|
+
].filter(Boolean).join(' '),
|
|
443
|
+
userRoute: `Agent Workspace -> Personal Ops -> ${laneLabel} effect receipts`,
|
|
444
|
+
modelRoute: artifactRoute,
|
|
445
|
+
tags: [
|
|
446
|
+
'provider-effect-receipt',
|
|
447
|
+
'artifact',
|
|
448
|
+
`${laneId}-effect`,
|
|
449
|
+
operation,
|
|
450
|
+
status,
|
|
451
|
+
providerId,
|
|
452
|
+
].filter(Boolean),
|
|
453
|
+
effect: 'read-only',
|
|
454
|
+
capability: effectReceiptCapability(laneId),
|
|
455
|
+
confirmationRequired: false,
|
|
456
|
+
artifactId: artifact.id,
|
|
457
|
+
...(sourceTool ? { sourceTool } : {}),
|
|
458
|
+
certification,
|
|
459
|
+
followUpRoutes: [
|
|
460
|
+
{
|
|
461
|
+
id: 'inspect-effect-receipt',
|
|
462
|
+
label: 'Inspect provider-effect receipt',
|
|
463
|
+
effect: 'read-only',
|
|
464
|
+
modelRoute: artifactRoute,
|
|
465
|
+
requiresConfirmation: false,
|
|
466
|
+
policy: 'Receipt inspection is read-only and uses redacted artifact metadata/content boundaries.',
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: 'continue-provider-lane',
|
|
470
|
+
label: `Continue ${lowerLaneLabel} lane review`,
|
|
471
|
+
effect: 'read-only',
|
|
472
|
+
modelRoute: nextRoute,
|
|
473
|
+
requiresConfirmation: false,
|
|
474
|
+
policy: 'Use the lane posture to decide whether a fresh connector read or separate confirmed provider effect is appropriate.',
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
};
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
|
|
308
481
|
export function matchingReadTool(
|
|
309
482
|
connectors: readonly PersonalOpsConnectorSignal[],
|
|
310
483
|
sourceTool: string,
|
|
@@ -508,225 +681,4 @@ export function savedReviewArtifactRecords(
|
|
|
508
681
|
});
|
|
509
682
|
}
|
|
510
683
|
|
|
511
|
-
export
|
|
512
|
-
const records: PersonalOpsLiveRecord[] = [
|
|
513
|
-
{
|
|
514
|
-
id: 'workplan-list',
|
|
515
|
-
label: 'Review visible work plan',
|
|
516
|
-
status: 'ready',
|
|
517
|
-
summary: 'Read Agent-owned work-plan items before starting or switching multi-step work.',
|
|
518
|
-
userRoute: 'Agent Workspace -> Work -> Review work plan',
|
|
519
|
-
modelRoute: 'agent_work_plan action:"list"',
|
|
520
|
-
tags: ['work-plan', 'task-read'],
|
|
521
|
-
effect: 'read-only',
|
|
522
|
-
capability: 'task-read',
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
id: 'workplan-add',
|
|
526
|
-
label: 'Add visible work item',
|
|
527
|
-
status: 'ready',
|
|
528
|
-
summary: 'Create one local Agent work-plan item instead of hiding task state in chat.',
|
|
529
|
-
userRoute: 'Agent Workspace -> Personal Ops -> Add work item',
|
|
530
|
-
modelRoute: 'agent_work_plan action:"create" title:"..."',
|
|
531
|
-
tags: ['work-plan', 'task-write'],
|
|
532
|
-
effect: 'confirmed-effect',
|
|
533
|
-
capability: 'task-write',
|
|
534
|
-
requiredFields: ['title'],
|
|
535
|
-
optionalFields: ['detail', 'priority', 'status'],
|
|
536
|
-
confirmationRequired: false,
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
id: 'workplan-status',
|
|
540
|
-
label: 'Update work item status',
|
|
541
|
-
status: 'ready',
|
|
542
|
-
summary: 'Move one visible work item through pending, active, blocked, done, failed, or cancelled state.',
|
|
543
|
-
userRoute: 'Agent Workspace -> Work -> Update work item status',
|
|
544
|
-
modelRoute: 'agent_work_plan action:"set_status" id:"..." status:"..."',
|
|
545
|
-
tags: ['work-plan', 'task-write'],
|
|
546
|
-
effect: 'confirmed-effect',
|
|
547
|
-
capability: 'task-write',
|
|
548
|
-
requiredFields: ['id', 'status'],
|
|
549
|
-
confirmationRequired: false,
|
|
550
|
-
},
|
|
551
|
-
];
|
|
552
|
-
if (hasMethod(methodIds, 'tasks.list')) {
|
|
553
|
-
records.push({
|
|
554
|
-
id: 'host-tasks-list',
|
|
555
|
-
label: 'List connected-host tasks',
|
|
556
|
-
status: 'ready',
|
|
557
|
-
summary: 'Inspect connected-host task state without creating, retrying, or mutating host tasks.',
|
|
558
|
-
userRoute: 'Agent Workspace -> Work -> Host tasks',
|
|
559
|
-
modelRoute: 'workspace action:"action" actionId:"tasks-list"',
|
|
560
|
-
tags: ['host-task', 'task-read'],
|
|
561
|
-
effect: 'read-only',
|
|
562
|
-
capability: 'host-task-read',
|
|
563
|
-
});
|
|
564
|
-
}
|
|
565
|
-
if (hasMethod(methodIds, 'tasks.get') || hasMethod(methodIds, 'tasks.status')) {
|
|
566
|
-
records.push({
|
|
567
|
-
id: 'host-task-inspect',
|
|
568
|
-
label: 'Inspect connected-host task',
|
|
569
|
-
status: 'ready',
|
|
570
|
-
summary: 'Inspect one exact connected-host task id and output before considering controls.',
|
|
571
|
-
userRoute: 'Agent Workspace -> Work -> Inspect host task',
|
|
572
|
-
modelRoute: 'workspace action:"action" actionId:"task-show"',
|
|
573
|
-
tags: ['host-task', 'task-read'],
|
|
574
|
-
effect: 'read-only',
|
|
575
|
-
capability: 'host-task-read',
|
|
576
|
-
requiredFields: ['taskId'],
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
if (hasMethod(methodIds, 'tasks.cancel')) {
|
|
580
|
-
records.push({
|
|
581
|
-
id: 'host-task-cancel',
|
|
582
|
-
label: 'Cancel connected-host task',
|
|
583
|
-
status: 'ready',
|
|
584
|
-
summary: 'Cancel one exact connected-host task id only when the user authorizes it.',
|
|
585
|
-
userRoute: 'Agent Workspace -> Work -> Host task controls',
|
|
586
|
-
modelRoute: 'agent_operator_method methodId:"tasks.cancel" input:{"taskId":"..."} confirm:true explicitUserRequest:"..."',
|
|
587
|
-
tags: ['host-task', 'task-write'],
|
|
588
|
-
effect: 'confirmed-effect',
|
|
589
|
-
capability: 'host-task-control',
|
|
590
|
-
requiredFields: ['taskId'],
|
|
591
|
-
confirmationRequired: true,
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
if (hasMethod(methodIds, 'tasks.retry')) {
|
|
595
|
-
records.push({
|
|
596
|
-
id: 'host-task-retry',
|
|
597
|
-
label: 'Retry connected-host task',
|
|
598
|
-
status: 'ready',
|
|
599
|
-
summary: 'Retry one failed or cancelled connected-host task id only after inspection.',
|
|
600
|
-
userRoute: 'Agent Workspace -> Work -> Host task controls',
|
|
601
|
-
modelRoute: 'agent_operator_method methodId:"tasks.retry" input:{"taskId":"..."} confirm:true explicitUserRequest:"..."',
|
|
602
|
-
tags: ['host-task', 'task-write'],
|
|
603
|
-
effect: 'confirmed-effect',
|
|
604
|
-
capability: 'host-task-control',
|
|
605
|
-
requiredFields: ['taskId'],
|
|
606
|
-
confirmationRequired: true,
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
return records;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
export function reminderOperationRecords(methodIds: readonly string[], deliveryConfigured: boolean): readonly PersonalOpsLiveRecord[] {
|
|
613
|
-
const records: PersonalOpsLiveRecord[] = [
|
|
614
|
-
{
|
|
615
|
-
id: 'reminder-create',
|
|
616
|
-
label: 'Create confirmed reminder',
|
|
617
|
-
status: hasMethod(methodIds, 'schedules.create') ? deliveryConfigured ? 'ready' : 'attention' : 'needs-setup',
|
|
618
|
-
summary: deliveryConfigured
|
|
619
|
-
? 'Create one connected reminder schedule with real timing and a visible delivery path.'
|
|
620
|
-
: 'Create one reminder only after confirming timing and delivery scope; no configured delivery target was detected.',
|
|
621
|
-
userRoute: 'Agent Workspace -> Personal Ops -> Create reminder',
|
|
622
|
-
modelRoute: 'schedule action:"remind" message:"..." scheduleKind:"..." scheduleValue:"..." confirm:true explicitUserRequest:"..."',
|
|
623
|
-
tags: ['reminder', 'schedule-write'],
|
|
624
|
-
effect: 'confirmed-effect',
|
|
625
|
-
capability: 'reminder-create',
|
|
626
|
-
requiredFields: ['title', 'scheduleKind', 'scheduleValue'],
|
|
627
|
-
optionalFields: ['deliveryTargetId', 'timezone', 'message'],
|
|
628
|
-
confirmationRequired: true,
|
|
629
|
-
},
|
|
630
|
-
{
|
|
631
|
-
id: 'autonomous-schedule-create',
|
|
632
|
-
label: 'Create autonomous schedule',
|
|
633
|
-
status: hasMethod(methodIds, 'schedules.create') ? 'ready' : 'needs-setup',
|
|
634
|
-
summary: 'Create one visible autonomous schedule only when task, cadence, success criteria, and user request provenance are explicit.',
|
|
635
|
-
userRoute: 'Agent Workspace -> Automation -> Create schedule',
|
|
636
|
-
modelRoute: 'schedule action:"create" task:"..." successCriteria:"..." scheduleKind:"..." scheduleValue:"..." confirm:true explicitUserRequest:"..."',
|
|
637
|
-
tags: ['autonomy', 'schedule-write'],
|
|
638
|
-
effect: 'confirmed-effect',
|
|
639
|
-
capability: 'schedule-create',
|
|
640
|
-
requiredFields: ['task', 'successCriteria', 'scheduleKind', 'scheduleValue'],
|
|
641
|
-
confirmationRequired: true,
|
|
642
|
-
},
|
|
643
|
-
];
|
|
644
|
-
if (hasMethod(methodIds, 'schedules.list')) {
|
|
645
|
-
records.push({
|
|
646
|
-
id: 'schedule-list',
|
|
647
|
-
label: 'List connected schedules',
|
|
648
|
-
status: 'ready',
|
|
649
|
-
summary: 'Inspect configured schedules and history before running or mutating one.',
|
|
650
|
-
userRoute: 'Agent Workspace -> Automation -> Schedules',
|
|
651
|
-
modelRoute: 'workspace action:"action" actionId:"schedule-list"',
|
|
652
|
-
tags: ['schedule', 'schedule-read'],
|
|
653
|
-
effect: 'read-only',
|
|
654
|
-
capability: 'schedule-read',
|
|
655
|
-
});
|
|
656
|
-
records.push({
|
|
657
|
-
id: 'schedule-edit',
|
|
658
|
-
label: 'Edit connected schedule',
|
|
659
|
-
status: 'ready',
|
|
660
|
-
summary: 'Preview and edit one exact connected schedule id with before/after diff context.',
|
|
661
|
-
userRoute: 'Agent Workspace -> Automation -> Edit schedule',
|
|
662
|
-
modelRoute: 'schedule action:"edit" scheduleId:"..." confirm:true explicitUserRequest:"..."',
|
|
663
|
-
tags: ['schedule', 'schedule-write'],
|
|
664
|
-
effect: 'confirmed-effect',
|
|
665
|
-
capability: 'schedule-control',
|
|
666
|
-
requiredFields: ['scheduleId'],
|
|
667
|
-
optionalFields: ['name', 'scheduleKind', 'scheduleValue', 'prompt'],
|
|
668
|
-
confirmationRequired: true,
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
if (hasMethod(methodIds, 'schedules.run')) {
|
|
672
|
-
records.push({
|
|
673
|
-
id: 'schedule-run-now',
|
|
674
|
-
label: 'Run schedule now',
|
|
675
|
-
status: 'ready',
|
|
676
|
-
summary: 'Run one exact connected schedule id now after the user confirms.',
|
|
677
|
-
userRoute: 'Agent Workspace -> Automation -> Run job now',
|
|
678
|
-
modelRoute: 'schedule action:"run" scheduleId:"..." confirm:true explicitUserRequest:"..."',
|
|
679
|
-
tags: ['schedule', 'schedule-write'],
|
|
680
|
-
effect: 'confirmed-effect',
|
|
681
|
-
capability: 'schedule-control',
|
|
682
|
-
requiredFields: ['scheduleId'],
|
|
683
|
-
confirmationRequired: true,
|
|
684
|
-
});
|
|
685
|
-
}
|
|
686
|
-
if (hasMethod(methodIds, 'schedules.disable')) {
|
|
687
|
-
records.push({
|
|
688
|
-
id: 'schedule-pause',
|
|
689
|
-
label: 'Pause connected schedule',
|
|
690
|
-
status: 'ready',
|
|
691
|
-
summary: 'Disable one exact connected schedule id after reviewing current state.',
|
|
692
|
-
userRoute: 'Agent Workspace -> Automation -> Schedule controls',
|
|
693
|
-
modelRoute: 'schedule action:"pause" scheduleId:"..." confirm:true explicitUserRequest:"..."',
|
|
694
|
-
tags: ['schedule', 'schedule-write'],
|
|
695
|
-
effect: 'confirmed-effect',
|
|
696
|
-
capability: 'schedule-control',
|
|
697
|
-
requiredFields: ['scheduleId'],
|
|
698
|
-
confirmationRequired: true,
|
|
699
|
-
});
|
|
700
|
-
}
|
|
701
|
-
if (hasMethod(methodIds, 'schedules.enable')) {
|
|
702
|
-
records.push({
|
|
703
|
-
id: 'schedule-resume',
|
|
704
|
-
label: 'Resume connected schedule',
|
|
705
|
-
status: 'ready',
|
|
706
|
-
summary: 'Enable one exact connected schedule id after reviewing current state.',
|
|
707
|
-
userRoute: 'Agent Workspace -> Automation -> Schedule controls',
|
|
708
|
-
modelRoute: 'schedule action:"resume" scheduleId:"..." confirm:true explicitUserRequest:"..."',
|
|
709
|
-
tags: ['schedule', 'schedule-write'],
|
|
710
|
-
effect: 'confirmed-effect',
|
|
711
|
-
capability: 'schedule-control',
|
|
712
|
-
requiredFields: ['scheduleId'],
|
|
713
|
-
confirmationRequired: true,
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
if (hasMethod(methodIds, 'schedules.delete')) {
|
|
717
|
-
records.push({
|
|
718
|
-
id: 'schedule-delete',
|
|
719
|
-
label: 'Delete connected schedule',
|
|
720
|
-
status: 'ready',
|
|
721
|
-
summary: 'Delete one exact connected schedule id only after explicit user confirmation.',
|
|
722
|
-
userRoute: 'Agent Workspace -> Automation -> Schedule controls',
|
|
723
|
-
modelRoute: 'schedule action:"delete" scheduleId:"..." confirm:true explicitUserRequest:"..."',
|
|
724
|
-
tags: ['schedule', 'schedule-write'],
|
|
725
|
-
effect: 'confirmed-effect',
|
|
726
|
-
capability: 'schedule-control',
|
|
727
|
-
requiredFields: ['scheduleId'],
|
|
728
|
-
confirmationRequired: true,
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
return records;
|
|
732
|
-
}
|
|
684
|
+
export { reminderOperationRecords, taskOperationRecords } from './agent-harness-personal-ops-operations.ts';
|
|
@@ -94,10 +94,25 @@ export interface PersonalOpsLiveRecord {
|
|
|
94
94
|
readonly reviewRecordCount?: number;
|
|
95
95
|
readonly reviewLabels?: readonly string[];
|
|
96
96
|
readonly sourceTool?: string;
|
|
97
|
+
readonly certification?: PersonalOpsRecordCertification;
|
|
97
98
|
readonly followUpRoutes?: readonly PersonalOpsFollowUpRoute[];
|
|
98
99
|
readonly freshness?: PersonalOpsRecordFreshness;
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
export interface PersonalOpsRecordCertification {
|
|
103
|
+
readonly schemaStatus: 'certified' | 'legacy';
|
|
104
|
+
readonly schemaVersion?: string;
|
|
105
|
+
readonly publicationGuarantee?: string;
|
|
106
|
+
readonly publisher?: string;
|
|
107
|
+
readonly provenance?: readonly string[];
|
|
108
|
+
readonly receiptId?: string;
|
|
109
|
+
readonly receiptStatus?: string;
|
|
110
|
+
readonly receiptRoute?: string;
|
|
111
|
+
readonly receiptIds?: readonly string[];
|
|
112
|
+
readonly missingSignals: readonly string[];
|
|
113
|
+
readonly policy: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
101
116
|
export interface PersonalOpsFollowUpRoute {
|
|
102
117
|
readonly id: string;
|
|
103
118
|
readonly label: string;
|
|
@@ -119,11 +134,12 @@ export interface PersonalOpsRoutePacket {
|
|
|
119
134
|
export interface PersonalOpsRecordFreshness {
|
|
120
135
|
readonly status:
|
|
121
136
|
| 'fresh-provider-route-ready'
|
|
137
|
+
| 'fresh-provider-record-current'
|
|
122
138
|
| 'saved-review-refreshable'
|
|
123
139
|
| 'connector-attention'
|
|
124
140
|
| 'provider-contract-missing'
|
|
125
141
|
| 'source-tool-missing';
|
|
126
|
-
readonly source: 'connector-read' | 'saved-review-artifact';
|
|
142
|
+
readonly source: 'connector-read' | 'saved-review-artifact' | 'daemon-read-model' | 'sdk-read-model';
|
|
127
143
|
readonly sourceTool?: string;
|
|
128
144
|
readonly lastReviewedAt?: string;
|
|
129
145
|
readonly refreshRoute?: string;
|
|
@@ -215,6 +231,8 @@ export const PERSONAL_OPS_READ_CONTROL_FIELDS = new Set(['saveReviewCards', 'sav
|
|
|
215
231
|
export const QUEUE_CAPABILITIES = new Set([
|
|
216
232
|
'inbox-read',
|
|
217
233
|
'calendar-read',
|
|
234
|
+
'inbox-provider-thread',
|
|
235
|
+
'calendar-provider-event',
|
|
218
236
|
'inbox-thread-review',
|
|
219
237
|
'calendar-event-review',
|
|
220
238
|
'inbox-review-artifact',
|
|
@@ -52,6 +52,11 @@ function recordCount(lane: PersonalOpsLane, predicate: (record: PersonalOpsLiveR
|
|
|
52
52
|
return (lane.liveRecords ?? []).filter(predicate).length;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
function isFreshProviderRecord(record: PersonalOpsLiveRecord): boolean {
|
|
56
|
+
return record.freshness?.status === 'fresh-provider-route-ready'
|
|
57
|
+
|| record.freshness?.status === 'fresh-provider-record-current';
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
function workflowCount(lane: PersonalOpsLane, status: PersonalOpsWorkflowStatus): number {
|
|
56
61
|
return (lane.workflows ?? []).filter((workflow) => workflow.status === status).length;
|
|
57
62
|
}
|
|
@@ -67,12 +72,12 @@ function briefingPurpose(lane: PersonalOpsLane): string {
|
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
function briefingNext(lane: PersonalOpsLane): string {
|
|
70
|
-
const freshProviderReads = recordCount(lane,
|
|
75
|
+
const freshProviderReads = recordCount(lane, isFreshProviderRecord);
|
|
71
76
|
const refreshableSavedRecords = recordCount(lane, (record) => record.freshness?.status === 'saved-review-refreshable');
|
|
72
77
|
const savedReviewRecords = recordCount(lane, (record) => record.freshness?.source === 'saved-review-artifact' || typeof record.reviewRecordCount === 'number');
|
|
73
78
|
const attentionWorkflows = workflowCount(lane, 'attention');
|
|
74
79
|
if ((lane.id === 'inbox' || lane.id === 'calendar') && freshProviderReads > 0) {
|
|
75
|
-
return '
|
|
80
|
+
return 'Inspect one current provider-backed record first; run a bounded refresh/read route only when the returned record exposes one and the user asks for live provider data.';
|
|
76
81
|
}
|
|
77
82
|
if ((lane.id === 'inbox' || lane.id === 'calendar') && refreshableSavedRecords > 0) {
|
|
78
83
|
return 'Recap the saved redacted queue first; refresh a single record only through the returned confirmed read route.';
|
|
@@ -89,7 +94,7 @@ function briefingNext(lane: PersonalOpsLane): string {
|
|
|
89
94
|
function briefingStepForLane(lane: PersonalOpsLane, includeParameters: boolean): Record<string, unknown> {
|
|
90
95
|
const records = lane.liveRecords ?? [];
|
|
91
96
|
const workflows = lane.workflows ?? [];
|
|
92
|
-
const freshProviderReads = recordCount(lane,
|
|
97
|
+
const freshProviderReads = recordCount(lane, isFreshProviderRecord);
|
|
93
98
|
const refreshableSavedRecords = recordCount(lane, (record) => record.freshness?.status === 'saved-review-refreshable');
|
|
94
99
|
const savedReviewRecords = recordCount(lane, (record) => record.freshness?.source === 'saved-review-artifact' || typeof record.reviewRecordCount === 'number');
|
|
95
100
|
const readOnlyRecords = recordCount(lane, (record) => record.effect === 'read-only');
|
|
@@ -105,7 +110,7 @@ function briefingStepForLane(lane: PersonalOpsLane, includeParameters: boolean):
|
|
|
105
110
|
`${records.length} live/operation record(s)`,
|
|
106
111
|
`${workflowCount(lane, 'ready')} ready workflow(s)`,
|
|
107
112
|
`${workflowCount(lane, 'attention')} attention workflow(s)`,
|
|
108
|
-
`${freshProviderReads} fresh provider read route(s)`,
|
|
113
|
+
`${freshProviderReads} fresh provider read/record route(s)`,
|
|
109
114
|
`${refreshableSavedRecords} refreshable saved review record(s)`,
|
|
110
115
|
`${savedReviewRecords} saved review record(s)`,
|
|
111
116
|
];
|
|
@@ -215,7 +220,7 @@ export async function personalOpsBriefingSummary(context: CommandContext, args:
|
|
|
215
220
|
workflows: workflows.length,
|
|
216
221
|
readyWorkflows: workflows.filter((workflow) => workflow.status === 'ready').length,
|
|
217
222
|
attentionWorkflows: workflows.filter((workflow) => workflow.status === 'attention').length,
|
|
218
|
-
freshProviderReads: liveRecords.filter(
|
|
223
|
+
freshProviderReads: liveRecords.filter(isFreshProviderRecord).length,
|
|
219
224
|
refreshableSavedRecords: liveRecords.filter((record) => record.freshness?.status === 'saved-review-refreshable').length,
|
|
220
225
|
savedReviewRecords: liveRecords.filter((record) => record.freshness?.source === 'saved-review-artifact' || typeof record.reviewRecordCount === 'number').length,
|
|
221
226
|
connectorSignals: lanes.reduce((sum, lane) => sum + (lane.connectorSignals?.length ?? 0), 0),
|
|
@@ -258,7 +263,7 @@ export async function personalOpsSummary(context: CommandContext, args: AgentHar
|
|
|
258
263
|
attention: workflows.filter((workflow) => workflow.status === 'attention').length,
|
|
259
264
|
needsSetup: workflows.filter((workflow) => workflow.status === 'needs-setup').length,
|
|
260
265
|
},
|
|
261
|
-
policy: 'Personal Ops unifies inbox, agenda, notes, tasks, reminders, routines, and delivery. Lanes include live records when Agent owns them and schema-derived connector operation records when MCP schemas are available. Missing email/calendar connectors, messages, and events are reported as setup/data gaps, not faked.',
|
|
266
|
+
policy: 'Personal Ops unifies inbox, agenda, notes, tasks, reminders, routines, and delivery. Lanes include live records when Agent owns them, daemon/SDK provider read-model queue records when published, and schema-derived connector operation records when MCP schemas are available. Missing email/calendar connectors, messages, and events are reported as setup/data gaps, not faked.',
|
|
262
267
|
nextActions: nextActions(lanes),
|
|
263
268
|
};
|
|
264
269
|
}
|
|
@@ -268,6 +273,7 @@ function queueRecordType(record: PersonalOpsLiveRecord): string {
|
|
|
268
273
|
if (record.capability === 'calendar-event-review') return 'saved-calendar-event';
|
|
269
274
|
if (record.capability === 'inbox-review-artifact') return 'saved-inbox-review';
|
|
270
275
|
if (record.capability === 'calendar-review-artifact') return 'saved-calendar-review';
|
|
276
|
+
if (record.freshness?.status === 'fresh-provider-record-current') return 'fresh-provider-record';
|
|
271
277
|
if (record.freshness?.status === 'fresh-provider-route-ready') return 'fresh-provider-read';
|
|
272
278
|
if (record.freshness?.status === 'connector-attention') return 'provider-read-attention';
|
|
273
279
|
return record.capability ?? 'personal-ops-record';
|
|
@@ -276,7 +282,7 @@ function queueRecordType(record: PersonalOpsLiveRecord): string {
|
|
|
276
282
|
function queueStatusRank(record: PersonalOpsLiveRecord): number {
|
|
277
283
|
if (record.freshness?.status === 'saved-review-refreshable') return 100;
|
|
278
284
|
if (record.capability === 'inbox-thread-review' || record.capability === 'calendar-event-review') return 90;
|
|
279
|
-
if (record.freshness?.status === 'fresh-provider-route-ready') return 80;
|
|
285
|
+
if (record.freshness?.status === 'fresh-provider-route-ready' || record.freshness?.status === 'fresh-provider-record-current') return 80;
|
|
280
286
|
if (record.capability === 'inbox-review-artifact' || record.capability === 'calendar-review-artifact') return 70;
|
|
281
287
|
if (record.freshness?.status === 'connector-attention') return 50;
|
|
282
288
|
if (record.freshness?.status === 'provider-contract-missing') return 35;
|
|
@@ -286,7 +292,7 @@ function queueStatusRank(record: PersonalOpsLiveRecord): number {
|
|
|
286
292
|
|
|
287
293
|
function isPersonalOpsQueueRecord(record: PersonalOpsLiveRecord): boolean {
|
|
288
294
|
if (record.freshness?.source === 'saved-review-artifact') return true;
|
|
289
|
-
if (record
|
|
295
|
+
if (isFreshProviderRecord(record) || record.freshness?.status === 'connector-attention') return true;
|
|
290
296
|
return record.capability ? QUEUE_CAPABILITIES.has(record.capability) : false;
|
|
291
297
|
}
|
|
292
298
|
|
|
@@ -323,6 +329,7 @@ function describeQueueItem(lane: PersonalOpsLane, record: PersonalOpsLiveRecord,
|
|
|
323
329
|
...(record.artifactId ? { artifact: `agent_artifacts show artifactId:"${record.artifactId}" includeContent:true` } : {}),
|
|
324
330
|
},
|
|
325
331
|
followUpRoutes,
|
|
332
|
+
...(includeParameters && record.certification ? { certification: record.certification } : {}),
|
|
326
333
|
...(includeParameters && record.tags && record.tags.length > 0 ? { tags: record.tags } : {}),
|
|
327
334
|
...(includeParameters && record.requiredFields ? { requiredFields: record.requiredFields } : {}),
|
|
328
335
|
...(includeParameters && record.sampleInput ? { sampleInput: record.sampleInput } : {}),
|
|
@@ -359,7 +366,7 @@ export async function personalOpsQueueSummary(context: CommandContext, args: Age
|
|
|
359
366
|
const items = allItems.slice(0, limit).map((item) => describeQueueItem(item.lane, item.record, includeParameters));
|
|
360
367
|
const readRecords = allItems.filter((item) => item.record.effect === 'read-only');
|
|
361
368
|
const confirmedFollowUps = allItems.reduce((total, item) => total + (item.record.followUpRoutes ?? []).filter((route) => route.requiresConfirmation).length, 0);
|
|
362
|
-
const freshProviderReads = allItems.filter((item) => item.record
|
|
369
|
+
const freshProviderReads = allItems.filter((item) => isFreshProviderRecord(item.record)).length;
|
|
363
370
|
const refreshableSavedRecords = allItems.filter((item) => item.record.freshness?.status === 'saved-review-refreshable').length;
|
|
364
371
|
const savedReviewRecords = allItems.filter((item) => item.record.freshness?.source === 'saved-review-artifact' || typeof item.record.reviewRecordCount === 'number').length;
|
|
365
372
|
const attentionRecords = allItems.filter((item) => item.record.freshness?.status === 'connector-attention' || item.lane.status === 'gap' || item.lane.status === 'needs-setup').length;
|
|
@@ -389,14 +396,14 @@ export async function personalOpsQueueSummary(context: CommandContext, args: Age
|
|
|
389
396
|
nextActions: allItems.length > 0
|
|
390
397
|
? [
|
|
391
398
|
refreshableSavedRecords > 0 ? 'Refresh one saved queue item only through its returned confirmed read route when the user asks for current provider state.' : '',
|
|
392
|
-
freshProviderReads > 0 ? '
|
|
399
|
+
freshProviderReads > 0 ? 'Inspect one current provider-backed queue record at a time; run a refresh route only when the record publishes one and the user asks.' : '',
|
|
393
400
|
'Use saved redacted queue artifacts for recap or local drafts before any external send, label, archive, edit, RSVP, or delete.',
|
|
394
401
|
].filter(Boolean).slice(0, includeParameters ? 5 : 3)
|
|
395
402
|
: [
|
|
396
403
|
'Run personal_ops action:"intake" for the user request to find a safe connector route.',
|
|
397
404
|
'Set up an inbox or calendar connector before promising fresh queue state.',
|
|
398
405
|
],
|
|
399
|
-
policy: 'Personal Ops queue is read-only. It aggregates existing saved review artifacts
|
|
406
|
+
policy: 'Personal Ops queue is read-only. It aggregates existing saved review artifacts, connector read-route records, and daemon/SDK provider read-model records; it does not execute MCP tools, read live provider data beyond already-published read models, send messages, edit calendar events, create reminders, or mutate artifacts.',
|
|
400
407
|
};
|
|
401
408
|
}
|
|
402
409
|
|