nexus-agentd 0.3.0 → 0.3.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/LICENSE +22 -22
- package/dist/artifact-store.d.ts +6 -0
- package/dist/artifact-store.js +30 -0
- package/dist/run-store.d.ts +38 -0
- package/dist/run-store.js +76 -0
- package/dist/server.js +55 -1
- package/dist/session/admin-runs.js +1 -0
- package/dist/session.d.ts +7 -1
- package/dist/session.js +12 -0
- package/dist/types.d.ts +2 -0
- package/dist/webui/app/sources.js +11 -10
- package/dist/webui/icons.d.ts +1 -0
- package/dist/webui/icons.js +1 -0
- package/dist/webui/index.js +11 -11
- package/dist/webui/markup.js +1 -0
- package/dist/webui/styles.js +59 -14
- package/nexus-agentd.example.json +38 -38
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 lumia1998
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
22
|
-
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lumia1998
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/dist/artifact-store.d.ts
CHANGED
|
@@ -126,6 +126,12 @@ export declare class ArtifactStore {
|
|
|
126
126
|
readArtifact(runId: string, artifactId: string): Promise<ArtifactReadResult | undefined>;
|
|
127
127
|
/** Queue removal of one run's own directory. Active runs are protected. */
|
|
128
128
|
removeRun(runId: string): void;
|
|
129
|
+
/**
|
|
130
|
+
* Delete a single artifact: drop its payload file and record entry. The
|
|
131
|
+
* run record itself stays; its artifacts list shrinks via the views
|
|
132
|
+
* callback. Refused while the payload write is still in flight.
|
|
133
|
+
*/
|
|
134
|
+
removeArtifact(runId: string, artifactId: string): Promise<boolean>;
|
|
129
135
|
flush(): Promise<void>;
|
|
130
136
|
get queuedByteCount(): number;
|
|
131
137
|
get storedByteCount(): number;
|
package/dist/artifact-store.js
CHANGED
|
@@ -359,6 +359,36 @@ export class ArtifactStore {
|
|
|
359
359
|
this.pendingDeletes.add(runId);
|
|
360
360
|
this.scheduleDrain();
|
|
361
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Delete a single artifact: drop its payload file and record entry. The
|
|
364
|
+
* run record itself stays; its artifacts list shrinks via the views
|
|
365
|
+
* callback. Refused while the payload write is still in flight.
|
|
366
|
+
*/
|
|
367
|
+
async removeArtifact(runId, artifactId) {
|
|
368
|
+
this.assertInitialized();
|
|
369
|
+
const key = entryKey(runId, artifactId);
|
|
370
|
+
const entry = this.entries.get(key);
|
|
371
|
+
if (!entry)
|
|
372
|
+
return false;
|
|
373
|
+
if (this.inFlight.has(key))
|
|
374
|
+
return false;
|
|
375
|
+
const batch = this.pending.get(runId);
|
|
376
|
+
const queued = batch?.get(artifactId);
|
|
377
|
+
if (queued) {
|
|
378
|
+
this.queuedBytes -= queued.bytes.length;
|
|
379
|
+
batch.delete(artifactId);
|
|
380
|
+
if (!batch.size)
|
|
381
|
+
this.pending.delete(runId);
|
|
382
|
+
}
|
|
383
|
+
if (entry.filePath) {
|
|
384
|
+
await this.safeUnlink(entry.filePath);
|
|
385
|
+
this.totalBytes -= entry.bytes || 0;
|
|
386
|
+
}
|
|
387
|
+
this.entries.delete(key);
|
|
388
|
+
await this.writeManifest(runId);
|
|
389
|
+
this.emit(runId, this.viewsForRun(runId));
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
362
392
|
async flush() {
|
|
363
393
|
this.assertInitialized();
|
|
364
394
|
if (this.activeDrain)
|
package/dist/run-store.d.ts
CHANGED
|
@@ -35,6 +35,32 @@ export interface RunListQuery {
|
|
|
35
35
|
limit?: number;
|
|
36
36
|
offset?: number;
|
|
37
37
|
}
|
|
38
|
+
export interface RunArtifactQuery {
|
|
39
|
+
agentId?: string;
|
|
40
|
+
/** 'all' keeps every kind; otherwise one of artifactKind() values. */
|
|
41
|
+
kind?: string;
|
|
42
|
+
query?: string;
|
|
43
|
+
limit?: number;
|
|
44
|
+
offset?: number;
|
|
45
|
+
}
|
|
46
|
+
export interface RunArtifactRow {
|
|
47
|
+
id: string;
|
|
48
|
+
runId: string;
|
|
49
|
+
agentId: string;
|
|
50
|
+
agentName: string;
|
|
51
|
+
runState: AgentdSessionState;
|
|
52
|
+
runStartedAt: number;
|
|
53
|
+
name?: string;
|
|
54
|
+
filename?: string;
|
|
55
|
+
mediaType?: string;
|
|
56
|
+
size?: number;
|
|
57
|
+
kind: string;
|
|
58
|
+
downloadable: boolean;
|
|
59
|
+
storageStatus?: string;
|
|
60
|
+
createdAt?: number;
|
|
61
|
+
}
|
|
62
|
+
/** Coarse bucket used by the console filter and list grouping. */
|
|
63
|
+
export declare function artifactKind(mediaType: string | undefined): "image" | "audio" | "video" | "file";
|
|
38
64
|
export declare class RunStore {
|
|
39
65
|
readonly filePath: string;
|
|
40
66
|
private readonly runs;
|
|
@@ -60,6 +86,13 @@ export declare class RunStore {
|
|
|
60
86
|
recordArtifacts(runId: string, artifacts: AgentdArtifact[]): StoredArtifactView[] | undefined;
|
|
61
87
|
artifactViews(runId: string): StoredArtifactView[] | undefined;
|
|
62
88
|
readArtifact(runId: string, artifactId: string): Promise<ArtifactReadResult | undefined>;
|
|
89
|
+
/** Flat, newest-first artifact index across all retained runs. */
|
|
90
|
+
listArtifacts(query?: RunArtifactQuery): {
|
|
91
|
+
artifacts: RunArtifactRow[];
|
|
92
|
+
total: number;
|
|
93
|
+
};
|
|
94
|
+
/** Delete one artifact's payload and record entry; the run record stays. */
|
|
95
|
+
removeArtifact(runId: string, artifactId: string): Promise<boolean>;
|
|
63
96
|
getOwnerKeyId(runId: string): string | undefined;
|
|
64
97
|
metrics(): {
|
|
65
98
|
historyBytes: number;
|
|
@@ -78,6 +111,11 @@ export declare class RunStore {
|
|
|
78
111
|
artifactStoreStats: ArtifactStoreMetrics;
|
|
79
112
|
};
|
|
80
113
|
setRetryOfRunId(runId: string, retryOfRunId?: string): AgentdRunDetail | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* Remove a terminal run record and its stored artifacts. Active runs are
|
|
116
|
+
* refused so a live turn cannot lose its progress tracking.
|
|
117
|
+
*/
|
|
118
|
+
deleteRun(id: string): AgentdRunDetail | undefined;
|
|
81
119
|
get(id: string): AgentdRunDetail | undefined;
|
|
82
120
|
list(query?: RunListQuery): {
|
|
83
121
|
runs: AgentdRunView[];
|
package/dist/run-store.js
CHANGED
|
@@ -3,6 +3,17 @@ import { chmod, mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promi
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { ArtifactStore, artifactStorePathForRunStore } from './artifact-store.js';
|
|
5
5
|
export { ArtifactStore, artifactStorePathForRunStore } from './artifact-store.js';
|
|
6
|
+
/** Coarse bucket used by the console filter and list grouping. */
|
|
7
|
+
export function artifactKind(mediaType) {
|
|
8
|
+
const type = String(mediaType || '').toLowerCase();
|
|
9
|
+
if (type.startsWith('image/'))
|
|
10
|
+
return 'image';
|
|
11
|
+
if (type.startsWith('video/'))
|
|
12
|
+
return 'video';
|
|
13
|
+
if (type.startsWith('audio/'))
|
|
14
|
+
return 'audio';
|
|
15
|
+
return 'file';
|
|
16
|
+
}
|
|
6
17
|
const STATES = new Set([
|
|
7
18
|
'created',
|
|
8
19
|
'running',
|
|
@@ -187,6 +198,55 @@ export class RunStore {
|
|
|
187
198
|
return undefined;
|
|
188
199
|
return this.artifactStore.readArtifact(runId, artifactId);
|
|
189
200
|
}
|
|
201
|
+
/** Flat, newest-first artifact index across all retained runs. */
|
|
202
|
+
listArtifacts(query = {}) {
|
|
203
|
+
this.assertInitialized();
|
|
204
|
+
const needle = String(query.query || '').trim().toLowerCase();
|
|
205
|
+
const limit = Math.min(200, Math.max(1, Number(query.limit) || 50));
|
|
206
|
+
const offset = Math.max(0, Math.floor(Number(query.offset) || 0));
|
|
207
|
+
const rows = [];
|
|
208
|
+
for (const run of this.runs.values()) {
|
|
209
|
+
for (const view of run.artifacts || []) {
|
|
210
|
+
if (!view.id)
|
|
211
|
+
continue;
|
|
212
|
+
if (query.agentId && run.agentId !== query.agentId)
|
|
213
|
+
continue;
|
|
214
|
+
const kind = artifactKind(view.mediaType);
|
|
215
|
+
if (query.kind && query.kind !== 'all' && kind !== query.kind)
|
|
216
|
+
continue;
|
|
217
|
+
if (needle) {
|
|
218
|
+
const haystack = `${view.name || ''} ${view.filename || ''}`.toLowerCase();
|
|
219
|
+
if (!haystack.includes(needle))
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
rows.push({
|
|
223
|
+
id: view.id,
|
|
224
|
+
runId: run.id,
|
|
225
|
+
agentId: run.agentId,
|
|
226
|
+
agentName: run.agentName,
|
|
227
|
+
runState: run.state,
|
|
228
|
+
runStartedAt: run.startedAt,
|
|
229
|
+
name: view.name,
|
|
230
|
+
filename: view.filename,
|
|
231
|
+
mediaType: view.mediaType,
|
|
232
|
+
size: view.size,
|
|
233
|
+
kind,
|
|
234
|
+
downloadable: view.downloadable === true,
|
|
235
|
+
storageStatus: view.storageStatus,
|
|
236
|
+
createdAt: view.createdAt
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
rows.sort((left, right) => (right.createdAt || 0) - (left.createdAt || 0));
|
|
241
|
+
return { artifacts: rows.slice(offset, offset + limit), total: rows.length };
|
|
242
|
+
}
|
|
243
|
+
/** Delete one artifact's payload and record entry; the run record stays. */
|
|
244
|
+
async removeArtifact(runId, artifactId) {
|
|
245
|
+
this.assertInitialized();
|
|
246
|
+
if (!this.runs.has(runId))
|
|
247
|
+
return false;
|
|
248
|
+
return this.artifactStore.removeArtifact(runId, artifactId);
|
|
249
|
+
}
|
|
190
250
|
getOwnerKeyId(runId) {
|
|
191
251
|
this.assertInitialized();
|
|
192
252
|
return this.runs.get(runId)?.ownerKeyId;
|
|
@@ -211,6 +271,22 @@ export class RunStore {
|
|
|
211
271
|
setRetryOfRunId(runId, retryOfRunId) {
|
|
212
272
|
return this.update(runId, { retryOfRunId });
|
|
213
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Remove a terminal run record and its stored artifacts. Active runs are
|
|
276
|
+
* refused so a live turn cannot lose its progress tracking.
|
|
277
|
+
*/
|
|
278
|
+
deleteRun(id) {
|
|
279
|
+
this.assertInitialized();
|
|
280
|
+
const run = this.runs.get(id);
|
|
281
|
+
if (!run)
|
|
282
|
+
return undefined;
|
|
283
|
+
if (isActive(run.state))
|
|
284
|
+
return undefined;
|
|
285
|
+
this.runs.delete(id);
|
|
286
|
+
this.artifactStore.removeRun(id);
|
|
287
|
+
this.changed();
|
|
288
|
+
return publicDetail(run);
|
|
289
|
+
}
|
|
214
290
|
get(id) {
|
|
215
291
|
this.assertInitialized();
|
|
216
292
|
const run = this.runs.get(id);
|
package/dist/server.js
CHANGED
|
@@ -505,15 +505,68 @@ async function handleAdminRoute(context, url) {
|
|
|
505
505
|
await handleAdminRunAction(context, decodeURIComponent(runActionMatch[1]), runActionMatch[2]);
|
|
506
506
|
return;
|
|
507
507
|
}
|
|
508
|
+
if (url.pathname === '/v1/admin/artifacts' && request.method === 'GET') {
|
|
509
|
+
writeJson(response, 200, sessions.listArtifacts({
|
|
510
|
+
agentId: cleanQuery(url.searchParams.get('agentId')),
|
|
511
|
+
kind: cleanQuery(url.searchParams.get('kind')),
|
|
512
|
+
query: cleanQuery(url.searchParams.get('q')),
|
|
513
|
+
offset: boundedOffset(url.searchParams.get('offset')),
|
|
514
|
+
limit: boundedLimit(url.searchParams.get('limit'))
|
|
515
|
+
}));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
508
518
|
const adminArtifactMatch = url.pathname.match(/^\/v1\/admin\/runs\/([^/]+)\/artifacts\/([^/]+)$/);
|
|
509
519
|
if (adminArtifactMatch && request.method === 'GET') {
|
|
510
520
|
const run = sessions.getRun(decodeURIComponent(adminArtifactMatch[1]));
|
|
511
521
|
await writeRunArtifact(response, sessions, run, decodeURIComponent(adminArtifactMatch[2]));
|
|
512
522
|
return;
|
|
513
523
|
}
|
|
524
|
+
if (adminArtifactMatch && request.method === 'DELETE') {
|
|
525
|
+
await assertEmptyJsonBody(request, config.maxRequestBytes);
|
|
526
|
+
const runId = decodeURIComponent(adminArtifactMatch[1]);
|
|
527
|
+
const artifactId = decodeURIComponent(adminArtifactMatch[2]);
|
|
528
|
+
const run = sessions.getRun(runId);
|
|
529
|
+
if (!isTerminalState(run.state)) {
|
|
530
|
+
throw new RequestError(409, 'Artifacts of active runs cannot be deleted; cancel the task first');
|
|
531
|
+
}
|
|
532
|
+
const deleted = await sessions.removeRunArtifact(runId, artifactId);
|
|
533
|
+
if (!deleted)
|
|
534
|
+
throw new RequestError(404, 'Agent Nexus artifact not found');
|
|
535
|
+
console.info(JSON.stringify({
|
|
536
|
+
level: 'info',
|
|
537
|
+
event: 'admin_artifact_deleted',
|
|
538
|
+
runId,
|
|
539
|
+
artifactId,
|
|
540
|
+
agentId: run.agentId,
|
|
541
|
+
requestId: String(response.getHeader('X-Request-Id') || '')
|
|
542
|
+
}));
|
|
543
|
+
writeJson(response, 200, { deleted: true, runId, artifactId });
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
514
546
|
const runMatch = url.pathname.match(/^\/v1\/admin\/runs\/([^/]+)$/);
|
|
515
|
-
if (runMatch && request.method === 'GET') {
|
|
547
|
+
if (runMatch && (request.method === 'GET' || request.method === 'DELETE')) {
|
|
516
548
|
const runId = decodeURIComponent(runMatch[1]);
|
|
549
|
+
if (request.method === 'DELETE') {
|
|
550
|
+
await assertEmptyJsonBody(request, config.maxRequestBytes);
|
|
551
|
+
const detail = sessions.getRun(runId);
|
|
552
|
+
if (!isTerminalState(detail.state)) {
|
|
553
|
+
throw new RequestError(409, 'Active runs cannot be deleted; cancel the task first');
|
|
554
|
+
}
|
|
555
|
+
const deleted = sessions.deleteRun(runId);
|
|
556
|
+
if (!deleted)
|
|
557
|
+
throw new RequestError(404, 'Agent Nexus run not found');
|
|
558
|
+
console.info(JSON.stringify({
|
|
559
|
+
level: 'info',
|
|
560
|
+
event: 'admin_run_record_deleted',
|
|
561
|
+
runId,
|
|
562
|
+
sessionId: detail.sessionId,
|
|
563
|
+
agentId: detail.agentId,
|
|
564
|
+
state: detail.state,
|
|
565
|
+
requestId: String(response.getHeader('X-Request-Id') || '')
|
|
566
|
+
}));
|
|
567
|
+
writeJson(response, 200, { deleted: true, id: runId });
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
517
570
|
const detail = sessions.getRun(runId);
|
|
518
571
|
writeJson(response, 200, {
|
|
519
572
|
...detail,
|
|
@@ -778,6 +831,7 @@ function buildRunControls(sessions, detail) {
|
|
|
778
831
|
return {
|
|
779
832
|
canCancel,
|
|
780
833
|
canRetry,
|
|
834
|
+
canDelete: !active,
|
|
781
835
|
...(pendingRequest ? { pendingRequest: structuredClone(pendingRequest) } : {}),
|
|
782
836
|
...(unavailableReason ? { unavailableReason } : {})
|
|
783
837
|
};
|
|
@@ -73,6 +73,7 @@ export class AdminRunManager {
|
|
|
73
73
|
return {
|
|
74
74
|
canCancel: current && active && Boolean(session?.runtimeAvailable()),
|
|
75
75
|
canRetry,
|
|
76
|
+
canDelete: isTerminal(run.state),
|
|
76
77
|
...(pendingRequest ? { pendingRequest } : {}),
|
|
77
78
|
...(unavailableReason ? { unavailableReason } : {})
|
|
78
79
|
};
|
package/dist/session.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentDriver } from './drivers/index.js';
|
|
2
2
|
import { SessionEventLog } from './events.js';
|
|
3
|
-
import { RunStore, type RunListQuery } from './run-store.js';
|
|
3
|
+
import { RunStore, type RunListQuery, type RunArtifactQuery } from './run-store.js';
|
|
4
4
|
import { type AdminRetryReservationFactory, type AdminRunOperationResult, type AdminRunControls } from './session/admin-runs.js';
|
|
5
5
|
import type { AcpSessionSink, AgentSessionRuntime, AgentSessionSink } from './session-contract.js';
|
|
6
6
|
import type { AgentdAgentView, AgentdArtifact, AgentdConfig, AgentdEvent, AgentdEventType, AgentdInputAttachmentView, AgentdPendingRequest, AgentdPendingResponse, AgentdProtocol, AgentdSessionState, AgentdSessionView, AgentdTurnCompletionProof } from './types.js';
|
|
@@ -114,8 +114,14 @@ export declare class SessionManager {
|
|
|
114
114
|
};
|
|
115
115
|
getRun(id: string): import("./types.js").AgentdRunDetail;
|
|
116
116
|
getRunOwnerKeyId(id: string): string | undefined;
|
|
117
|
+
deleteRun(id: string): import("./types.js").AgentdRunDetail | undefined;
|
|
117
118
|
ownsRun(id: string, keyId: string): boolean;
|
|
118
119
|
getRunArtifacts(id: string): import("./types.js").AgentdRunArtifactView[];
|
|
120
|
+
listArtifacts(query?: RunArtifactQuery): {
|
|
121
|
+
artifacts: import("./run-store.js").RunArtifactRow[];
|
|
122
|
+
total: number;
|
|
123
|
+
};
|
|
124
|
+
removeRunArtifact(runId: string, artifactId: string): Promise<boolean | undefined>;
|
|
119
125
|
getStorageMetrics(): ReturnType<RunStore['metrics']> | undefined;
|
|
120
126
|
readRunArtifact(runId: string, artifactId: string): Promise<import("./artifact-store.js").ArtifactReadResult | undefined>;
|
|
121
127
|
getRunArtifact(runId: string, artifactId: string): Promise<import("./artifact-store.js").ArtifactReadResult | undefined>;
|
package/dist/session.js
CHANGED
|
@@ -654,12 +654,24 @@ export class SessionManager {
|
|
|
654
654
|
const store = this.runStore;
|
|
655
655
|
return store?.getOwnerKeyId?.(id);
|
|
656
656
|
}
|
|
657
|
+
deleteRun(id) {
|
|
658
|
+
const store = this.runStore;
|
|
659
|
+
return store?.deleteRun?.(id);
|
|
660
|
+
}
|
|
657
661
|
ownsRun(id, keyId) {
|
|
658
662
|
return this.getRunOwnerKeyId(id) === keyId;
|
|
659
663
|
}
|
|
660
664
|
getRunArtifacts(id) {
|
|
661
665
|
return this.getRun(id).artifacts;
|
|
662
666
|
}
|
|
667
|
+
listArtifacts(query = {}) {
|
|
668
|
+
const store = this.runStore;
|
|
669
|
+
return store?.listArtifacts?.(query) || { artifacts: [], total: 0 };
|
|
670
|
+
}
|
|
671
|
+
async removeRunArtifact(runId, artifactId) {
|
|
672
|
+
const store = this.runStore;
|
|
673
|
+
return store?.removeArtifact?.(runId, artifactId);
|
|
674
|
+
}
|
|
663
675
|
getStorageMetrics() {
|
|
664
676
|
return this.runStore?.metrics();
|
|
665
677
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -268,6 +268,7 @@ export interface AgentdRunArtifactView {
|
|
|
268
268
|
size?: number;
|
|
269
269
|
downloadable?: boolean;
|
|
270
270
|
storageStatus?: 'pending' | 'available' | 'metadata_only' | 'expired' | 'evicted' | 'failed';
|
|
271
|
+
createdAt?: number;
|
|
271
272
|
}
|
|
272
273
|
export interface AgentdRunView {
|
|
273
274
|
id: string;
|
|
@@ -301,6 +302,7 @@ export interface AgentdRunDetail extends AgentdRunView {
|
|
|
301
302
|
export interface AgentdRunControls {
|
|
302
303
|
canCancel: boolean;
|
|
303
304
|
canRetry: boolean;
|
|
305
|
+
canDelete?: boolean;
|
|
304
306
|
pendingRequest?: AgentdPendingRequest;
|
|
305
307
|
unavailableReason?: string;
|
|
306
308
|
}
|