@purista/harness 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.js +276 -141
- package/dist/errors/catalog.d.ts +4 -3
- package/dist/harness/defineHarness.d.ts +26 -2
- package/dist/harness/defineHarness.js +51 -2
- package/dist/index.d.ts +1 -1
- package/dist/memory/sandbox/index.js +7 -1
- package/dist/models/registry.js +45 -3
- package/dist/ports/base-model-provider.js +2 -0
- package/dist/ports/capabilities.d.ts +2 -0
- package/dist/ports/harness-context.d.ts +1 -0
- package/dist/ports/model-provider.d.ts +4 -0
- package/dist/ports/state.d.ts +6 -0
- package/dist/runtime/abort.d.ts +5 -0
- package/dist/runtime/abort.js +33 -0
- package/dist/runtime/durable.d.ts +2 -0
- package/dist/runtime/durable.js +6 -2
- package/dist/runtime/sessionDurable.d.ts +49 -0
- package/dist/runtime/sessionDurable.js +135 -0
- package/dist/runtime/steps.d.ts +19 -1
- package/dist/runtime/steps.js +21 -3
- package/dist/sandbox/index.d.ts +34 -0
- package/dist/sandbox/index.js +40 -3
- package/dist/sessions/index.d.ts +15 -2
- package/dist/sessions/index.js +212 -99
- package/dist/skills/index.js +19 -6
- package/dist/state/in-memory.d.ts +1 -0
- package/dist/state/in-memory.js +15 -0
- package/dist/telemetry/shim.js +9 -4
- package/dist/testing/durableWorkspaceStoreContract.d.ts +1 -1
- package/dist/testing/durableWorkspaceStoreContract.js +64 -28
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +15 -1
- package/dist/tools/mcp/runner.js +11 -6
- package/dist/tools/mcp/stdio.js +170 -1
- package/dist/ulid/index.d.ts +6 -1
- package/dist/ulid/index.js +31 -13
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/dist/workflows/index.js +7 -1
- package/dist/workspace/in-memory.d.ts +9 -10
- package/dist/workspace/in-memory.js +191 -48
- package/package.json +1 -1
- package/dist/harness/errors.d.ts +0 -62
- package/dist/harness/errors.js +0 -67
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { OperationCancelledError, WorkspaceError, WorkspaceQuotaExceededError } from '../errors/index.js';
|
|
2
|
+
const RETENTION = {
|
|
3
|
+
pausedTtlMs: 86_400_000,
|
|
4
|
+
terminalFailureTtlMs: 86_400_000,
|
|
5
|
+
terminalSuccessTtlMs: 0,
|
|
6
|
+
abortedTtlMs: 86_400_000,
|
|
7
|
+
cleanupMode: 'manual_only'
|
|
8
|
+
};
|
|
9
|
+
const QUOTA = { maxActiveWorkspaces: 100, maxWorkspaceBytes: 10_000_000, maxCheckpointPayloadBytes: 1_000_000 };
|
|
1
10
|
/** In-process durable workspace store for local development, examples, and tests. */
|
|
2
11
|
export class InMemoryDurableWorkspaceStore {
|
|
3
12
|
info = {
|
|
@@ -13,25 +22,44 @@ export class InMemoryDurableWorkspaceStore {
|
|
|
13
22
|
'workspace_store.retention',
|
|
14
23
|
'workspace_store.quota'
|
|
15
24
|
],
|
|
16
|
-
policy: {
|
|
17
|
-
retention: {
|
|
18
|
-
pausedTtlMs: 86_400_000,
|
|
19
|
-
terminalFailureTtlMs: 86_400_000,
|
|
20
|
-
terminalSuccessTtlMs: 0,
|
|
21
|
-
cleanupMode: 'manual_only'
|
|
22
|
-
},
|
|
23
|
-
quota: { maxActiveWorkspaces: 100, maxWorkspaceBytes: 10_000_000 }
|
|
24
|
-
}
|
|
25
|
+
policy: { retention: RETENTION, quota: { maxActiveWorkspaces: QUOTA.maxActiveWorkspaces, maxWorkspaceBytes: QUOTA.maxWorkspaceBytes } }
|
|
25
26
|
};
|
|
26
27
|
capabilities = this.info.capabilities;
|
|
27
28
|
workspaces = new Map();
|
|
29
|
+
startKeys = new Map();
|
|
30
|
+
opResults = new Map();
|
|
28
31
|
nextId = 1;
|
|
29
32
|
configureHarnessContext() { }
|
|
30
33
|
async startWorkspace(opts) {
|
|
31
|
-
opts.signal
|
|
34
|
+
throwIfAborted(opts.signal);
|
|
35
|
+
// Idempotent start: a repeated key replays the same workspace; a key reused
|
|
36
|
+
// with a different identity is a conflict.
|
|
37
|
+
const prior = this.startKeys.get(opts.idempotencyKey);
|
|
38
|
+
if (prior) {
|
|
39
|
+
if (prior.runId !== opts.runId || prior.sessionId !== opts.sessionId) {
|
|
40
|
+
throw new WorkspaceError('Workspace start idempotency key reused with a different run/session.', {
|
|
41
|
+
reason: 'idempotency_conflict',
|
|
42
|
+
workspace_ref: prior.workspaceRef,
|
|
43
|
+
run_id: opts.runId,
|
|
44
|
+
session_id: opts.sessionId
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const existing = this.workspaces.get(prior.workspaceRef);
|
|
48
|
+
if (existing)
|
|
49
|
+
return this.toHandle(existing);
|
|
50
|
+
}
|
|
51
|
+
const activeCount = [...this.workspaces.values()].filter((w) => w.state === 'active' || w.state === 'paused').length;
|
|
52
|
+
if (activeCount >= QUOTA.maxActiveWorkspaces) {
|
|
53
|
+
throw new WorkspaceQuotaExceededError('Active workspace quota exceeded.', {
|
|
54
|
+
quota: 'maxActiveWorkspaces',
|
|
55
|
+
limit: QUOTA.maxActiveWorkspaces,
|
|
56
|
+
actual: activeCount,
|
|
57
|
+
run_id: opts.runId,
|
|
58
|
+
session_id: opts.sessionId
|
|
59
|
+
});
|
|
60
|
+
}
|
|
32
61
|
const workspaceRef = `workspace_${this.nextId++}`;
|
|
33
62
|
const now = new Date().toISOString();
|
|
34
|
-
const metadata = { ...(opts.metadata ?? {}) };
|
|
35
63
|
const workspace = {
|
|
36
64
|
workspaceRef,
|
|
37
65
|
state: 'active',
|
|
@@ -40,17 +68,42 @@ export class InMemoryDurableWorkspaceStore {
|
|
|
40
68
|
attempt: opts.attempt,
|
|
41
69
|
createdAt: now,
|
|
42
70
|
updatedAt: now,
|
|
43
|
-
metadata,
|
|
44
|
-
checkpoints: []
|
|
71
|
+
metadata: { ...(opts.metadata ?? {}) },
|
|
72
|
+
checkpoints: [],
|
|
73
|
+
bytes: 0
|
|
45
74
|
};
|
|
46
75
|
this.workspaces.set(workspaceRef, workspace);
|
|
47
|
-
|
|
76
|
+
this.startKeys.set(opts.idempotencyKey, { workspaceRef, runId: opts.runId, sessionId: opts.sessionId });
|
|
77
|
+
return this.toHandle(workspace);
|
|
48
78
|
}
|
|
49
79
|
async pauseWorkspace(opts) {
|
|
50
|
-
opts.signal
|
|
51
|
-
const
|
|
80
|
+
throwIfAborted(opts.signal);
|
|
81
|
+
const replay = this.opResults.get(opts.idempotencyKey);
|
|
82
|
+
if (replay)
|
|
83
|
+
return replay;
|
|
84
|
+
const workspace = this.requireLiveWorkspace(opts.handle.workspaceRef);
|
|
85
|
+
const payloadBytes = opts.checkpointPayload === undefined ? 0 : byteLength(opts.checkpointPayload);
|
|
86
|
+
if (payloadBytes > QUOTA.maxCheckpointPayloadBytes) {
|
|
87
|
+
throw new WorkspaceQuotaExceededError('Checkpoint payload exceeds the size quota.', {
|
|
88
|
+
quota: 'maxCheckpointPayloadBytes',
|
|
89
|
+
limit: QUOTA.maxCheckpointPayloadBytes,
|
|
90
|
+
actual: payloadBytes,
|
|
91
|
+
workspace_ref: workspace.workspaceRef
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (workspace.bytes + payloadBytes > QUOTA.maxWorkspaceBytes) {
|
|
95
|
+
throw new WorkspaceQuotaExceededError('Workspace byte quota exceeded.', {
|
|
96
|
+
quota: 'maxWorkspaceBytes',
|
|
97
|
+
limit: QUOTA.maxWorkspaceBytes,
|
|
98
|
+
actual: workspace.bytes + payloadBytes,
|
|
99
|
+
workspace_ref: workspace.workspaceRef
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const committedAt = new Date().toISOString();
|
|
52
103
|
workspace.state = 'paused';
|
|
53
|
-
workspace.updatedAt =
|
|
104
|
+
workspace.updatedAt = committedAt;
|
|
105
|
+
workspace.bytes += payloadBytes;
|
|
106
|
+
const expiresAt = expiryFor('paused', committedAt);
|
|
54
107
|
const checkpoint = {
|
|
55
108
|
workspaceRef: workspace.workspaceRef,
|
|
56
109
|
checkpointRef: `${workspace.workspaceRef}:checkpoint:${opts.sequence}`,
|
|
@@ -59,61 +112,101 @@ export class InMemoryDurableWorkspaceStore {
|
|
|
59
112
|
stepId: opts.stepId,
|
|
60
113
|
sequence: opts.sequence,
|
|
61
114
|
attempt: opts.attempt,
|
|
62
|
-
committedAt
|
|
115
|
+
committedAt,
|
|
116
|
+
...(expiresAt ? { expiresAt } : {}),
|
|
117
|
+
sizeBytes: payloadBytes,
|
|
63
118
|
metadata: {
|
|
64
119
|
reason: opts.reason,
|
|
65
120
|
...(opts.checkpointPayload !== undefined ? { checkpointPayload: opts.checkpointPayload } : {})
|
|
66
121
|
}
|
|
67
122
|
};
|
|
68
123
|
workspace.checkpoints.push(checkpoint);
|
|
124
|
+
this.opResults.set(opts.idempotencyKey, checkpoint);
|
|
69
125
|
return checkpoint;
|
|
70
126
|
}
|
|
71
127
|
async resumeWorkspace(opts) {
|
|
72
|
-
opts.signal
|
|
73
|
-
const
|
|
128
|
+
throwIfAborted(opts.signal);
|
|
129
|
+
const replay = this.opResults.get(opts.idempotencyKey);
|
|
130
|
+
if (replay)
|
|
131
|
+
return replay;
|
|
132
|
+
const workspace = this.workspaces.get(opts.workspaceRef);
|
|
133
|
+
if (!workspace || workspace.state === 'cleaned') {
|
|
134
|
+
throw new WorkspaceError('Workspace not found.', { reason: 'not_found', workspace_ref: opts.workspaceRef });
|
|
135
|
+
}
|
|
136
|
+
if (workspace.state === 'aborted') {
|
|
137
|
+
throw new WorkspaceError('Workspace was aborted and cannot resume.', { reason: 'aborted', workspace_ref: opts.workspaceRef });
|
|
138
|
+
}
|
|
139
|
+
if (this.isExpired(workspace)) {
|
|
140
|
+
throw new WorkspaceError('Workspace has expired.', { reason: 'expired', workspace_ref: opts.workspaceRef });
|
|
141
|
+
}
|
|
74
142
|
if (opts.checkpointRef && !workspace.checkpoints.some((checkpoint) => checkpoint.checkpointRef === opts.checkpointRef)) {
|
|
75
|
-
throw new
|
|
143
|
+
throw new WorkspaceError('Workspace checkpoint not found.', { reason: 'missing_checkpoint', workspace_ref: opts.workspaceRef, checkpoint_ref: opts.checkpointRef });
|
|
76
144
|
}
|
|
77
145
|
workspace.state = 'active';
|
|
78
146
|
workspace.runId = opts.runId;
|
|
79
147
|
workspace.sessionId = opts.sessionId;
|
|
80
148
|
workspace.attempt = opts.attempt;
|
|
81
149
|
workspace.updatedAt = new Date().toISOString();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
sessionId: workspace.sessionId,
|
|
86
|
-
state: 'active',
|
|
87
|
-
startedAt: workspace.updatedAt,
|
|
88
|
-
attempt: workspace.attempt,
|
|
89
|
-
metadata: workspace.metadata
|
|
90
|
-
};
|
|
150
|
+
const handle = this.toHandle(workspace);
|
|
151
|
+
this.opResults.set(opts.idempotencyKey, handle);
|
|
152
|
+
return handle;
|
|
91
153
|
}
|
|
92
154
|
async abortWorkspace(opts) {
|
|
93
|
-
opts.signal
|
|
94
|
-
const
|
|
155
|
+
throwIfAborted(opts.signal);
|
|
156
|
+
const replay = this.opResults.get(opts.idempotencyKey);
|
|
157
|
+
if (replay)
|
|
158
|
+
return replay;
|
|
159
|
+
const workspace = this.workspaces.get(opts.workspaceRef);
|
|
160
|
+
if (!workspace || workspace.state === 'cleaned') {
|
|
161
|
+
throw new WorkspaceError('Workspace not found.', { reason: 'not_found', workspace_ref: opts.workspaceRef });
|
|
162
|
+
}
|
|
163
|
+
const abortedAt = new Date().toISOString();
|
|
95
164
|
workspace.state = 'aborted';
|
|
96
|
-
workspace.updatedAt =
|
|
97
|
-
|
|
165
|
+
workspace.updatedAt = abortedAt;
|
|
166
|
+
const cleanupEligibleAt = expiryFor('aborted', abortedAt);
|
|
167
|
+
const result = { workspaceRef: opts.workspaceRef, state: 'aborted', abortedAt, ...(cleanupEligibleAt ? { cleanupEligibleAt } : {}) };
|
|
168
|
+
this.opResults.set(opts.idempotencyKey, result);
|
|
169
|
+
return result;
|
|
98
170
|
}
|
|
99
171
|
async cleanupWorkspace(opts) {
|
|
100
|
-
opts.signal
|
|
101
|
-
const
|
|
172
|
+
throwIfAborted(opts.signal);
|
|
173
|
+
const replay = this.opResults.get(opts.idempotencyKey);
|
|
174
|
+
if (replay)
|
|
175
|
+
return replay;
|
|
176
|
+
const workspace = this.workspaces.get(opts.workspaceRef);
|
|
177
|
+
const completedAt = new Date().toISOString();
|
|
178
|
+
// Cleanup is idempotent: an already-cleaned (or unknown) workspace returns a
|
|
179
|
+
// terminal cleaned result rather than throwing.
|
|
180
|
+
if (!workspace || workspace.state === 'cleaned') {
|
|
181
|
+
const result = { workspaceRef: opts.workspaceRef, state: 'cleaned', completedAt, deletedBytes: 0, deletedFiles: 0 };
|
|
182
|
+
this.opResults.set(opts.idempotencyKey, result);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
const deletedBytes = workspace.bytes;
|
|
186
|
+
const deletedFiles = workspace.checkpoints.length;
|
|
102
187
|
workspace.state = 'cleaned';
|
|
103
|
-
workspace.updatedAt =
|
|
104
|
-
|
|
105
|
-
|
|
188
|
+
workspace.updatedAt = completedAt;
|
|
189
|
+
workspace.checkpoints = [];
|
|
190
|
+
workspace.bytes = 0;
|
|
191
|
+
const result = { workspaceRef: opts.workspaceRef, state: 'cleaned', completedAt, deletedBytes, deletedFiles };
|
|
192
|
+
this.opResults.set(opts.idempotencyKey, result);
|
|
193
|
+
return result;
|
|
106
194
|
}
|
|
107
195
|
async inspectWorkspace(opts) {
|
|
108
|
-
opts.signal
|
|
196
|
+
throwIfAborted(opts.signal);
|
|
109
197
|
const workspaceRef = opts.workspaceRef ?? this.findWorkspaceByCheckpoint(opts.checkpointRef);
|
|
110
|
-
const workspace = this.
|
|
198
|
+
const workspace = this.workspaces.get(workspaceRef);
|
|
199
|
+
if (!workspace) {
|
|
200
|
+
throw new WorkspaceError('Workspace not found.', { reason: 'not_found', workspace_ref: workspaceRef });
|
|
201
|
+
}
|
|
111
202
|
const latest = workspace.checkpoints.at(-1);
|
|
203
|
+
const expiresAt = expiryFor(workspace.state, workspace.updatedAt);
|
|
112
204
|
return {
|
|
113
205
|
workspaceRef: workspace.workspaceRef,
|
|
114
206
|
state: workspace.state,
|
|
115
207
|
checkpoints: workspace.checkpoints,
|
|
116
208
|
...(latest ? { currentCheckpointRef: latest.checkpointRef } : {}),
|
|
209
|
+
...(expiresAt ? { expiresAt, cleanupEligibleAt: expiresAt } : {}),
|
|
117
210
|
retention: this.info.policy.retention,
|
|
118
211
|
quota: this.info.policy.quota,
|
|
119
212
|
createdAt: workspace.createdAt,
|
|
@@ -121,21 +214,71 @@ export class InMemoryDurableWorkspaceStore {
|
|
|
121
214
|
metadata: workspace.metadata
|
|
122
215
|
};
|
|
123
216
|
}
|
|
217
|
+
toHandle(workspace) {
|
|
218
|
+
return {
|
|
219
|
+
workspaceRef: workspace.workspaceRef,
|
|
220
|
+
runId: workspace.runId,
|
|
221
|
+
sessionId: workspace.sessionId,
|
|
222
|
+
state: 'active',
|
|
223
|
+
startedAt: workspace.updatedAt,
|
|
224
|
+
attempt: workspace.attempt,
|
|
225
|
+
metadata: workspace.metadata
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
isExpired(workspace) {
|
|
229
|
+
const expiresAt = expiryFor(workspace.state, workspace.updatedAt);
|
|
230
|
+
return expiresAt !== undefined && Date.parse(expiresAt) <= Date.now();
|
|
231
|
+
}
|
|
124
232
|
findWorkspaceByCheckpoint(checkpointRef) {
|
|
125
|
-
if (!checkpointRef)
|
|
126
|
-
throw new
|
|
233
|
+
if (!checkpointRef) {
|
|
234
|
+
throw new WorkspaceError('workspaceRef or checkpointRef is required.', { reason: 'invalid_reference' });
|
|
235
|
+
}
|
|
127
236
|
const found = [...this.workspaces.values()].find((workspace) => workspace.checkpoints.some((checkpoint) => checkpoint.checkpointRef === checkpointRef));
|
|
128
|
-
if (!found)
|
|
129
|
-
throw new
|
|
237
|
+
if (!found) {
|
|
238
|
+
throw new WorkspaceError('Workspace checkpoint not found.', { reason: 'invalid_reference', checkpoint_ref: checkpointRef });
|
|
239
|
+
}
|
|
130
240
|
return found.workspaceRef;
|
|
131
241
|
}
|
|
132
|
-
|
|
242
|
+
requireLiveWorkspace(workspaceRef) {
|
|
133
243
|
const workspace = this.workspaces.get(workspaceRef);
|
|
134
|
-
if (!workspace)
|
|
135
|
-
throw new
|
|
244
|
+
if (!workspace || workspace.state === 'cleaned') {
|
|
245
|
+
throw new WorkspaceError('Workspace not found.', { reason: 'not_found', workspace_ref: workspaceRef });
|
|
246
|
+
}
|
|
247
|
+
if (workspace.state === 'aborted') {
|
|
248
|
+
throw new WorkspaceError('Workspace was aborted.', { reason: 'aborted', workspace_ref: workspaceRef });
|
|
249
|
+
}
|
|
136
250
|
return workspace;
|
|
137
251
|
}
|
|
138
252
|
}
|
|
253
|
+
function throwIfAborted(signal) {
|
|
254
|
+
if (signal?.aborted) {
|
|
255
|
+
throw new OperationCancelledError('Workspace operation was cancelled.', { scope: 'workspace' });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function ttlForState(state) {
|
|
259
|
+
switch (state) {
|
|
260
|
+
case 'paused':
|
|
261
|
+
return RETENTION.pausedTtlMs;
|
|
262
|
+
case 'aborted':
|
|
263
|
+
return RETENTION.abortedTtlMs ?? RETENTION.terminalFailureTtlMs;
|
|
264
|
+
default:
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function expiryFor(state, fromIso) {
|
|
269
|
+
const ttl = ttlForState(state);
|
|
270
|
+
if (ttl === undefined || ttl <= 0)
|
|
271
|
+
return undefined;
|
|
272
|
+
return new Date(Date.parse(fromIso) + ttl).toISOString();
|
|
273
|
+
}
|
|
274
|
+
function byteLength(value) {
|
|
275
|
+
try {
|
|
276
|
+
return Buffer.byteLength(JSON.stringify(value) ?? '', 'utf8');
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
139
282
|
/** Creates a fresh in-process durable workspace store. */
|
|
140
283
|
export function inMemoryDurableWorkspaceStore() {
|
|
141
284
|
return new InMemoryDurableWorkspaceStore();
|
package/package.json
CHANGED
package/dist/harness/errors.d.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { JsonValue } from './types.js';
|
|
2
|
-
export declare class HarnessError extends Error {
|
|
3
|
-
code: string;
|
|
4
|
-
category: string;
|
|
5
|
-
retriable: boolean;
|
|
6
|
-
meta?: Record<string, JsonValue>;
|
|
7
|
-
constructor(message: string, opts: {
|
|
8
|
-
code: string;
|
|
9
|
-
category: string;
|
|
10
|
-
retriable: boolean;
|
|
11
|
-
meta?: Record<string, JsonValue>;
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
export declare class HarnessConfigError extends HarnessError {
|
|
15
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
16
|
-
}
|
|
17
|
-
export declare class ValidationError extends HarnessError {
|
|
18
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
19
|
-
}
|
|
20
|
-
export declare class PermissionDeniedError extends HarnessError {
|
|
21
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
22
|
-
}
|
|
23
|
-
export declare class SandboxError extends HarnessError {
|
|
24
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
25
|
-
}
|
|
26
|
-
export declare class SandboxNoExecutorError extends HarnessError {
|
|
27
|
-
constructor();
|
|
28
|
-
}
|
|
29
|
-
export declare class ModelError extends HarnessError {
|
|
30
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
31
|
-
}
|
|
32
|
-
export declare class ToolError extends HarnessError {
|
|
33
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
34
|
-
}
|
|
35
|
-
export declare class ToolNotFoundError extends HarnessError {
|
|
36
|
-
constructor(tool: string);
|
|
37
|
-
}
|
|
38
|
-
export declare class SkillManifestError extends HarnessError {
|
|
39
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
40
|
-
}
|
|
41
|
-
export declare class AgentLoopBudgetError extends HarnessError {
|
|
42
|
-
constructor();
|
|
43
|
-
}
|
|
44
|
-
export declare class SessionBusyError extends HarnessError {
|
|
45
|
-
constructor(reason?: string);
|
|
46
|
-
}
|
|
47
|
-
export declare class OperationTimeoutError extends HarnessError {
|
|
48
|
-
constructor(scope: string);
|
|
49
|
-
}
|
|
50
|
-
export declare class OperationCancelledError extends HarnessError {
|
|
51
|
-
constructor(scope: string);
|
|
52
|
-
}
|
|
53
|
-
export declare class InternalError extends HarnessError {
|
|
54
|
-
constructor(message: string, meta?: Record<string, JsonValue>);
|
|
55
|
-
}
|
|
56
|
-
export declare function serializeError(error: unknown): {
|
|
57
|
-
code: string;
|
|
58
|
-
category: string;
|
|
59
|
-
retriable: boolean;
|
|
60
|
-
message: string;
|
|
61
|
-
meta?: Record<string, JsonValue>;
|
|
62
|
-
};
|
package/dist/harness/errors.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export class HarnessError extends Error {
|
|
2
|
-
code;
|
|
3
|
-
category;
|
|
4
|
-
retriable;
|
|
5
|
-
meta;
|
|
6
|
-
constructor(message, opts) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = new.target.name;
|
|
9
|
-
this.code = opts.code;
|
|
10
|
-
this.category = opts.category;
|
|
11
|
-
this.retriable = opts.retriable;
|
|
12
|
-
if (opts.meta !== undefined)
|
|
13
|
-
this.meta = opts.meta;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function errorOptions(opts, meta) {
|
|
17
|
-
return meta === undefined ? opts : { ...opts, meta };
|
|
18
|
-
}
|
|
19
|
-
export class HarnessConfigError extends HarnessError {
|
|
20
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'HARNESS_CONFIG_ERROR', category: 'config', retriable: false }, meta)); }
|
|
21
|
-
}
|
|
22
|
-
export class ValidationError extends HarnessError {
|
|
23
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'VALIDATION_ERROR', category: 'validation', retriable: false }, meta)); }
|
|
24
|
-
}
|
|
25
|
-
export class PermissionDeniedError extends HarnessError {
|
|
26
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'PERMISSION_DENIED', category: 'permission', retriable: false }, meta)); }
|
|
27
|
-
}
|
|
28
|
-
export class SandboxError extends HarnessError {
|
|
29
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'SANDBOX_ERROR', category: 'sandbox', retriable: false }, meta)); }
|
|
30
|
-
}
|
|
31
|
-
export class SandboxNoExecutorError extends HarnessError {
|
|
32
|
-
constructor() { super('Sandbox executor unavailable', { code: 'SANDBOX_NO_EXECUTOR', category: 'sandbox', retriable: false }); }
|
|
33
|
-
}
|
|
34
|
-
export class ModelError extends HarnessError {
|
|
35
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'MODEL_ERROR', category: 'model', retriable: true }, meta)); }
|
|
36
|
-
}
|
|
37
|
-
export class ToolError extends HarnessError {
|
|
38
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'TOOL_ERROR', category: 'tool', retriable: true }, meta)); }
|
|
39
|
-
}
|
|
40
|
-
export class ToolNotFoundError extends HarnessError {
|
|
41
|
-
constructor(tool) { super(`Tool not found: ${tool}`, { code: 'TOOL_NOT_FOUND', category: 'tool', retriable: false, meta: { tool } }); }
|
|
42
|
-
}
|
|
43
|
-
export class SkillManifestError extends HarnessError {
|
|
44
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'SKILL_MANIFEST_ERROR', category: 'config', retriable: false }, meta)); }
|
|
45
|
-
}
|
|
46
|
-
export class AgentLoopBudgetError extends HarnessError {
|
|
47
|
-
constructor() { super('Agent maxSteps exceeded', { code: 'AGENT_LOOP_BUDGET', category: 'agent', retriable: false, meta: { reason: 'iterations_exceeded' } }); }
|
|
48
|
-
}
|
|
49
|
-
export class SessionBusyError extends HarnessError {
|
|
50
|
-
constructor(reason = 'run_in_flight') { super('Session is busy', { code: 'SESSION_BUSY', category: 'session', retriable: true, meta: { reason } }); }
|
|
51
|
-
}
|
|
52
|
-
export class OperationTimeoutError extends HarnessError {
|
|
53
|
-
constructor(scope) { super('Operation timed out', { code: 'OPERATION_TIMEOUT', category: 'harness', retriable: true, meta: { scope } }); }
|
|
54
|
-
}
|
|
55
|
-
export class OperationCancelledError extends HarnessError {
|
|
56
|
-
constructor(scope) { super('Operation cancelled', { code: 'OPERATION_CANCELLED', category: 'harness', retriable: false, meta: { scope } }); }
|
|
57
|
-
}
|
|
58
|
-
export class InternalError extends HarnessError {
|
|
59
|
-
constructor(message, meta) { super(message, errorOptions({ code: 'INTERNAL_ERROR', category: 'internal', retriable: false }, meta)); }
|
|
60
|
-
}
|
|
61
|
-
export function serializeError(error) {
|
|
62
|
-
if (error instanceof HarnessError) {
|
|
63
|
-
const serialized = { code: error.code, category: error.category, retriable: error.retriable, message: error.message };
|
|
64
|
-
return error.meta === undefined ? serialized : { ...serialized, meta: error.meta };
|
|
65
|
-
}
|
|
66
|
-
return { code: 'INTERNAL_ERROR', category: 'internal', retriable: false, message: error instanceof Error ? error.message : String(error) };
|
|
67
|
-
}
|