@pellux/goodvibes-agent 1.2.0 → 1.3.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/CHANGELOG.md +159 -0
- package/dist/package/main.js +19016 -12684
- 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 +17 -5
- 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 +245 -9
- package/src/input/agent-workspace-categories.ts +2 -2
- package/src/input/agent-workspace-onboarding-categories.ts +4 -4
- package/src/input/agent-workspace-settings.ts +52 -1
- package/src/input/agent-workspace-setup-snapshot.ts +20 -1
- package/src/input/agent-workspace-setup.ts +32 -5
- package/src/input/agent-workspace-snapshot.ts +23 -3
- package/src/input/agent-workspace.ts +5 -1
- package/src/input/setup-wizard-live-receipts.ts +76 -0
- package/src/renderer/agent-workspace-context-lines.ts +21 -6
- package/src/renderer/agent-workspace.ts +46 -10
- 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-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
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
3
|
+
import { readRecord, readString } from './agent-harness-model-routing-utils.ts';
|
|
4
|
+
|
|
5
|
+
export type AgentHarnessInteractiveRuntimeKind = 'process-output' | 'pty-session' | 'sudo-mediation' | 'browser-desktop-receipt';
|
|
6
|
+
export type AgentHarnessInteractiveRuntimeStatus = 'ready' | 'running' | 'completed' | 'blocked' | 'failed' | 'attention' | 'unknown';
|
|
7
|
+
|
|
8
|
+
export interface AgentHarnessInteractiveRuntimeCertification {
|
|
9
|
+
readonly schemaStatus: 'certified' | 'legacy';
|
|
10
|
+
readonly schemaVersion?: string;
|
|
11
|
+
readonly publicationGuarantee?: string;
|
|
12
|
+
readonly publisher?: string;
|
|
13
|
+
readonly provenance?: readonly string[];
|
|
14
|
+
readonly receiptId?: string;
|
|
15
|
+
readonly receiptRoute?: string;
|
|
16
|
+
readonly missingSignals: readonly string[];
|
|
17
|
+
readonly policy: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AgentHarnessInteractiveRuntimeRoute {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly modelRoute: string;
|
|
24
|
+
readonly effect: 'read-only' | 'confirmed' | 'confirmed-admin';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface AgentHarnessInteractiveRuntimeRecord {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly kind: AgentHarnessInteractiveRuntimeKind;
|
|
30
|
+
readonly status: AgentHarnessInteractiveRuntimeStatus;
|
|
31
|
+
readonly source: string;
|
|
32
|
+
readonly label: string;
|
|
33
|
+
readonly summary: string;
|
|
34
|
+
readonly processId?: string;
|
|
35
|
+
readonly sessionId?: string;
|
|
36
|
+
readonly pid?: number;
|
|
37
|
+
readonly command?: string;
|
|
38
|
+
readonly surface?: string;
|
|
39
|
+
readonly action?: string;
|
|
40
|
+
readonly receiptId?: string;
|
|
41
|
+
readonly outputChunks?: readonly Record<string, unknown>[];
|
|
42
|
+
readonly routes: readonly AgentHarnessInteractiveRuntimeRoute[];
|
|
43
|
+
readonly updatedAt?: string;
|
|
44
|
+
readonly certification: AgentHarnessInteractiveRuntimeCertification;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const SECRET_PATTERNS: readonly [RegExp, string][] = [
|
|
48
|
+
[/secret:\/\/[^\s,'"}]+/gi, 'secret://<redacted>'],
|
|
49
|
+
[/("?\b(?:api[-_]?key|apikey|token|secret|password|passwd|credential|authorization)\b"?\s*:\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1"<redacted>"'],
|
|
50
|
+
[/\b([A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTHORIZATION|BEARER)[A-Z0-9_]*)=("[^"]*"|'[^']*'|[^\s]+)/gi, '$1=<redacted>'],
|
|
51
|
+
[/(\b(?:token|secret|password|passwd|api[-_]?key|apikey|authorization|credential)\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s,}]+)/gi, '$1<redacted>'],
|
|
52
|
+
[/(Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, '$1<redacted>'],
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
function redactedPreview(value: unknown, limit = 180): string {
|
|
56
|
+
const raw = readString(value);
|
|
57
|
+
const redacted = SECRET_PATTERNS.reduce((text, [pattern, replacement]) => text.replace(pattern, replacement), raw);
|
|
58
|
+
return previewHarnessText(redacted, limit);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function readBoolean(value: unknown): boolean | null {
|
|
62
|
+
if (typeof value === 'boolean') return value;
|
|
63
|
+
const raw = readString(value).toLowerCase();
|
|
64
|
+
if (['true', 'yes', '1', 'ready', 'available', 'published', 'certified'].includes(raw)) return true;
|
|
65
|
+
if (['false', 'no', '0', 'blocked', 'missing', 'unavailable'].includes(raw)) return false;
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function readNumber(value: unknown): number | undefined {
|
|
70
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
71
|
+
return typeof parsed === 'number' && Number.isFinite(parsed) ? Math.trunc(parsed) : undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function readTimestamp(value: unknown): string | undefined {
|
|
75
|
+
const raw = readString(value);
|
|
76
|
+
const parsed = raw ? Date.parse(raw) : typeof value === 'number' && Number.isFinite(value) ? value : NaN;
|
|
77
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function stringArray(value: unknown): readonly string[] {
|
|
81
|
+
if (Array.isArray(value)) return [...new Set(value.map((entry) => readString(entry)).filter(Boolean))].slice(0, 10);
|
|
82
|
+
const raw = readString(value);
|
|
83
|
+
return raw ? raw.split(',').map((entry) => entry.trim()).filter(Boolean).slice(0, 10) : [];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function firstString(records: readonly Readonly<Record<string, unknown>>[], keys: readonly string[]): string {
|
|
87
|
+
for (const record of records) {
|
|
88
|
+
for (const key of keys) {
|
|
89
|
+
const value = readString(record[key]);
|
|
90
|
+
if (value) return value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function certificationRecords(record: Readonly<Record<string, unknown>>): readonly Readonly<Record<string, unknown>>[] {
|
|
97
|
+
return [
|
|
98
|
+
record,
|
|
99
|
+
readRecord(record.schema),
|
|
100
|
+
readRecord(record.contract),
|
|
101
|
+
readRecord(record.publication),
|
|
102
|
+
readRecord(record.receipt),
|
|
103
|
+
readRecord(record.certification),
|
|
104
|
+
];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function schemaStatus(records: readonly Readonly<Record<string, unknown>>[]): AgentHarnessInteractiveRuntimeCertification['schemaStatus'] {
|
|
108
|
+
const explicit = firstString(records, ['schemaStatus', 'receiptSchemaStatus', 'certificationStatus']).toLowerCase().replace(/[_\s]+/g, '-');
|
|
109
|
+
if (['certified', 'valid', 'verified', 'schema-certified'].includes(explicit)) return 'certified';
|
|
110
|
+
return firstString(records, ['schemaVersion', 'receiptSchemaVersion', 'contractVersion'])
|
|
111
|
+
&& firstString(records, ['publicationGuarantee', 'hostPublicationGuarantee', 'runtimePublicationGuarantee'])
|
|
112
|
+
&& firstString(records, ['publisher', 'publisherId', 'daemonId', 'hostId', 'methodId', 'sourceTool'])
|
|
113
|
+
? 'certified'
|
|
114
|
+
: 'legacy';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function routeValue(value: unknown): string {
|
|
118
|
+
const direct = readString(value);
|
|
119
|
+
if (direct) return direct;
|
|
120
|
+
const record = readRecord(value);
|
|
121
|
+
return readString(record.modelRoute) || readString(record.route) || readString(record.command) || readString(record.action) || readString(record.href) || readString(record.url);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function routeFrom(record: Readonly<Record<string, unknown>>, aliases: readonly string[]): string {
|
|
125
|
+
const containers = [record, readRecord(record.routes), readRecord(record.modelRoutes), readRecord(record.actions), readRecord(record.commands), readRecord(record.links)];
|
|
126
|
+
for (const alias of aliases) {
|
|
127
|
+
for (const container of containers) {
|
|
128
|
+
const route = routeValue(container[alias]) || routeValue(container[`${alias}Route`]) || routeValue(container[`${alias}Command`]) || routeValue(container[`${alias}Action`]);
|
|
129
|
+
if (route) return route;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function runtimeKind(record: Readonly<Record<string, unknown>>, fallback: AgentHarnessInteractiveRuntimeKind): AgentHarnessInteractiveRuntimeKind {
|
|
136
|
+
const raw = `${readString(record.kind) || readString(record.recordKind) || readString(record.type) || readString(record.capability)}`.toLowerCase();
|
|
137
|
+
if (/pty|terminal-session|interactive-session/.test(raw)) return 'pty-session';
|
|
138
|
+
if (/sudo|credential|privilege/.test(raw)) return 'sudo-mediation';
|
|
139
|
+
if (/browser|desktop|screenshot|screen|computer|control|receipt/.test(raw)) return 'browser-desktop-receipt';
|
|
140
|
+
if (/process|output|chunk|terminal/.test(raw)) return 'process-output';
|
|
141
|
+
return fallback;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function normalizeStatus(value: unknown): AgentHarnessInteractiveRuntimeStatus {
|
|
145
|
+
const raw = readString(value).toLowerCase().replace(/_/g, '-');
|
|
146
|
+
if (['ready', 'available', 'published', 'certified', 'ok', 'healthy'].includes(raw)) return 'ready';
|
|
147
|
+
if (['running', 'active', 'in-progress'].includes(raw)) return 'running';
|
|
148
|
+
if (['completed', 'complete', 'succeeded', 'success', 'done'].includes(raw)) return 'completed';
|
|
149
|
+
if (['blocked', 'denied', 'permission-denied'].includes(raw)) return 'blocked';
|
|
150
|
+
if (['failed', 'failure', 'error', 'errored'].includes(raw)) return 'failed';
|
|
151
|
+
if (['attention', 'review', 'stale'].includes(raw)) return 'attention';
|
|
152
|
+
return raw ? 'unknown' : 'unknown';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function readId(record: Readonly<Record<string, unknown>>, kind: AgentHarnessInteractiveRuntimeKind): string {
|
|
156
|
+
return readString(record.id)
|
|
157
|
+
|| readString(record.recordId)
|
|
158
|
+
|| readString(record.processId)
|
|
159
|
+
|| readString(record.sessionId)
|
|
160
|
+
|| readString(record.receiptId)
|
|
161
|
+
|| readString(record.contractId)
|
|
162
|
+
|| `${kind}:${readString(record.sourceId) || readString(record.action) || 'published'}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function routesFor(kind: AgentHarnessInteractiveRuntimeKind, record: Readonly<Record<string, unknown>>): readonly AgentHarnessInteractiveRuntimeRoute[] {
|
|
166
|
+
const routeSpecs: readonly [string, string, readonly string[], AgentHarnessInteractiveRuntimeRoute['effect']][] = [
|
|
167
|
+
['inspect', 'Inspect record', ['inspect', 'status', 'show'], 'read-only'],
|
|
168
|
+
['log', 'Read output', ['log', 'output', 'chunks', 'tail'], 'read-only'],
|
|
169
|
+
['write', 'Write input', ['write', 'stdin', 'input', 'sendInput'], 'confirmed'],
|
|
170
|
+
['resize', 'Resize session', ['resize'], 'confirmed'],
|
|
171
|
+
['close', 'Close session', ['close', 'stop', 'kill', 'cancel'], 'confirmed'],
|
|
172
|
+
['credential', 'Mediated credential prompt', ['credential', 'sudo', 'privilege', 'prompt'], 'confirmed-admin'],
|
|
173
|
+
['execute', kind === 'browser-desktop-receipt' ? 'Execute trusted control' : 'Execute route', ['execute', 'command', 'control', 'run'], 'confirmed'],
|
|
174
|
+
['receipt', 'Inspect receipt', ['receipt', 'receipts', 'history'], 'read-only'],
|
|
175
|
+
];
|
|
176
|
+
return routeSpecs
|
|
177
|
+
.map(([id, label, aliases, effect]) => {
|
|
178
|
+
const modelRoute = routeFrom(record, aliases);
|
|
179
|
+
return modelRoute ? { id, label, modelRoute: redactedPreview(modelRoute, 220), effect } : null;
|
|
180
|
+
})
|
|
181
|
+
.filter((route): route is AgentHarnessInteractiveRuntimeRoute => route !== null);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function outputChunks(record: Readonly<Record<string, unknown>>): readonly Record<string, unknown>[] {
|
|
185
|
+
const output = readRecord(record.output);
|
|
186
|
+
const rawChunks = Array.isArray(record.outputChunks) ? record.outputChunks
|
|
187
|
+
: Array.isArray(record.chunks) ? record.chunks
|
|
188
|
+
: Array.isArray(output.chunks) ? output.chunks
|
|
189
|
+
: [];
|
|
190
|
+
const chunks = rawChunks.flatMap((entry, index): Record<string, unknown>[] => {
|
|
191
|
+
const chunk = readRecord(entry);
|
|
192
|
+
const text = redactedPreview(chunk.text ?? chunk.preview ?? chunk.data ?? chunk.content, 600);
|
|
193
|
+
return text ? [{
|
|
194
|
+
chunkId: readString(chunk.chunkId) || readString(chunk.id) || `${index + 1}`,
|
|
195
|
+
stream: readString(chunk.stream) || readString(chunk.channel) || 'stdout',
|
|
196
|
+
text,
|
|
197
|
+
chars: readNumber(chunk.chars) ?? text.length,
|
|
198
|
+
bytes: readNumber(chunk.bytes) ?? Buffer.byteLength(text),
|
|
199
|
+
truncated: readBoolean(chunk.truncated) ?? false,
|
|
200
|
+
createdAt: readTimestamp(chunk.createdAt ?? chunk.timestamp),
|
|
201
|
+
}] : [];
|
|
202
|
+
});
|
|
203
|
+
if (chunks.length > 0) return chunks.slice(0, 5);
|
|
204
|
+
return ['stdoutTail', 'stderrTail', 'stdout', 'stderr'].flatMap((key) => {
|
|
205
|
+
const text = redactedPreview(record[key] ?? output[key], 600);
|
|
206
|
+
return text ? [{ chunkId: key, stream: key.includes('stderr') ? 'stderr' : 'stdout', text, chars: text.length, bytes: Buffer.byteLength(text), truncated: false }] : [];
|
|
207
|
+
}).slice(0, 5);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function certification(input: {
|
|
211
|
+
readonly record: Readonly<Record<string, unknown>>;
|
|
212
|
+
readonly source: string;
|
|
213
|
+
readonly kind: AgentHarnessInteractiveRuntimeKind;
|
|
214
|
+
readonly id: string;
|
|
215
|
+
readonly routes: readonly AgentHarnessInteractiveRuntimeRoute[];
|
|
216
|
+
readonly chunks: readonly Record<string, unknown>[];
|
|
217
|
+
}): AgentHarnessInteractiveRuntimeCertification {
|
|
218
|
+
const records = certificationRecords(input.record);
|
|
219
|
+
const status = schemaStatus(records);
|
|
220
|
+
const publicationGuarantee = firstString(records, ['publicationGuarantee', 'hostPublicationGuarantee', 'runtimePublicationGuarantee']);
|
|
221
|
+
const publisher = firstString(records, ['publisher', 'publisherId', 'daemonId', 'hostId']);
|
|
222
|
+
const provenance = [...new Set([
|
|
223
|
+
...stringArray(input.record.provenance),
|
|
224
|
+
input.source ? `source ${input.source}` : '',
|
|
225
|
+
firstString(records, ['methodId']) ? `method ${firstString(records, ['methodId'])}` : '',
|
|
226
|
+
firstString(records, ['sourceTool']) ? `sourceTool ${firstString(records, ['sourceTool'])}` : '',
|
|
227
|
+
].map((entry) => redactedPreview(entry, 180)).filter(Boolean))].slice(0, 8);
|
|
228
|
+
const receiptId = firstString(records, ['receiptId', 'operationReceiptId', 'commandReceiptId', 'sessionReceiptId']);
|
|
229
|
+
const hasRoute = (id: string) => input.routes.some((route) => route.id === id);
|
|
230
|
+
const rawSecretReturned = readBoolean(input.record.rawSecretReturned) === true || readBoolean(input.record.rawValueReturned) === true;
|
|
231
|
+
const missingSignals = [
|
|
232
|
+
...(status === 'certified' ? [] : [`Certified ${input.kind} schema is not published.`]),
|
|
233
|
+
...(input.id ? [] : [`Durable ${input.kind} id is not published.`]),
|
|
234
|
+
...(publicationGuarantee ? [] : [`${input.kind} publication guarantee is not published.`]),
|
|
235
|
+
...(publisher ? [] : [`${input.kind} publisher is not published.`]),
|
|
236
|
+
...(provenance.length > 0 ? [] : [`${input.kind} provenance is not published.`]),
|
|
237
|
+
...(input.kind === 'process-output' && input.chunks.length === 0 && !hasRoute('log') ? ['Live process output chunks or log route are not published.'] : []),
|
|
238
|
+
...(input.kind === 'pty-session' && (!hasRoute('write') || (!hasRoute('log') && input.chunks.length === 0)) ? ['PTY input and output routes are not both published.'] : []),
|
|
239
|
+
...(input.kind === 'sudo-mediation' && (!hasRoute('credential') || rawSecretReturned) ? ['Sudo credential mediation route is missing or raw secret exposure was reported.'] : []),
|
|
240
|
+
...(input.kind === 'browser-desktop-receipt' && (!receiptId || !hasRoute('execute') || !hasRoute('receipt')) ? ['Browser/desktop command receipt, execute route, or receipt route is not published.'] : []),
|
|
241
|
+
];
|
|
242
|
+
return {
|
|
243
|
+
schemaStatus: status,
|
|
244
|
+
...(firstString(records, ['schemaVersion', 'receiptSchemaVersion', 'contractVersion']) ? { schemaVersion: redactedPreview(firstString(records, ['schemaVersion', 'receiptSchemaVersion', 'contractVersion']), 80) } : {}),
|
|
245
|
+
...(publicationGuarantee ? { publicationGuarantee: redactedPreview(publicationGuarantee, 220) } : {}),
|
|
246
|
+
...(publisher ? { publisher: redactedPreview(publisher, 80) } : {}),
|
|
247
|
+
...(provenance.length > 0 ? { provenance } : {}),
|
|
248
|
+
...(receiptId ? { receiptId: redactedPreview(receiptId, 96) } : {}),
|
|
249
|
+
...(hasRoute('receipt') ? { receiptRoute: input.routes.find((route) => route.id === 'receipt')?.modelRoute } : {}),
|
|
250
|
+
missingSignals,
|
|
251
|
+
policy: 'Interactive runtime records certify release readiness only when the SDK or daemon publishes schema, durable id, publication guarantee, publisher/provenance, bounded output or receipt evidence, exact confirmed control routes, and no raw secret material.',
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function normalizeRecord(value: unknown, source: string, fallbackKind: AgentHarnessInteractiveRuntimeKind): AgentHarnessInteractiveRuntimeRecord | null {
|
|
256
|
+
const record = readRecord(value);
|
|
257
|
+
if (Object.keys(record).length === 0) return null;
|
|
258
|
+
const kind = runtimeKind(record, fallbackKind);
|
|
259
|
+
const id = readId(record, kind);
|
|
260
|
+
if (!id) return null;
|
|
261
|
+
const routes = routesFor(kind, record);
|
|
262
|
+
const chunks = outputChunks(record);
|
|
263
|
+
const command = redactedPreview(record.command ?? record.cmd, 180);
|
|
264
|
+
const receiptId = readString(record.receiptId) || readString(record.operationReceiptId) || readString(record.commandReceiptId);
|
|
265
|
+
return {
|
|
266
|
+
id,
|
|
267
|
+
kind,
|
|
268
|
+
status: normalizeStatus(record.status ?? record.state ?? record.outcome),
|
|
269
|
+
source,
|
|
270
|
+
label: redactedPreview(record.label ?? record.title ?? id, 96),
|
|
271
|
+
summary: redactedPreview(record.summary ?? record.description ?? record.detail ?? command ?? id, 240),
|
|
272
|
+
...(readString(record.processId) ? { processId: readString(record.processId) } : {}),
|
|
273
|
+
...(readString(record.sessionId) ? { sessionId: readString(record.sessionId) } : {}),
|
|
274
|
+
...(readNumber(record.pid) !== undefined ? { pid: readNumber(record.pid) } : {}),
|
|
275
|
+
...(command ? { command } : {}),
|
|
276
|
+
...(readString(record.surface) ? { surface: redactedPreview(record.surface, 80) } : {}),
|
|
277
|
+
...(readString(record.action) ? { action: redactedPreview(record.action, 80) } : {}),
|
|
278
|
+
...(receiptId ? { receiptId: redactedPreview(receiptId, 96) } : {}),
|
|
279
|
+
...(chunks.length > 0 ? { outputChunks: chunks } : {}),
|
|
280
|
+
routes,
|
|
281
|
+
...(readTimestamp(record.updatedAt ?? record.createdAt ?? record.timestamp) ? { updatedAt: readTimestamp(record.updatedAt ?? record.createdAt ?? record.timestamp) } : {}),
|
|
282
|
+
certification: certification({ record, source, kind, id, routes, chunks }),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function readSnapshot(source: unknown): unknown {
|
|
287
|
+
if (typeof source === 'function') {
|
|
288
|
+
const value = (source as () => unknown)();
|
|
289
|
+
return value && typeof (value as Promise<unknown>).then === 'function' ? undefined : value;
|
|
290
|
+
}
|
|
291
|
+
const record = readRecord(source);
|
|
292
|
+
for (const methodName of ['getSnapshot', 'snapshot', 'list', 'records']) {
|
|
293
|
+
const method = record[methodName];
|
|
294
|
+
if (typeof method !== 'function') continue;
|
|
295
|
+
const value = (method as () => unknown)();
|
|
296
|
+
return value && typeof (value as Promise<unknown>).then === 'function' ? undefined : value;
|
|
297
|
+
}
|
|
298
|
+
return source;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function recordsFromSnapshot(snapshot: unknown, fallbackKind: AgentHarnessInteractiveRuntimeKind): readonly { readonly kind: AgentHarnessInteractiveRuntimeKind; readonly value: unknown }[] {
|
|
302
|
+
if (Array.isArray(snapshot)) return snapshot.map((value) => ({ kind: fallbackKind, value }));
|
|
303
|
+
const record = readRecord(snapshot);
|
|
304
|
+
const keyed: Array<readonly [string, AgentHarnessInteractiveRuntimeKind]> = [
|
|
305
|
+
['processes', 'process-output'],
|
|
306
|
+
['liveProcesses', 'process-output'],
|
|
307
|
+
['outputChunks', 'process-output'],
|
|
308
|
+
['ptySessions', 'pty-session'],
|
|
309
|
+
['sessions', 'pty-session'],
|
|
310
|
+
['sudoMediation', 'sudo-mediation'],
|
|
311
|
+
['credentials', 'sudo-mediation'],
|
|
312
|
+
['browserDesktopReceipts', 'browser-desktop-receipt'],
|
|
313
|
+
['controlReceipts', 'browser-desktop-receipt'],
|
|
314
|
+
['receipts', 'browser-desktop-receipt'],
|
|
315
|
+
['records', fallbackKind],
|
|
316
|
+
['items', fallbackKind],
|
|
317
|
+
];
|
|
318
|
+
const values: { kind: AgentHarnessInteractiveRuntimeKind; value: unknown }[] = [];
|
|
319
|
+
for (const [key, kind] of keyed) {
|
|
320
|
+
const candidate = record[key];
|
|
321
|
+
if (Array.isArray(candidate)) values.push(...candidate.map((value) => ({ kind, value })));
|
|
322
|
+
else {
|
|
323
|
+
const map = readRecord(candidate);
|
|
324
|
+
if (Object.keys(map).length > 0) values.push(...Object.entries(map).map(([id, value]) => ({ kind, value: { ...readRecord(value), id: readString(readRecord(value).id) || id } })));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return values.length > 0 ? values : Object.keys(record).length > 0 ? [{ kind: fallbackKind, value: record }] : [];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function runtimeSources(context: CommandContext): readonly { readonly path: string; readonly source: unknown; readonly kind: AgentHarnessInteractiveRuntimeKind }[] {
|
|
331
|
+
const platform = context.platform as unknown as Record<string, unknown>;
|
|
332
|
+
const clients = readRecord(context.clients);
|
|
333
|
+
const extensions = context.extensions as unknown as Record<string, unknown>;
|
|
334
|
+
const readModels = readRecord(platform.readModels);
|
|
335
|
+
const execution = readRecord(readModels.execution);
|
|
336
|
+
const computer = readRecord(readModels.computer);
|
|
337
|
+
const browser = readRecord(readModels.browser);
|
|
338
|
+
const operatorSdk = readRecord(clients.operatorSdk);
|
|
339
|
+
const daemonRuntime = readRecord(extensions.daemonRuntime);
|
|
340
|
+
return [
|
|
341
|
+
{ path: 'context.platform.readModels.execution.interactiveRuntime', source: execution.interactiveRuntime, kind: 'process-output' },
|
|
342
|
+
{ path: 'context.platform.readModels.execution.processRuntime', source: execution.processRuntime, kind: 'process-output' },
|
|
343
|
+
{ path: 'context.platform.readModels.execution.ptySessions', source: execution.ptySessions, kind: 'pty-session' },
|
|
344
|
+
{ path: 'context.platform.readModels.execution.sudoMediation', source: execution.sudoMediation, kind: 'sudo-mediation' },
|
|
345
|
+
{ path: 'context.platform.readModels.computer.browserDesktopReceipts', source: computer.browserDesktopReceipts, kind: 'browser-desktop-receipt' },
|
|
346
|
+
{ path: 'context.platform.readModels.browser.controlReceipts', source: browser.controlReceipts, kind: 'browser-desktop-receipt' },
|
|
347
|
+
{ path: 'context.clients.operatorSdk.execution.interactiveRuntime', source: readRecord(operatorSdk.execution).interactiveRuntime, kind: 'process-output' },
|
|
348
|
+
{ path: 'context.extensions.daemonRuntime.interactiveRuntime', source: daemonRuntime.interactiveRuntime, kind: 'process-output' },
|
|
349
|
+
];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function interactiveRuntimeRecords(context: CommandContext): readonly AgentHarnessInteractiveRuntimeRecord[] {
|
|
353
|
+
const records: AgentHarnessInteractiveRuntimeRecord[] = [];
|
|
354
|
+
for (const source of runtimeSources(context)) {
|
|
355
|
+
if (source.source === undefined || source.source === null) continue;
|
|
356
|
+
try {
|
|
357
|
+
const snapshot = readSnapshot(source.source);
|
|
358
|
+
records.push(...recordsFromSnapshot(snapshot, source.kind)
|
|
359
|
+
.map((entry) => normalizeRecord(entry.value, source.path, entry.kind))
|
|
360
|
+
.filter((entry): entry is AgentHarnessInteractiveRuntimeRecord => entry !== null));
|
|
361
|
+
} catch {
|
|
362
|
+
// Runtime read models are optional; a broken publisher should not hide local execution posture.
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return records.sort((left, right) => {
|
|
366
|
+
const delta = (right.updatedAt ? Date.parse(right.updatedAt) : 0) - (left.updatedAt ? Date.parse(left.updatedAt) : 0);
|
|
367
|
+
return delta || left.kind.localeCompare(right.kind) || left.id.localeCompare(right.id);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function complete(record: AgentHarnessInteractiveRuntimeRecord): boolean {
|
|
372
|
+
return record.certification.schemaStatus === 'certified' && record.certification.missingSignals.length === 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function kindSummary(records: readonly AgentHarnessInteractiveRuntimeRecord[], kind: AgentHarnessInteractiveRuntimeKind): Record<string, unknown> {
|
|
376
|
+
const matches = records.filter((record) => record.kind === kind);
|
|
377
|
+
const certified = matches.filter(complete);
|
|
378
|
+
return {
|
|
379
|
+
status: certified.length > 0 ? 'certified' : matches.length > 0 ? 'attention' : 'not-published',
|
|
380
|
+
recordCount: matches.length,
|
|
381
|
+
certifiedRecordCount: certified.length,
|
|
382
|
+
...(matches[0] ? { latest: matches[0] } : {}),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export function interactiveRuntimeCapabilitySummary(context: CommandContext): Record<string, unknown> {
|
|
387
|
+
const records = interactiveRuntimeRecords(context);
|
|
388
|
+
const certified = records.filter(complete);
|
|
389
|
+
return {
|
|
390
|
+
status: certified.length > 0 ? 'certified-live-runtime' : records.length > 0 ? 'attention' : 'not-published',
|
|
391
|
+
recordCount: records.length,
|
|
392
|
+
certifiedRecordCount: certified.length,
|
|
393
|
+
liveProcessOutput: kindSummary(records, 'process-output'),
|
|
394
|
+
ptySessions: kindSummary(records, 'pty-session'),
|
|
395
|
+
sudoMediation: kindSummary(records, 'sudo-mediation'),
|
|
396
|
+
browserDesktopControl: kindSummary(records, 'browser-desktop-receipt'),
|
|
397
|
+
latestRecords: records.slice(0, 6),
|
|
398
|
+
policy: 'Certified interactive runtime records are read-only evidence until the selected published route is invoked with its own confirmation boundary.',
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function interactiveRuntimeParityStatus(context: CommandContext): {
|
|
403
|
+
readonly stdinWriteContract: boolean;
|
|
404
|
+
readonly ptyContract: boolean;
|
|
405
|
+
readonly sudoMediationContract: boolean;
|
|
406
|
+
readonly browserDesktopControlContract: boolean;
|
|
407
|
+
readonly browserDesktopRoute: string | null;
|
|
408
|
+
readonly browserDesktopRecords: readonly AgentHarnessInteractiveRuntimeRecord[];
|
|
409
|
+
} {
|
|
410
|
+
const certified = interactiveRuntimeRecords(context).filter(complete);
|
|
411
|
+
const hasRoute = (record: AgentHarnessInteractiveRuntimeRecord, id: string) => record.routes.some((route) => route.id === id);
|
|
412
|
+
const browserDesktopRecords = certified.filter((record) => record.kind === 'browser-desktop-receipt');
|
|
413
|
+
return {
|
|
414
|
+
stdinWriteContract: certified.some((record) => (record.kind === 'process-output' || record.kind === 'pty-session') && hasRoute(record, 'write')),
|
|
415
|
+
ptyContract: certified.some((record) => record.kind === 'pty-session'),
|
|
416
|
+
sudoMediationContract: certified.some((record) => record.kind === 'sudo-mediation'),
|
|
417
|
+
browserDesktopControlContract: browserDesktopRecords.length > 0,
|
|
418
|
+
browserDesktopRoute: browserDesktopRecords[0]?.routes.find((route) => route.id === 'execute')?.modelRoute ?? browserDesktopRecords[0]?.routes.find((route) => route.id === 'inspect')?.modelRoute ?? null,
|
|
419
|
+
browserDesktopRecords,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { CommandContext } from '../input/command-registry.ts';
|
|
|
3
3
|
import { previewHarnessText } from './agent-harness-text.ts';
|
|
4
4
|
import { readArtifactStore } from './agent-harness-model-catalog.ts';
|
|
5
5
|
import { localStackFor } from './agent-harness-local-model-endpoints.ts';
|
|
6
|
-
import type { LocalModelBenchmarkEvidence, LocalModelBenchmarkPlan, LocalModelBenchmarkWinner, LocalModelRecipe } from './agent-harness-model-routing-types.ts';
|
|
6
|
+
import type { LocalModelBenchmarkEvidence, LocalModelBenchmarkPlan, LocalModelBenchmarkRouteLatency, LocalModelBenchmarkWinner, LocalModelRecipe } from './agent-harness-model-routing-types.ts';
|
|
7
7
|
import { readRecord, readString } from './agent-harness-model-routing-utils.ts';
|
|
8
8
|
|
|
9
9
|
export function isLocalModelBenchmarkArtifact(artifact: ArtifactDescriptor): boolean {
|
|
@@ -24,6 +24,7 @@ export function benchmarkCreatedAt(artifact: ArtifactDescriptor): string | null
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function describeLocalBenchmarkArtifact(artifact: ArtifactDescriptor): Record<string, unknown> {
|
|
27
|
+
const routeLatencies = localBenchmarkRouteLatenciesForArtifact(artifact);
|
|
27
28
|
return {
|
|
28
29
|
artifactId: artifact.id,
|
|
29
30
|
...(artifact.filename ? { filename: artifact.filename } : {}),
|
|
@@ -32,6 +33,14 @@ export function describeLocalBenchmarkArtifact(artifact: ArtifactDescriptor): Re
|
|
|
32
33
|
promptPreview: previewHarnessText(readString(artifact.metadata.promptPreview) || 'local model benchmark', 120),
|
|
33
34
|
candidateCount: artifact.metadata.candidateCount ?? null,
|
|
34
35
|
completedCandidates: artifact.metadata.completedCandidates ?? null,
|
|
36
|
+
...(routeLatencies.length > 0 ? {
|
|
37
|
+
routeLatencies: routeLatencies.map((entry) => ({
|
|
38
|
+
registryKey: entry.registryKey,
|
|
39
|
+
latencyMs: entry.latencyMs,
|
|
40
|
+
status: entry.status,
|
|
41
|
+
blindId: entry.blindId,
|
|
42
|
+
})),
|
|
43
|
+
} : {}),
|
|
35
44
|
benchmarkKind: readString(artifact.metadata.benchmarkKind) || 'local-model-route',
|
|
36
45
|
reviewRoute: `agent_model_compare review artifactId:"${artifact.id}"`,
|
|
37
46
|
revealRoute: `agent_model_compare reveal artifactId:"${artifact.id}"`,
|
|
@@ -61,6 +70,64 @@ export function describeLocalBenchmarkJudgment(artifact: ArtifactDescriptor): Re
|
|
|
61
70
|
};
|
|
62
71
|
}
|
|
63
72
|
|
|
73
|
+
function readLatencyMs(value: unknown): number | null {
|
|
74
|
+
const numberValue = typeof value === 'number' ? value : typeof value === 'string' && value.trim() ? Number(value) : Number.NaN;
|
|
75
|
+
return Number.isFinite(numberValue) && numberValue >= 0 ? Math.round(numberValue) : null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function localBenchmarkRouteLatenciesForArtifact(artifact: ArtifactDescriptor): readonly LocalModelBenchmarkRouteLatency[] {
|
|
79
|
+
const evidence = artifact.metadata.candidateLatencyEvidence;
|
|
80
|
+
if (!Array.isArray(evidence)) return [];
|
|
81
|
+
const comparisonId = readString(artifact.metadata.comparisonId) || null;
|
|
82
|
+
const createdAt = benchmarkCreatedAt(artifact);
|
|
83
|
+
return evidence.map((entry, index) => {
|
|
84
|
+
const record = readRecord(entry);
|
|
85
|
+
const registryKey = readString(record.registryKey);
|
|
86
|
+
const latencyMs = readLatencyMs(record.latencyMs);
|
|
87
|
+
if (!registryKey || latencyMs == null) return null;
|
|
88
|
+
const blindId = readString(record.blindId) || String.fromCharCode(65 + index);
|
|
89
|
+
return {
|
|
90
|
+
registryKey,
|
|
91
|
+
providerId: readString(record.providerId),
|
|
92
|
+
modelId: readString(record.modelId) || registryKey,
|
|
93
|
+
displayName: readString(record.displayName) || registryKey,
|
|
94
|
+
blindId,
|
|
95
|
+
latencyMs,
|
|
96
|
+
status: readString(record.status) || 'completed',
|
|
97
|
+
artifactId: artifact.id,
|
|
98
|
+
comparisonId,
|
|
99
|
+
createdAt,
|
|
100
|
+
reviewRoute: `agent_model_compare review artifactId:"${artifact.id}"`,
|
|
101
|
+
};
|
|
102
|
+
}).filter((entry): entry is LocalModelBenchmarkRouteLatency => entry !== null);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function localBenchmarkRouteLatencies(artifacts: readonly ArtifactDescriptor[]): readonly LocalModelBenchmarkRouteLatency[] {
|
|
106
|
+
const byRoute = new Map<string, LocalModelBenchmarkRouteLatency>();
|
|
107
|
+
for (const artifact of artifacts) {
|
|
108
|
+
for (const latency of localBenchmarkRouteLatenciesForArtifact(artifact)) {
|
|
109
|
+
const current = byRoute.get(latency.registryKey);
|
|
110
|
+
if (!current) {
|
|
111
|
+
byRoute.set(latency.registryKey, latency);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const currentTime = current.createdAt ? Date.parse(current.createdAt) : 0;
|
|
115
|
+
const candidateTime = latency.createdAt ? Date.parse(latency.createdAt) : 0;
|
|
116
|
+
if (candidateTime > currentTime || (candidateTime === currentTime && latency.latencyMs < current.latencyMs)) {
|
|
117
|
+
byRoute.set(latency.registryKey, latency);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return [...byRoute.values()].sort((left, right) => left.registryKey.localeCompare(right.registryKey));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function localBenchmarkRouteLatencyMap(context: CommandContext): ReadonlyMap<string, LocalModelBenchmarkRouteLatency> {
|
|
125
|
+
const store = readArtifactStore(context);
|
|
126
|
+
if (!store?.list) return new Map();
|
|
127
|
+
const artifacts = store.list(100).filter(isLocalModelBenchmarkArtifact);
|
|
128
|
+
return new Map(localBenchmarkRouteLatencies(artifacts).map((entry) => [entry.registryKey, entry]));
|
|
129
|
+
}
|
|
130
|
+
|
|
64
131
|
export function localBenchmarkEvidence(
|
|
65
132
|
comparisons: readonly ArtifactDescriptor[],
|
|
66
133
|
judgments: readonly ArtifactDescriptor[],
|
|
@@ -75,6 +142,7 @@ export function localBenchmarkEvidence(
|
|
|
75
142
|
hiddenJudgmentCount: 0,
|
|
76
143
|
winnerStacks: [],
|
|
77
144
|
winnerModels: [],
|
|
145
|
+
routeLatencies: [],
|
|
78
146
|
summary: 'Artifact history is unavailable in this runtime.',
|
|
79
147
|
confidence: 'estimated',
|
|
80
148
|
};
|
|
@@ -106,6 +174,7 @@ export function localBenchmarkEvidence(
|
|
|
106
174
|
const value = artifact.metadata.completedCandidates;
|
|
107
175
|
return total + (typeof value === 'number' && Number.isFinite(value) ? value : 0);
|
|
108
176
|
}, 0);
|
|
177
|
+
const routeLatencies = localBenchmarkRouteLatencies(comparisons);
|
|
109
178
|
const status: LocalModelBenchmarkEvidence['status'] = winnerModels.length > 0
|
|
110
179
|
? 'reviewed-winner'
|
|
111
180
|
: comparisons.length > 0
|
|
@@ -119,6 +188,7 @@ export function localBenchmarkEvidence(
|
|
|
119
188
|
hiddenJudgmentCount,
|
|
120
189
|
winnerStacks,
|
|
121
190
|
winnerModels,
|
|
191
|
+
routeLatencies,
|
|
122
192
|
summary: winnerModels.length > 0
|
|
123
193
|
? `Reviewed benchmark winner(s): ${winnerModels.map((winner) => winner.registryKey).join(', ')}.`
|
|
124
194
|
: comparisons.length > 0
|