@ai-sdk/harness-pi 1.0.94 → 1.0.96
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 +26 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +39 -25
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/pi-harness.ts +3 -2
- package/src/pi-session.ts +48 -30
- package/src/pi-skills.ts +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness-pi",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.96",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@ai-sdk/harness": "1.0.
|
|
30
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
29
|
+
"@ai-sdk/harness": "1.0.94",
|
|
30
|
+
"@ai-sdk/provider-utils": "5.0.34",
|
|
31
31
|
"@earendil-works/pi-ai": "0.74.2",
|
|
32
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
32
|
+
"@earendil-works/pi-coding-agent": "^0.84.3",
|
|
33
33
|
"pi-mcp-adapter": "2.12.1",
|
|
34
34
|
"typebox": "^1.1.38"
|
|
35
35
|
},
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"zod": "^3.25.76 || ^4.1.8"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@ai-sdk/sandbox-just-bash": "1.0.
|
|
40
|
+
"@ai-sdk/sandbox-just-bash": "1.0.94",
|
|
41
41
|
"@types/node": "22.19.19",
|
|
42
42
|
"@vercel/ai-tsconfig": "0.0.0",
|
|
43
43
|
"tsup": "^8.5.1",
|
package/src/pi-harness.ts
CHANGED
|
@@ -27,6 +27,8 @@ export type PiHarnessSettings = {
|
|
|
27
27
|
* Pi model id (or name). Leaving this unset falls back to the AI Gateway
|
|
28
28
|
* default when `AI_GATEWAY_API_KEY` / `VERCEL_OIDC_TOKEN` is set, and to
|
|
29
29
|
* Pi's own resolution otherwise.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated Use `model` on `HarnessAgent` instead.
|
|
30
32
|
*/
|
|
31
33
|
readonly model?: string;
|
|
32
34
|
/**
|
|
@@ -149,10 +151,9 @@ export function createPi(
|
|
|
149
151
|
sessionId: startOpts.sessionId,
|
|
150
152
|
sandboxSession: startOpts.sandboxSession,
|
|
151
153
|
sessionWorkDir: startOpts.sessionWorkDir,
|
|
152
|
-
skills: startOpts.skills ?? [],
|
|
153
154
|
settings: {
|
|
154
155
|
...(settings.auth ? { auth: settings.auth } : {}),
|
|
155
|
-
...(settings.model ? { model: settings.model }
|
|
156
|
+
...(settings.model == null ? {} : { model: settings.model }),
|
|
156
157
|
...(settings.thinkingLevel
|
|
157
158
|
? { thinkingLevel: settings.thinkingLevel }
|
|
158
159
|
: {}),
|
package/src/pi-session.ts
CHANGED
|
@@ -212,7 +212,8 @@ export type PiThinkingLevel =
|
|
|
212
212
|
| 'low'
|
|
213
213
|
| 'medium'
|
|
214
214
|
| 'high'
|
|
215
|
-
| 'xhigh'
|
|
215
|
+
| 'xhigh'
|
|
216
|
+
| 'max';
|
|
216
217
|
|
|
217
218
|
export interface PiSessionSettings {
|
|
218
219
|
readonly auth?: PiAuthenticationMode;
|
|
@@ -226,7 +227,6 @@ export interface CreatePiSessionInput {
|
|
|
226
227
|
readonly sessionId: string;
|
|
227
228
|
readonly sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;
|
|
228
229
|
readonly sessionWorkDir: string;
|
|
229
|
-
readonly skills: ReadonlyArray<HarnessV1Skill>;
|
|
230
230
|
readonly settings: PiSessionSettings;
|
|
231
231
|
readonly clientApp: string;
|
|
232
232
|
readonly isResume: boolean;
|
|
@@ -331,24 +331,13 @@ export async function createPiSession(
|
|
|
331
331
|
sessionId: input.sessionId,
|
|
332
332
|
});
|
|
333
333
|
const permissionMode = input.permissionMode ?? 'allow-all';
|
|
334
|
-
|
|
334
|
+
const sandboxSkillRootDir = path.posix.join(
|
|
335
|
+
sandboxHomeDir,
|
|
336
|
+
'.agents',
|
|
337
|
+
'skills',
|
|
338
|
+
);
|
|
335
339
|
let harnessSkills: Skill[] = [];
|
|
336
340
|
|
|
337
|
-
// Materialise harness-provided skills into sandbox HOME, not the workspace.
|
|
338
|
-
if (input.skills.length > 0) {
|
|
339
|
-
sandboxSkillRootDir = path.posix.join(sandboxHomeDir, '.agents', 'skills');
|
|
340
|
-
harnessSkills = createHarnessPiSkills({
|
|
341
|
-
skills: input.skills,
|
|
342
|
-
sandboxSkillRootDir,
|
|
343
|
-
});
|
|
344
|
-
await writePiSkills({
|
|
345
|
-
sandbox: toolSafeSandboxSession,
|
|
346
|
-
sandboxHomeDir,
|
|
347
|
-
skills: input.skills,
|
|
348
|
-
...(input.abortSignal ? { abortSignal: input.abortSignal } : {}),
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
341
|
// On resume: pull the Pi session file out of the sandbox into the fresh
|
|
353
342
|
// host mirror so SessionManager.open can read it.
|
|
354
343
|
let resumeSessionFilePath: string | undefined;
|
|
@@ -384,9 +373,7 @@ export async function createPiSession(
|
|
|
384
373
|
const paths = createPiPathMapper({
|
|
385
374
|
hostWorkDir,
|
|
386
375
|
sandboxWorkDir: sessionWorkDir,
|
|
387
|
-
readableRoots: sandboxSkillRootDir
|
|
388
|
-
? [{ sandboxDir: sandboxSkillRootDir }]
|
|
389
|
-
: [],
|
|
376
|
+
readableRoots: [{ sandboxDir: sandboxSkillRootDir }],
|
|
390
377
|
});
|
|
391
378
|
|
|
392
379
|
// Pi auth + model registry are global to this Pi session. These live on the
|
|
@@ -428,9 +415,7 @@ export async function createPiSession(
|
|
|
428
415
|
modelRegistry,
|
|
429
416
|
env: resolverEnv,
|
|
430
417
|
});
|
|
431
|
-
|
|
432
|
-
// `Model` object handed to `createAgentSession`.
|
|
433
|
-
const resolvedModel = resolveModel(input.settings.model);
|
|
418
|
+
let activeResolvedModel = resolveModel(input.settings.model);
|
|
434
419
|
const mcpServers = resolvePiMcpServers({
|
|
435
420
|
mcpServers: input.settings.mcpServers,
|
|
436
421
|
});
|
|
@@ -797,6 +782,8 @@ export async function createPiSession(
|
|
|
797
782
|
// rebuilding the Pi session from it.
|
|
798
783
|
const control = await runTurn({
|
|
799
784
|
text: '',
|
|
785
|
+
...(continueOpts.model ? { model: continueOpts.model } : {}),
|
|
786
|
+
skills: continueOpts.skills,
|
|
800
787
|
tools: continueOpts.tools ?? [],
|
|
801
788
|
instructions: continueOpts.instructions,
|
|
802
789
|
emit: continueOpts.emit,
|
|
@@ -1027,7 +1014,7 @@ export async function createPiSession(
|
|
|
1027
1014
|
...(input.settings.thinkingLevel
|
|
1028
1015
|
? { thinkingLevel: input.settings.thinkingLevel }
|
|
1029
1016
|
: {}),
|
|
1030
|
-
...(
|
|
1017
|
+
...(activeResolvedModel ? { model: activeResolvedModel } : {}),
|
|
1031
1018
|
});
|
|
1032
1019
|
piSession = session;
|
|
1033
1020
|
if (hasMcpServers) {
|
|
@@ -1073,6 +1060,8 @@ export async function createPiSession(
|
|
|
1073
1060
|
*/
|
|
1074
1061
|
async function runTurn(turnOpts: {
|
|
1075
1062
|
text: string;
|
|
1063
|
+
model?: string;
|
|
1064
|
+
skills: ReadonlyArray<HarnessV1Skill>;
|
|
1076
1065
|
tools: ReadonlyArray<HarnessV1ToolSpec>;
|
|
1077
1066
|
instructions?: string;
|
|
1078
1067
|
emit: (part: HarnessV1StreamPart) => void;
|
|
@@ -1082,6 +1071,20 @@ export async function createPiSession(
|
|
|
1082
1071
|
throw new Error('Pi session has been stopped.');
|
|
1083
1072
|
}
|
|
1084
1073
|
|
|
1074
|
+
const skillWriteResult = await writePiSkills({
|
|
1075
|
+
sandbox: toolSafeSandboxSession,
|
|
1076
|
+
sandboxHomeDir,
|
|
1077
|
+
skills: turnOpts.skills,
|
|
1078
|
+
abortSignal: turnOpts.abortSignal,
|
|
1079
|
+
});
|
|
1080
|
+
harnessSkills = createHarnessPiSkills({
|
|
1081
|
+
skills: turnOpts.skills,
|
|
1082
|
+
sandboxSkillRootDir,
|
|
1083
|
+
});
|
|
1084
|
+
if (piSession != null && skillWriteResult.changed) {
|
|
1085
|
+
await reloadResourcesOnly();
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1085
1088
|
const userTools = turnOpts.tools;
|
|
1086
1089
|
currentEmit = turnOpts.emit;
|
|
1087
1090
|
const turnAbortController = new AbortController();
|
|
@@ -1108,6 +1111,10 @@ export async function createPiSession(
|
|
|
1108
1111
|
const didAppendDeliveredHostToolResults =
|
|
1109
1112
|
appendDeliveredHostToolResults();
|
|
1110
1113
|
|
|
1114
|
+
const nextModel =
|
|
1115
|
+
turnOpts.model == null ? undefined : resolveModel(turnOpts.model);
|
|
1116
|
+
if (nextModel != null) activeResolvedModel = nextModel;
|
|
1117
|
+
|
|
1111
1118
|
const signature = JSON.stringify(userTools.map(t => t.name).sort());
|
|
1112
1119
|
const needsRebuild =
|
|
1113
1120
|
piSession == null || signature !== lastToolsSignature;
|
|
@@ -1119,6 +1126,14 @@ export async function createPiSession(
|
|
|
1119
1126
|
);
|
|
1120
1127
|
turnAbortController.signal.throwIfAborted();
|
|
1121
1128
|
lastToolsSignature = signature;
|
|
1129
|
+
} else if (
|
|
1130
|
+
nextModel != null &&
|
|
1131
|
+
piSession != null &&
|
|
1132
|
+
(piSession.model?.provider !== nextModel.provider ||
|
|
1133
|
+
piSession.model.id !== nextModel.id)
|
|
1134
|
+
) {
|
|
1135
|
+
await piSession.setModel(nextModel);
|
|
1136
|
+
turnAbortController.signal.throwIfAborted();
|
|
1122
1137
|
}
|
|
1123
1138
|
|
|
1124
1139
|
if (!resourcesReloaded) {
|
|
@@ -1140,7 +1155,10 @@ export async function createPiSession(
|
|
|
1140
1155
|
nativeToCommon: NATIVE_TO_COMMON,
|
|
1141
1156
|
});
|
|
1142
1157
|
|
|
1143
|
-
currentEmit?.({
|
|
1158
|
+
currentEmit?.({
|
|
1159
|
+
type: 'stream-start',
|
|
1160
|
+
...(piSession?.model?.id ? { modelId: piSession.model.id } : {}),
|
|
1161
|
+
});
|
|
1144
1162
|
|
|
1145
1163
|
/*
|
|
1146
1164
|
* A live continuation reports the completed tool execution before the
|
|
@@ -1315,10 +1333,6 @@ export async function createPiSession(
|
|
|
1315
1333
|
const sessionImpl: HarnessV1Session = {
|
|
1316
1334
|
sessionId: input.sessionId,
|
|
1317
1335
|
isResume: input.isResume,
|
|
1318
|
-
// The model Pi actually resolves to (the configured id, or its default when
|
|
1319
|
-
// unset) — `gen_ai.request.model`.
|
|
1320
|
-
...(resolvedModel?.id ? { modelId: resolvedModel.id } : {}),
|
|
1321
|
-
|
|
1322
1336
|
// Pi has no bridge to attach to and no on-disk event log to replay; its
|
|
1323
1337
|
// only resume path is restoring the session file on a fresh/snapshotted
|
|
1324
1338
|
// sandbox, i.e. `rerun`.
|
|
@@ -1334,6 +1348,8 @@ export async function createPiSession(
|
|
|
1334
1348
|
}
|
|
1335
1349
|
return runTurn({
|
|
1336
1350
|
text: extractUserText(promptOpts.prompt),
|
|
1351
|
+
...(promptOpts.model ? { model: promptOpts.model } : {}),
|
|
1352
|
+
skills: promptOpts.skills,
|
|
1337
1353
|
tools: promptOpts.tools ?? [],
|
|
1338
1354
|
instructions: promptOpts.instructions,
|
|
1339
1355
|
emit: promptOpts.emit,
|
|
@@ -1390,6 +1406,8 @@ export async function createPiSession(
|
|
|
1390
1406
|
*/
|
|
1391
1407
|
return runTurn({
|
|
1392
1408
|
text: '',
|
|
1409
|
+
...(continueOpts.model ? { model: continueOpts.model } : {}),
|
|
1410
|
+
skills: continueOpts.skills,
|
|
1393
1411
|
tools: continueOpts.tools ?? [],
|
|
1394
1412
|
instructions: continueOpts.instructions,
|
|
1395
1413
|
emit: continueOpts.emit,
|
package/src/pi-skills.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import type { HarnessV1Skill } from '@ai-sdk/harness';
|
|
3
|
-
import { writeSkills } from '@ai-sdk/harness/utils';
|
|
3
|
+
import { writeSkills, type WriteSkillsResult } from '@ai-sdk/harness/utils';
|
|
4
4
|
import type { Experimental_SandboxSession } from '@ai-sdk/provider-utils';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -12,8 +12,8 @@ export async function writePiSkills(args: {
|
|
|
12
12
|
readonly sandboxHomeDir: string;
|
|
13
13
|
readonly skills: ReadonlyArray<HarnessV1Skill>;
|
|
14
14
|
readonly abortSignal?: AbortSignal;
|
|
15
|
-
}): Promise<
|
|
16
|
-
|
|
15
|
+
}): Promise<WriteSkillsResult> {
|
|
16
|
+
return writeSkills({
|
|
17
17
|
sandbox: args.sandbox,
|
|
18
18
|
rootDir: path.posix.join(args.sandboxHomeDir, '.agents', 'skills'),
|
|
19
19
|
skills: args.skills,
|