@ai-sdk/harness 1.0.0-canary.5 → 1.0.0-canary.7
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 +23 -0
- package/dist/agent/index.d.ts +68 -30
- package/dist/agent/index.js +254 -101
- package/dist/agent/index.js.map +1 -1
- package/dist/index.d.ts +37 -23
- package/package.json +3 -3
- package/src/agent/harness-agent-session.ts +224 -83
- package/src/agent/harness-agent.ts +56 -17
- package/src/agent/internal/lifecycle-state-validation.ts +45 -11
- package/src/agent/internal/run-prompt.ts +2 -0
- package/src/v1/harness-v1-lifecycle-state.ts +13 -7
- package/src/v1/harness-v1-session.ts +7 -9
- package/src/v1/harness-v1-skill.ts +22 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @ai-sdk/harness
|
|
2
2
|
|
|
3
|
+
## 1.0.0-canary.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3d87086: fix(harness): guard against invalid resuming a session vs continuing a turn
|
|
8
|
+
- 1ea15a3: fix(harness): fix various bugs with harness skills not being correctly processed by the harness adapters
|
|
9
|
+
- Updated dependencies [aeda373]
|
|
10
|
+
- Updated dependencies [25a64f8]
|
|
11
|
+
- Updated dependencies [375fdd7]
|
|
12
|
+
- Updated dependencies [f18b08f]
|
|
13
|
+
- Updated dependencies [b4507d5]
|
|
14
|
+
- @ai-sdk/provider-utils@5.0.0-canary.48
|
|
15
|
+
- ai@7.0.0-canary.172
|
|
16
|
+
|
|
17
|
+
## 1.0.0-canary.6
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [89ad56f]
|
|
22
|
+
- Updated dependencies [f9a496f]
|
|
23
|
+
- Updated dependencies [3295831]
|
|
24
|
+
- ai@7.0.0-canary.171
|
|
25
|
+
|
|
3
26
|
## 1.0.0-canary.5
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -381,12 +381,6 @@ type HarnessV1LifecycleStateBase = {
|
|
|
381
381
|
* responsible for any necessary encoding.
|
|
382
382
|
*/
|
|
383
383
|
readonly data: JSONValue;
|
|
384
|
-
/**
|
|
385
|
-
* Framework-owned pending approval records. These are intentionally outside
|
|
386
|
-
* adapter-defined `data` so callers can persist the entire lifecycle payload
|
|
387
|
-
* without the harness framework owning storage.
|
|
388
|
-
*/
|
|
389
|
-
readonly pendingToolApprovals?: readonly HarnessV1PendingToolApproval[];
|
|
390
384
|
};
|
|
391
385
|
/**
|
|
392
386
|
* Opaque payload returned by between-turn session lifecycle methods and
|
|
@@ -395,6 +389,11 @@ type HarnessV1LifecycleStateBase = {
|
|
|
395
389
|
*/
|
|
396
390
|
type HarnessV1ResumeSessionState = HarnessV1LifecycleStateBase & {
|
|
397
391
|
readonly type: 'resume-session';
|
|
392
|
+
/**
|
|
393
|
+
* Optional unfinished-turn state. When present, the session must be resumed
|
|
394
|
+
* before the turn is continued.
|
|
395
|
+
*/
|
|
396
|
+
readonly continueFrom?: HarnessV1ContinueTurnState;
|
|
398
397
|
};
|
|
399
398
|
/**
|
|
400
399
|
* Opaque payload returned by `doSuspendTurn` and accepted by a future
|
|
@@ -403,28 +402,45 @@ type HarnessV1ResumeSessionState = HarnessV1LifecycleStateBase & {
|
|
|
403
402
|
*/
|
|
404
403
|
type HarnessV1ContinueTurnState = HarnessV1LifecycleStateBase & {
|
|
405
404
|
readonly type: 'continue-turn';
|
|
405
|
+
/**
|
|
406
|
+
* Framework-owned pending approval records. These are intentionally outside
|
|
407
|
+
* adapter-defined `data` so callers can persist the entire lifecycle payload
|
|
408
|
+
* without the harness framework owning storage.
|
|
409
|
+
*/
|
|
410
|
+
readonly pendingToolApprovals?: readonly HarnessV1PendingToolApproval[];
|
|
406
411
|
};
|
|
407
412
|
type HarnessV1LifecycleState = HarnessV1ResumeSessionState | HarnessV1ContinueTurnState;
|
|
408
413
|
|
|
409
414
|
/**
|
|
410
415
|
* A self-contained instruction bundle the underlying runtime can load into
|
|
411
|
-
* its context. Adapters decide how to surface skills to the runtime
|
|
412
|
-
* `claude` CLI auto-discovers skills materialised as Markdown files in
|
|
413
|
-
* `.claude/skills`, while the `codex` CLI has no skill mechanism and the
|
|
414
|
-
* adapter inlines them into every user message.
|
|
416
|
+
* its context. Adapters decide how to surface skills to the runtime.
|
|
415
417
|
*/
|
|
416
418
|
type HarnessV1Skill = {
|
|
417
419
|
/** Stable identifier for the skill (kebab-case slug). */
|
|
418
420
|
readonly name: string;
|
|
419
421
|
/**
|
|
420
|
-
* Short, model-facing description.
|
|
421
|
-
*
|
|
422
|
-
* skill is relevant; for runtimes that load every skill on every turn
|
|
423
|
-
* (Codex), it appears alongside the content.
|
|
422
|
+
* Short, model-facing description. This is what the runtime sees to
|
|
423
|
+
* decide whether the skill is relevant.
|
|
424
424
|
*/
|
|
425
425
|
readonly description: string;
|
|
426
426
|
/** Full skill content the model loads when the skill is active. */
|
|
427
427
|
readonly content: string;
|
|
428
|
+
/**
|
|
429
|
+
* Additional files that belong to this skill. Adapters with native skill
|
|
430
|
+
* directories materialize these next to `SKILL.md`; adapters without native
|
|
431
|
+
* skill files include them with the skill content.
|
|
432
|
+
*/
|
|
433
|
+
readonly files?: ReadonlyArray<HarnessV1SkillFile>;
|
|
434
|
+
};
|
|
435
|
+
type HarnessV1SkillFile = {
|
|
436
|
+
/**
|
|
437
|
+
* Skill-relative POSIX path, for example `reference.md` or
|
|
438
|
+
* `references/codes.md`. Absolute paths and `..` segments are rejected by
|
|
439
|
+
* adapters before writing.
|
|
440
|
+
*/
|
|
441
|
+
readonly path: string;
|
|
442
|
+
/** UTF-8 text content for the file. */
|
|
443
|
+
readonly content: string;
|
|
428
444
|
};
|
|
429
445
|
|
|
430
446
|
/**
|
|
@@ -585,21 +601,19 @@ type HarnessV1StartOptions = {
|
|
|
585
601
|
readonly sessionId: string;
|
|
586
602
|
/**
|
|
587
603
|
* Skills made available to the underlying runtime for the lifetime of
|
|
588
|
-
* the session. Adapters decide how to surface them
|
|
589
|
-
* picks them up from `.claude/skills/*.md`, while the `codex` adapter
|
|
590
|
-
* inlines them into every user message.
|
|
604
|
+
* the session. Adapters decide how to surface them.
|
|
591
605
|
*/
|
|
592
606
|
readonly skills?: ReadonlyArray<HarnessV1Skill>;
|
|
593
607
|
/**
|
|
594
|
-
* Optional resume payload returned by a prior
|
|
595
|
-
*
|
|
596
|
-
*
|
|
608
|
+
* Optional resume payload returned by a prior session lifecycle method. When
|
|
609
|
+
* provided, the adapter should resume the existing session before accepting a
|
|
610
|
+
* new prompt or continuing a nested unfinished turn.
|
|
597
611
|
*/
|
|
598
612
|
readonly resumeFrom?: HarnessV1ResumeSessionState;
|
|
599
613
|
/**
|
|
600
|
-
* Optional continuation payload returned by `doSuspendTurn
|
|
601
|
-
* the adapter should resume the existing session
|
|
602
|
-
* `doContinueTurn` rather than for a fresh prompt.
|
|
614
|
+
* Optional continuation payload returned by `doSuspendTurn`, or nested in
|
|
615
|
+
* `resumeFrom`. When provided, the adapter should resume the existing session
|
|
616
|
+
* in a shape ready for `doContinueTurn` rather than for a fresh prompt.
|
|
603
617
|
*/
|
|
604
618
|
readonly continueFrom?: HarnessV1ContinueTurnState;
|
|
605
619
|
/**
|
|
@@ -1151,6 +1165,7 @@ type HarnessAgentTurnResult<TOOLS extends ToolSet, RUNTIME_CONTEXT extends Conte
|
|
|
1151
1165
|
result: StreamTextResult<TOOLS, RUNTIME_CONTEXT, never>;
|
|
1152
1166
|
done: Promise<void>;
|
|
1153
1167
|
};
|
|
1168
|
+
type HarnessAgentTurnState = 'idle' | 'running' | 'awaiting-approval' | 'suspended';
|
|
1154
1169
|
/**
|
|
1155
1170
|
* Live harness session held by the caller.
|
|
1156
1171
|
*
|
|
@@ -1180,7 +1195,10 @@ declare class HarnessAgentSession {
|
|
|
1180
1195
|
private leasedBridgePort;
|
|
1181
1196
|
private readonly toolApproval;
|
|
1182
1197
|
private readonly pendingToolApprovals;
|
|
1183
|
-
private
|
|
1198
|
+
private sessionState;
|
|
1199
|
+
private turnState;
|
|
1200
|
+
private turnSequence;
|
|
1201
|
+
private activeTurnSequence;
|
|
1184
1202
|
/**
|
|
1185
1203
|
* Whether this session was created from `resumeFrom` or `continueFrom`.
|
|
1186
1204
|
* Captured at construction so it survives lifecycle cleanup.
|
|
@@ -1196,6 +1214,7 @@ declare class HarnessAgentSession {
|
|
|
1196
1214
|
sessionWorkDir: string;
|
|
1197
1215
|
toolApproval: HarnessAgentToolApprovalConfiguration | undefined;
|
|
1198
1216
|
pendingToolApprovals?: readonly HarnessAgentPendingToolApproval[];
|
|
1217
|
+
turnState?: HarnessAgentTurnState;
|
|
1199
1218
|
});
|
|
1200
1219
|
promptTurn<TOOLS extends ToolSet, RUNTIME_CONTEXT extends Context>(options: {
|
|
1201
1220
|
prompt: HarnessAgentPrompt;
|
|
@@ -1247,11 +1266,11 @@ declare class HarnessAgentSession {
|
|
|
1247
1266
|
/**
|
|
1248
1267
|
* Gracefully freeze the active turn at the slice boundary and return the
|
|
1249
1268
|
* continuation payload, **leaving the sandbox/runtime running** so the next
|
|
1250
|
-
* process can continue. Resolves once the in-flight `stream()
|
|
1251
|
-
* has cleanly wound down at a precise cursor (see
|
|
1269
|
+
* process can continue. Resolves once the in-flight `stream()` /
|
|
1270
|
+
* `continueStream()` has cleanly wound down at a precise cursor (see
|
|
1252
1271
|
* `doSuspendTurn`).
|
|
1253
1272
|
*
|
|
1254
|
-
* After this call the session is
|
|
1273
|
+
* After this call the session is detached. This in-process handle no
|
|
1255
1274
|
* longer drives turns; a future slice creates a fresh session from the
|
|
1256
1275
|
* returned state. The sandbox is **not** stopped and no port lease is
|
|
1257
1276
|
* released, because bridge-backed adapters may still have a live bridge on
|
|
@@ -1259,7 +1278,15 @@ declare class HarnessAgentSession {
|
|
|
1259
1278
|
*/
|
|
1260
1279
|
suspendTurn(): Promise<HarnessAgentContinueTurnState>;
|
|
1261
1280
|
private getPendingToolApprovals;
|
|
1262
|
-
private
|
|
1281
|
+
private addPendingToolApprovals;
|
|
1282
|
+
private suspendCurrentTurn;
|
|
1283
|
+
private toResumeStateWithContinuation;
|
|
1284
|
+
private requirePromptableTurn;
|
|
1285
|
+
private requireContinuableTurn;
|
|
1286
|
+
private markAwaitingApprovalIfActive;
|
|
1287
|
+
private startTrackedTurn;
|
|
1288
|
+
private trackTurnCompletion;
|
|
1289
|
+
private finishTrackedTurn;
|
|
1263
1290
|
private endLocalHandle;
|
|
1264
1291
|
private releasePortLease;
|
|
1265
1292
|
private requireReusableSession;
|
|
@@ -1304,7 +1331,8 @@ interface HarnessAgentCallExtensions {
|
|
|
1304
1331
|
* `session.stop()`. The framework validates `resumeFrom` against the
|
|
1305
1332
|
* harness's `lifecycleStateSchema` before handing it to the adapter.
|
|
1306
1333
|
* `createSession({ sessionId, continueFrom })` resumes from state returned
|
|
1307
|
-
* by `session.suspendTurn()` before `
|
|
1334
|
+
* by `session.suspendTurn()` before `continueStream()` /
|
|
1335
|
+
* `continueGenerate()`.
|
|
1308
1336
|
* - **Host tool execution.** User tools passed in `settings.tools` are
|
|
1309
1337
|
* executed on the host whenever the underlying runtime calls them;
|
|
1310
1338
|
* the result is fed back to the harness via `submitToolResult`.
|
|
@@ -1365,6 +1393,16 @@ declare class HarnessAgent<THarness extends HarnessAgentAdapter<any> = HarnessAg
|
|
|
1365
1393
|
}): Promise<HarnessAgentSession>;
|
|
1366
1394
|
generate(options: AgentCallParameters<never, HarnessAllTools<THarness, TUserTools>, RUNTIME_CONTEXT> & HarnessAgentCallExtensions): Promise<GenerateTextResult<HarnessAllTools<THarness, TUserTools>, RUNTIME_CONTEXT, never>>;
|
|
1367
1395
|
stream(options: AgentStreamParameters<never, HarnessAllTools<THarness, TUserTools>, RUNTIME_CONTEXT> & HarnessAgentCallExtensions): Promise<StreamTextResult<HarnessAllTools<THarness, TUserTools>, RUNTIME_CONTEXT, never>>;
|
|
1396
|
+
/**
|
|
1397
|
+
* Continue the in-flight turn **without a new prompt**, draining it like
|
|
1398
|
+
* {@link generate}. Used after `createSession({ continueFrom })` to finish
|
|
1399
|
+
* consuming a turn that crossed a process boundary.
|
|
1400
|
+
*/
|
|
1401
|
+
continueGenerate(options: {
|
|
1402
|
+
session: HarnessAgentSession;
|
|
1403
|
+
toolApprovalContinuations?: readonly HarnessAgentToolApprovalContinuation[];
|
|
1404
|
+
abortSignal?: AbortSignal;
|
|
1405
|
+
}): Promise<GenerateTextResult<HarnessAllTools<THarness, TUserTools>, RUNTIME_CONTEXT, never>>;
|
|
1368
1406
|
/**
|
|
1369
1407
|
* Continue the in-flight turn **without a new prompt**, streaming its events
|
|
1370
1408
|
* like {@link stream}. Used to keep consuming a turn that is still running
|
|
@@ -1373,7 +1411,7 @@ declare class HarnessAgent<THarness extends HarnessAgentAdapter<any> = HarnessAg
|
|
|
1373
1411
|
* `doContinueTurn`; what it can guarantee (lossless attach vs. lossy rerun)
|
|
1374
1412
|
* follows from how the adapter resumed the session.
|
|
1375
1413
|
*/
|
|
1376
|
-
|
|
1414
|
+
continueStream(options: {
|
|
1377
1415
|
session: HarnessAgentSession;
|
|
1378
1416
|
toolApprovalContinuations?: readonly HarnessAgentToolApprovalContinuation[];
|
|
1379
1417
|
abortSignal?: AbortSignal;
|