@ai-sdk/harness-pi 1.0.124 → 1.0.126
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 +22 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +174 -21
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/pi-auth.ts +0 -1
- package/src/pi-events.ts +0 -2
- package/src/pi-harness.ts +4 -1
- package/src/pi-session.ts +84 -19
- package/src/pi-tool-result.ts +147 -0
- package/src/pi-translate.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @ai-sdk/harness-pi
|
|
2
2
|
|
|
3
|
+
## 1.0.126
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e9c5e0f: fix(harness-pi): release suspended sessions when in-process reattachment is disabled
|
|
8
|
+
- 85f3ff6: fix(harness-pi): bound model-facing tool results and support paged file reads
|
|
9
|
+
- Updated dependencies [40231b6]
|
|
10
|
+
- @ai-sdk/harness@1.0.124
|
|
11
|
+
|
|
12
|
+
## 1.0.125
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 771e74b: chore: enable dead code lint rules
|
|
17
|
+
- Updated dependencies [fe07867]
|
|
18
|
+
- Updated dependencies [a4b0940]
|
|
19
|
+
- Updated dependencies [9c8c0c1]
|
|
20
|
+
- Updated dependencies [771e74b]
|
|
21
|
+
- Updated dependencies [7115a3f]
|
|
22
|
+
- @ai-sdk/provider-utils@5.0.47
|
|
23
|
+
- @ai-sdk/harness@1.0.123
|
|
24
|
+
|
|
3
25
|
## 1.0.124
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ type PiHarnessSettings = {
|
|
|
65
65
|
declare const PI_BUILTIN_TOOLS: {
|
|
66
66
|
readonly read: HarnessV1BuiltinTool<{
|
|
67
67
|
file_path: string;
|
|
68
|
+
offset?: number | undefined;
|
|
69
|
+
limit?: number | undefined;
|
|
68
70
|
}, unknown>;
|
|
69
71
|
readonly write: HarnessV1BuiltinTool<{
|
|
70
72
|
file_path: string;
|
|
@@ -106,6 +108,8 @@ declare const VERSION: string;
|
|
|
106
108
|
declare const pi: _ai_sdk_harness.HarnessV1<{
|
|
107
109
|
readonly read: _ai_sdk_harness.HarnessV1BuiltinTool<{
|
|
108
110
|
file_path: string;
|
|
111
|
+
offset?: number | undefined;
|
|
112
|
+
limit?: number | undefined;
|
|
109
113
|
}, unknown>;
|
|
110
114
|
readonly write: _ai_sdk_harness.HarnessV1BuiltinTool<{
|
|
111
115
|
file_path: string;
|
package/dist/index.js
CHANGED
|
@@ -136,7 +136,7 @@ import {
|
|
|
136
136
|
import { access } from "fs/promises";
|
|
137
137
|
|
|
138
138
|
// src/version.ts
|
|
139
|
-
var VERSION = true ? "1.0.
|
|
139
|
+
var VERSION = true ? "1.0.126" : "0.0.0-test";
|
|
140
140
|
|
|
141
141
|
// src/pi-auth.ts
|
|
142
142
|
var DEFAULT_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
|
|
@@ -425,7 +425,6 @@ async function registerPiProviders({
|
|
|
425
425
|
clientApp,
|
|
426
426
|
headers
|
|
427
427
|
});
|
|
428
|
-
return;
|
|
429
428
|
}
|
|
430
429
|
}
|
|
431
430
|
}
|
|
@@ -627,7 +626,6 @@ function getPiTerminalError(event) {
|
|
|
627
626
|
if (event.isError && typeof event.content === "string" && event.content.trim()) {
|
|
628
627
|
return event.content.trim();
|
|
629
628
|
}
|
|
630
|
-
return void 0;
|
|
631
629
|
}
|
|
632
630
|
function extractAssistantText(message) {
|
|
633
631
|
if (!message || message.role !== "assistant") {
|
|
@@ -1156,6 +1154,104 @@ ${stderr}`;
|
|
|
1156
1154
|
};
|
|
1157
1155
|
}
|
|
1158
1156
|
|
|
1157
|
+
// src/pi-tool-result.ts
|
|
1158
|
+
import {
|
|
1159
|
+
DEFAULT_MAX_BYTES,
|
|
1160
|
+
formatSize,
|
|
1161
|
+
truncateHead,
|
|
1162
|
+
truncateTail
|
|
1163
|
+
} from "@earendil-works/pi-coding-agent";
|
|
1164
|
+
function joinContentAndNotice(content, notice) {
|
|
1165
|
+
return content.length > 0 ? `${content}
|
|
1166
|
+
|
|
1167
|
+
[${notice}]` : `[${notice}]`;
|
|
1168
|
+
}
|
|
1169
|
+
function truncateUtf8Start(text, maxBytes) {
|
|
1170
|
+
const buffer = Buffer.from(text, "utf8");
|
|
1171
|
+
if (buffer.length <= maxBytes) return text;
|
|
1172
|
+
let end = maxBytes;
|
|
1173
|
+
while (end > 0 && (buffer[end] & 192) === 128) {
|
|
1174
|
+
end--;
|
|
1175
|
+
}
|
|
1176
|
+
return buffer.subarray(0, end).toString("utf8");
|
|
1177
|
+
}
|
|
1178
|
+
function formatHeadNotice(truncation, continuation) {
|
|
1179
|
+
const limit = truncation.truncatedBy === "bytes" ? ` (${formatSize(truncation.maxBytes)} limit)` : "";
|
|
1180
|
+
return `Output truncated: showing the first ${truncation.outputLines} of ${truncation.totalLines} lines${limit}. ${continuation}`;
|
|
1181
|
+
}
|
|
1182
|
+
function formatTailNotice(truncation, continuation) {
|
|
1183
|
+
const limit = truncation.truncatedBy === "bytes" ? ` (${formatSize(truncation.maxBytes)} limit)` : "";
|
|
1184
|
+
return `Output truncated: showing the last ${truncation.outputLines} of ${truncation.totalLines} lines${limit}. ${continuation}`;
|
|
1185
|
+
}
|
|
1186
|
+
function truncatePiToolOutputHead(text, continuation) {
|
|
1187
|
+
const truncation = truncateHead(text);
|
|
1188
|
+
if (!truncation.truncated) return text;
|
|
1189
|
+
if (truncation.firstLineExceedsLimit) {
|
|
1190
|
+
const content = truncateUtf8Start(text, DEFAULT_MAX_BYTES);
|
|
1191
|
+
return joinContentAndNotice(
|
|
1192
|
+
content,
|
|
1193
|
+
`Output truncated: showing the first ${formatSize(
|
|
1194
|
+
Buffer.byteLength(content, "utf8")
|
|
1195
|
+
)} of a ${formatSize(truncation.totalBytes)} line. ${continuation}`
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
return joinContentAndNotice(
|
|
1199
|
+
truncation.content,
|
|
1200
|
+
formatHeadNotice(truncation, continuation)
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
function truncatePiToolOutputTail(text, continuation) {
|
|
1204
|
+
const truncation = truncateTail(text);
|
|
1205
|
+
if (!truncation.truncated) return text;
|
|
1206
|
+
return joinContentAndNotice(
|
|
1207
|
+
truncation.content,
|
|
1208
|
+
formatTailNotice(truncation, continuation)
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
function formatPiReadToolOutput({
|
|
1212
|
+
text,
|
|
1213
|
+
filePath,
|
|
1214
|
+
offset,
|
|
1215
|
+
limit
|
|
1216
|
+
}) {
|
|
1217
|
+
const allLines = text.split("\n");
|
|
1218
|
+
const startLine = offset == null ? 0 : Math.max(0, Math.floor(offset) - 1);
|
|
1219
|
+
const startLineDisplay = startLine + 1;
|
|
1220
|
+
if (startLine >= allLines.length) {
|
|
1221
|
+
throw new Error(
|
|
1222
|
+
`Offset ${offset} is beyond end of file (${allLines.length} lines total)`
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
const normalizedLimit = limit == null ? void 0 : Math.max(1, Math.floor(limit));
|
|
1226
|
+
const endLine = normalizedLimit == null ? allLines.length : Math.min(startLine + normalizedLimit, allLines.length);
|
|
1227
|
+
const selectedContent = allLines.slice(startLine, endLine).join("\n");
|
|
1228
|
+
const truncation = truncateHead(selectedContent);
|
|
1229
|
+
if (truncation.firstLineExceedsLimit) {
|
|
1230
|
+
const lineSize = formatSize(
|
|
1231
|
+
Buffer.byteLength(allLines[startLine] ?? "", "utf8")
|
|
1232
|
+
);
|
|
1233
|
+
return `[Line ${startLineDisplay} is ${lineSize}, exceeds ${formatSize(
|
|
1234
|
+
DEFAULT_MAX_BYTES
|
|
1235
|
+
)} limit. Use bash: sed -n '${startLineDisplay}p' ${filePath} | head -c ${DEFAULT_MAX_BYTES}]`;
|
|
1236
|
+
}
|
|
1237
|
+
if (truncation.truncated) {
|
|
1238
|
+
const endLineDisplay = startLineDisplay + Math.max(0, truncation.outputLines - 1);
|
|
1239
|
+
const nextOffset = endLineDisplay + 1;
|
|
1240
|
+
const limitNotice = truncation.truncatedBy === "bytes" ? ` (${formatSize(DEFAULT_MAX_BYTES)} limit)` : "";
|
|
1241
|
+
return joinContentAndNotice(
|
|
1242
|
+
truncation.content,
|
|
1243
|
+
`Showing lines ${startLineDisplay}-${endLineDisplay} of ${allLines.length}${limitNotice}. Use offset=${nextOffset} to continue.`
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
if (endLine < allLines.length) {
|
|
1247
|
+
return joinContentAndNotice(
|
|
1248
|
+
truncation.content,
|
|
1249
|
+
`${allLines.length - endLine} more lines in file. Use offset=${endLine + 1} to continue.`
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
return truncation.content;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1159
1255
|
// src/pi-translate.ts
|
|
1160
1256
|
import { randomBytes } from "crypto";
|
|
1161
1257
|
import { secureJsonParse } from "@ai-sdk/provider-utils";
|
|
@@ -1215,8 +1311,8 @@ function createPiTranslatorState(options = {}) {
|
|
|
1215
1311
|
stepOpen: false,
|
|
1216
1312
|
hostToolResults: /* @__PURE__ */ new Map(),
|
|
1217
1313
|
dynamicToolCallIds: /* @__PURE__ */ new Set(),
|
|
1218
|
-
builtinToolNames: new Set(options.builtinToolNames
|
|
1219
|
-
hostToolNames: new Set(options.hostToolNames
|
|
1314
|
+
builtinToolNames: new Set(options.builtinToolNames),
|
|
1315
|
+
hostToolNames: new Set(options.hostToolNames),
|
|
1220
1316
|
nativeToCommonNameMap: map
|
|
1221
1317
|
};
|
|
1222
1318
|
}
|
|
@@ -2561,7 +2657,13 @@ async function createPiSession(input) {
|
|
|
2561
2657
|
toolCallId,
|
|
2562
2658
|
toolName: delivered.toolName,
|
|
2563
2659
|
content: [
|
|
2564
|
-
{
|
|
2660
|
+
{
|
|
2661
|
+
type: "text",
|
|
2662
|
+
text: truncatePiToolOutputHead(
|
|
2663
|
+
serializeToolOutput(delivered.output),
|
|
2664
|
+
"Call the tool again with narrower parameters to inspect the omitted output."
|
|
2665
|
+
)
|
|
2666
|
+
}
|
|
2565
2667
|
],
|
|
2566
2668
|
isError: delivered.isError,
|
|
2567
2669
|
timestamp: Date.now()
|
|
@@ -3091,7 +3193,7 @@ async function createPiSession(input) {
|
|
|
3091
3193
|
},
|
|
3092
3194
|
doStop,
|
|
3093
3195
|
doDetach: async () => {
|
|
3094
|
-
if (activeTurn != null || pendingToolResults.size > 0) {
|
|
3196
|
+
if (input.settings.reattachInProcess !== false && (activeTurn != null || pendingToolResults.size > 0)) {
|
|
3095
3197
|
parkedPiSessions.set(input.sessionId, {
|
|
3096
3198
|
session: sessionImpl,
|
|
3097
3199
|
input,
|
|
@@ -3116,7 +3218,7 @@ async function createPiSession(input) {
|
|
|
3116
3218
|
if (stopped) {
|
|
3117
3219
|
throw new Error("Pi session has been stopped.");
|
|
3118
3220
|
}
|
|
3119
|
-
if (activeTurn != null && (pendingToolResults.size > 0 || pendingToolApprovals.size > 0)) {
|
|
3221
|
+
if (input.settings.reattachInProcess !== false && activeTurn != null && (pendingToolResults.size > 0 || pendingToolApprovals.size > 0)) {
|
|
3120
3222
|
parkedPiSessions.set(input.sessionId, {
|
|
3121
3223
|
session: sessionImpl,
|
|
3122
3224
|
input,
|
|
@@ -3137,8 +3239,11 @@ async function createPiSession(input) {
|
|
|
3137
3239
|
}
|
|
3138
3240
|
suspending = true;
|
|
3139
3241
|
const turnToSuspend = activeTurn;
|
|
3140
|
-
|
|
3242
|
+
const abortingTurn = turnToSuspend?.abort();
|
|
3141
3243
|
deferredRerun?.cancel();
|
|
3244
|
+
settlePendingToolResults("Pi session suspended");
|
|
3245
|
+
settlePendingToolApprovals("Pi session suspended");
|
|
3246
|
+
await abortingTurn;
|
|
3142
3247
|
await turnToSuspend?.done.catch(() => {
|
|
3143
3248
|
});
|
|
3144
3249
|
try {
|
|
@@ -3153,8 +3258,6 @@ async function createPiSession(input) {
|
|
|
3153
3258
|
}
|
|
3154
3259
|
stopped = true;
|
|
3155
3260
|
parkedPiSessions.delete(input.sessionId);
|
|
3156
|
-
settlePendingToolResults("Pi session suspended");
|
|
3157
|
-
settlePendingToolApprovals("Pi session suspended");
|
|
3158
3261
|
await disposePiSession();
|
|
3159
3262
|
workspaceVfs.unmount();
|
|
3160
3263
|
await rm2(hostRoot, { recursive: true, force: true });
|
|
@@ -3219,8 +3322,22 @@ function buildBuiltinToolDefinition(input) {
|
|
|
3219
3322
|
return defineTool({
|
|
3220
3323
|
name: "read",
|
|
3221
3324
|
label: "read",
|
|
3222
|
-
description: "Read file contents.",
|
|
3223
|
-
parameters: Type2.Object({
|
|
3325
|
+
description: "Read file contents. Output is limited to 2,000 lines or 50KB. Use offset and limit to read large files in pages.",
|
|
3326
|
+
parameters: Type2.Object({
|
|
3327
|
+
file_path: Type2.String(),
|
|
3328
|
+
offset: Type2.Optional(
|
|
3329
|
+
Type2.Integer({
|
|
3330
|
+
minimum: 1,
|
|
3331
|
+
description: "Line number to start reading from (1-indexed)."
|
|
3332
|
+
})
|
|
3333
|
+
),
|
|
3334
|
+
limit: Type2.Optional(
|
|
3335
|
+
Type2.Integer({
|
|
3336
|
+
minimum: 1,
|
|
3337
|
+
description: "Maximum number of lines to read."
|
|
3338
|
+
})
|
|
3339
|
+
)
|
|
3340
|
+
}),
|
|
3224
3341
|
async execute(toolCallId, params) {
|
|
3225
3342
|
const denied = await maybeDenyPiBuiltinTool({
|
|
3226
3343
|
toolCallId,
|
|
@@ -3229,7 +3346,14 @@ function buildBuiltinToolDefinition(input) {
|
|
|
3229
3346
|
});
|
|
3230
3347
|
if (denied) return denied;
|
|
3231
3348
|
const buf = await input.remoteOps.readBuffer(params.file_path);
|
|
3232
|
-
return asPiToolResult(
|
|
3349
|
+
return asPiToolResult(
|
|
3350
|
+
formatPiReadToolOutput({
|
|
3351
|
+
text: buf.toString("utf8"),
|
|
3352
|
+
filePath: params.file_path,
|
|
3353
|
+
offset: params.offset,
|
|
3354
|
+
limit: params.limit
|
|
3355
|
+
})
|
|
3356
|
+
);
|
|
3233
3357
|
}
|
|
3234
3358
|
});
|
|
3235
3359
|
case "write":
|
|
@@ -3307,7 +3431,12 @@ function buildBuiltinToolDefinition(input) {
|
|
|
3307
3431
|
const text = `${out}${result.exitCode != null ? `
|
|
3308
3432
|
|
|
3309
3433
|
(exit ${result.exitCode})` : ""}`.trim();
|
|
3310
|
-
return asPiToolResult(
|
|
3434
|
+
return asPiToolResult(
|
|
3435
|
+
truncatePiToolOutputTail(
|
|
3436
|
+
text,
|
|
3437
|
+
"Re-run the command with narrower output, or redirect it to a file and use read with offset and limit."
|
|
3438
|
+
)
|
|
3439
|
+
);
|
|
3311
3440
|
}
|
|
3312
3441
|
});
|
|
3313
3442
|
case "grep":
|
|
@@ -3332,7 +3461,12 @@ function buildBuiltinToolDefinition(input) {
|
|
|
3332
3461
|
});
|
|
3333
3462
|
if (denied) return denied;
|
|
3334
3463
|
const out = await input.remoteOps.grepFiles(params.pattern, params);
|
|
3335
|
-
return asPiToolResult(
|
|
3464
|
+
return asPiToolResult(
|
|
3465
|
+
truncatePiToolOutputHead(
|
|
3466
|
+
out,
|
|
3467
|
+
"Narrow the pattern or path, or read the matching file with offset and limit."
|
|
3468
|
+
)
|
|
3469
|
+
);
|
|
3336
3470
|
}
|
|
3337
3471
|
});
|
|
3338
3472
|
case "find":
|
|
@@ -3357,7 +3491,12 @@ function buildBuiltinToolDefinition(input) {
|
|
|
3357
3491
|
params.path ?? ".",
|
|
3358
3492
|
params.limit ?? 1e3
|
|
3359
3493
|
);
|
|
3360
|
-
return asPiToolResult(
|
|
3494
|
+
return asPiToolResult(
|
|
3495
|
+
truncatePiToolOutputHead(
|
|
3496
|
+
matches.join("\n"),
|
|
3497
|
+
"Narrow the pattern or search path to inspect the omitted matches."
|
|
3498
|
+
)
|
|
3499
|
+
);
|
|
3361
3500
|
}
|
|
3362
3501
|
});
|
|
3363
3502
|
case "ls":
|
|
@@ -3380,7 +3519,12 @@ function buildBuiltinToolDefinition(input) {
|
|
|
3380
3519
|
params.path ?? ".",
|
|
3381
3520
|
params.limit ?? 500
|
|
3382
3521
|
);
|
|
3383
|
-
return asPiToolResult(
|
|
3522
|
+
return asPiToolResult(
|
|
3523
|
+
truncatePiToolOutputHead(
|
|
3524
|
+
entries.join("\n"),
|
|
3525
|
+
"List a narrower directory path to inspect the omitted entries."
|
|
3526
|
+
)
|
|
3527
|
+
);
|
|
3384
3528
|
}
|
|
3385
3529
|
});
|
|
3386
3530
|
}
|
|
@@ -3399,7 +3543,14 @@ function buildUserToolDefinition(spec, pending) {
|
|
|
3399
3543
|
async execute(toolCallId) {
|
|
3400
3544
|
return new Promise((resolve2) => {
|
|
3401
3545
|
pending.set(toolCallId, { resolve: resolve2 });
|
|
3402
|
-
}).then(
|
|
3546
|
+
}).then(
|
|
3547
|
+
(output) => asPiToolResult(
|
|
3548
|
+
truncatePiToolOutputHead(
|
|
3549
|
+
serializeToolOutput(output),
|
|
3550
|
+
"Call the tool again with narrower parameters to inspect the omitted output."
|
|
3551
|
+
)
|
|
3552
|
+
)
|
|
3553
|
+
);
|
|
3403
3554
|
}
|
|
3404
3555
|
});
|
|
3405
3556
|
}
|
|
@@ -3410,9 +3561,11 @@ var PI_BUILTIN_TOOLS = {
|
|
|
3410
3561
|
read: commonTool("read", {
|
|
3411
3562
|
nativeName: "read",
|
|
3412
3563
|
toolUseKind: "readonly",
|
|
3413
|
-
description: "Read file contents.",
|
|
3564
|
+
description: "Read file contents. Output is limited to 2,000 lines or 50KB. Use offset and limit to read large files in pages.",
|
|
3414
3565
|
inputSchema: z3.object({
|
|
3415
|
-
file_path: z3.string()
|
|
3566
|
+
file_path: z3.string(),
|
|
3567
|
+
offset: z3.number().int().positive().optional(),
|
|
3568
|
+
limit: z3.number().int().positive().optional()
|
|
3416
3569
|
})
|
|
3417
3570
|
}),
|
|
3418
3571
|
write: commonTool("write", {
|