@ai-sdk/harness-pi 1.0.120 → 1.0.121
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 +9 -0
- package/README.md +19 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +32 -13
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +1 -1
- package/src/pi-auth.ts +11 -5
- package/src/pi-harness.ts +21 -1
- package/src/pi-session.ts +67 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @ai-sdk/harness-pi
|
|
2
2
|
|
|
3
|
+
## 1.0.121
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9e9f18f: fix(harness-pi): support stateless session restoration and injected credentials
|
|
8
|
+
- 2adbb77: feat(harness): update underlying harness SDKs to their latest versions
|
|
9
|
+
- Updated dependencies [125f493]
|
|
10
|
+
- @ai-sdk/harness@1.0.119
|
|
11
|
+
|
|
3
12
|
## 1.0.120
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -51,6 +51,25 @@ try {
|
|
|
51
51
|
|
|
52
52
|
The adapter requires a `HarnessV1SandboxProvider`. Pi has no in-sandbox bridge, so the sandbox doesn't need to expose any ports — `@ai-sdk/sandbox-vercel` or `@ai-sdk/sandbox-just-bash` both work.
|
|
53
53
|
|
|
54
|
+
## Stateless session configuration
|
|
55
|
+
|
|
56
|
+
By default, a suspended turn can reuse its live Pi session in the same process.
|
|
57
|
+
For stateless or multi-replica applications, set `reattachInProcess: false` so
|
|
58
|
+
continuations restore persisted state using the current request's settings.
|
|
59
|
+
Application-managed credentials can be supplied through a `PiCredentialStore`;
|
|
60
|
+
this replaces Pi's file-backed `auth.json` storage.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { createPi, type PiCredentialStore } from '@ai-sdk/harness-pi';
|
|
64
|
+
|
|
65
|
+
declare const credentials: PiCredentialStore;
|
|
66
|
+
|
|
67
|
+
const harness = createPi({
|
|
68
|
+
credentials,
|
|
69
|
+
reattachInProcess: false,
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
54
73
|
## Inline extensions
|
|
55
74
|
|
|
56
75
|
Use `extensionFactories` to load trusted inline Pi extensions for each harness session:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as _ai_sdk_harness from '@ai-sdk/harness';
|
|
2
2
|
import { HarnessV1Authentication, HarnessV1, HarnessV1BuiltinTool } from '@ai-sdk/harness';
|
|
3
|
-
import { ProviderConfig, ExtensionFactory } from '@earendil-works/pi-coding-agent';
|
|
3
|
+
import { CreateModelRuntimeOptions, ProviderConfig, ExtensionFactory } from '@earendil-works/pi-coding-agent';
|
|
4
4
|
|
|
5
|
+
/** Persistent credential storage consumed by Pi's model runtime. */
|
|
6
|
+
type PiCredentialStore = NonNullable<CreateModelRuntimeOptions['credentials']>;
|
|
5
7
|
/**
|
|
6
8
|
* Pi auth options. Choose an explicit mode or rely on 'auto' (precedence:
|
|
7
9
|
* explicit gateway, then OpenAI / Anthropic / custom environment variables).
|
|
@@ -17,6 +19,19 @@ type PiThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' |
|
|
|
17
19
|
type PiHarnessSettings = {
|
|
18
20
|
/** Where Pi sources API keys / gateway credentials from. */
|
|
19
21
|
readonly auth?: PiAuthenticationMode;
|
|
22
|
+
/**
|
|
23
|
+
* Application-owned credential storage for Pi's model runtime. When set,
|
|
24
|
+
* this replaces Pi's file-backed auth.json credential storage.
|
|
25
|
+
*/
|
|
26
|
+
readonly credentials?: PiCredentialStore;
|
|
27
|
+
/**
|
|
28
|
+
* Whether a suspended turn may reuse its live Pi session in this process.
|
|
29
|
+
* Disable this in stateless or multi-replica applications so every request
|
|
30
|
+
* restores from persisted lifecycle state with the current settings.
|
|
31
|
+
*
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
readonly reattachInProcess?: boolean;
|
|
20
35
|
/**
|
|
21
36
|
* Explicit Pi provider configurations keyed by provider id. Use this to
|
|
22
37
|
* register custom models and their API protocol without coupling model
|
|
@@ -122,4 +137,4 @@ declare const pi: _ai_sdk_harness.HarnessV1<{
|
|
|
122
137
|
readonly ls: _ai_sdk_harness.HarnessV1BuiltinTool;
|
|
123
138
|
}>;
|
|
124
139
|
|
|
125
|
-
export { type PiAuthenticationMode, type PiHarnessSettings, VERSION, createPi, pi };
|
|
140
|
+
export { type PiAuthenticationMode, type PiCredentialStore, type PiHarnessSettings, VERSION, createPi, pi };
|
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.121" : "0.0.0-test";
|
|
140
140
|
|
|
141
141
|
// src/pi-auth.ts
|
|
142
142
|
var DEFAULT_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
|
|
@@ -203,19 +203,20 @@ function scopePiProviderEnvironment({
|
|
|
203
203
|
}
|
|
204
204
|
async function createPiModelRuntime({
|
|
205
205
|
auth,
|
|
206
|
+
credentials,
|
|
206
207
|
authPath,
|
|
207
208
|
modelsPath
|
|
208
209
|
}) {
|
|
209
210
|
if (!isHarnessAuthenticationEnvironment(auth)) {
|
|
210
211
|
return ModelRuntime.create({
|
|
211
|
-
authPath,
|
|
212
|
+
...credentials ? { credentials } : { authPath },
|
|
212
213
|
modelsPath,
|
|
213
214
|
allowModelNetwork: false
|
|
214
215
|
});
|
|
215
216
|
}
|
|
216
|
-
const isolatedCredentials = createIsolatedPiCredentialStore();
|
|
217
|
+
const isolatedCredentials = credentials == null ? createIsolatedPiCredentialStore() : void 0;
|
|
217
218
|
const modelRuntime = await ModelRuntime.create({
|
|
218
|
-
credentials: isolatedCredentials.credentials,
|
|
219
|
+
credentials: credentials ?? isolatedCredentials.credentials,
|
|
219
220
|
modelsPath: null,
|
|
220
221
|
allowModelNetwork: false
|
|
221
222
|
});
|
|
@@ -237,7 +238,7 @@ async function createPiModelRuntime({
|
|
|
237
238
|
modelRuntime,
|
|
238
239
|
authenticationEnvironment: auth
|
|
239
240
|
});
|
|
240
|
-
isolatedCredentials
|
|
241
|
+
isolatedCredentials?.finishInitialization();
|
|
241
242
|
await modelRuntime.refresh({ allowNetwork: false });
|
|
242
243
|
return modelRuntime;
|
|
243
244
|
}
|
|
@@ -2228,6 +2229,9 @@ function resolveActivePiBuiltinNames(toolFiltering) {
|
|
|
2228
2229
|
(native) => !toolFiltering.toolNames.includes(NATIVE_TO_COMMON[native] ?? native)
|
|
2229
2230
|
);
|
|
2230
2231
|
}
|
|
2232
|
+
function hasCompatibleReattachSettings(parked, current) {
|
|
2233
|
+
return parked.sandboxSession === current.sandboxSession && parked.sessionWorkDir === current.sessionWorkDir && parked.clientApp === current.clientApp && parked.permissionMode === current.permissionMode && parked.builtinToolFiltering === current.builtinToolFiltering && parked.abortSignal === current.abortSignal && parked.agentDir === current.agentDir && parked.settings.auth === current.settings.auth && parked.settings.credentials === current.settings.credentials && parked.settings.headers === current.settings.headers && parked.settings.thinkingLevel === current.settings.thinkingLevel && parked.settings.mcpServers === current.settings.mcpServers && parked.settings.providers === current.settings.providers && parked.settings.extensionFactories === current.settings.extensionFactories;
|
|
2234
|
+
}
|
|
2231
2235
|
async function isWorkspaceAvailableOnHost({
|
|
2232
2236
|
sandbox,
|
|
2233
2237
|
sessionWorkDir
|
|
@@ -2250,13 +2254,16 @@ async function isWorkspaceAvailableOnHost({
|
|
|
2250
2254
|
}
|
|
2251
2255
|
async function createPiSession(input) {
|
|
2252
2256
|
if (input.isResume) {
|
|
2253
|
-
const
|
|
2254
|
-
if (
|
|
2257
|
+
const parked = parkedPiSessions.get(input.sessionId);
|
|
2258
|
+
if (parked) {
|
|
2255
2259
|
parkedPiSessions.delete(input.sessionId);
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
+
if (input.settings.reattachInProcess !== false && (input.resumeStateType == null || input.resumeStateType === parked.stateType) && hasCompatibleReattachSettings(parked.input, input)) {
|
|
2261
|
+
return {
|
|
2262
|
+
...parked.session,
|
|
2263
|
+
isResume: true
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2266
|
+
await parked.session.doDestroy();
|
|
2260
2267
|
}
|
|
2261
2268
|
}
|
|
2262
2269
|
const safeSessionId = input.sessionId.replace(/[\\/: ]/g, "-");
|
|
@@ -2328,6 +2335,7 @@ async function createPiSession(input) {
|
|
|
2328
2335
|
});
|
|
2329
2336
|
const modelRuntime = await createPiModelRuntime({
|
|
2330
2337
|
auth: input.settings.auth,
|
|
2338
|
+
credentials: input.settings.credentials,
|
|
2331
2339
|
authPath: path6.join(nativeAgentDir ?? hostAgentDir, "auth.json"),
|
|
2332
2340
|
modelsPath: path6.join(agentDir, "models.json")
|
|
2333
2341
|
});
|
|
@@ -3084,7 +3092,11 @@ async function createPiSession(input) {
|
|
|
3084
3092
|
doStop,
|
|
3085
3093
|
doDetach: async () => {
|
|
3086
3094
|
if (activeTurn != null || pendingToolResults.size > 0) {
|
|
3087
|
-
parkedPiSessions.set(input.sessionId,
|
|
3095
|
+
parkedPiSessions.set(input.sessionId, {
|
|
3096
|
+
session: sessionImpl,
|
|
3097
|
+
input,
|
|
3098
|
+
stateType: "resume-session"
|
|
3099
|
+
});
|
|
3088
3100
|
if (sessionFileName) {
|
|
3089
3101
|
try {
|
|
3090
3102
|
await persistSessionFile();
|
|
@@ -3105,7 +3117,11 @@ async function createPiSession(input) {
|
|
|
3105
3117
|
throw new Error("Pi session has been stopped.");
|
|
3106
3118
|
}
|
|
3107
3119
|
if (activeTurn != null && (pendingToolResults.size > 0 || pendingToolApprovals.size > 0)) {
|
|
3108
|
-
parkedPiSessions.set(input.sessionId,
|
|
3120
|
+
parkedPiSessions.set(input.sessionId, {
|
|
3121
|
+
session: sessionImpl,
|
|
3122
|
+
input,
|
|
3123
|
+
stateType: "continue-turn"
|
|
3124
|
+
});
|
|
3109
3125
|
if (sessionFileName) {
|
|
3110
3126
|
try {
|
|
3111
3127
|
await persistSessionFile();
|
|
@@ -3481,6 +3497,8 @@ function createPi(settings = {}) {
|
|
|
3481
3497
|
sessionWorkDir: startOpts.sessionWorkDir,
|
|
3482
3498
|
settings: {
|
|
3483
3499
|
...settings.auth ? { auth: settings.auth } : {},
|
|
3500
|
+
...settings.credentials ? { credentials: settings.credentials } : {},
|
|
3501
|
+
...settings.reattachInProcess != null ? { reattachInProcess: settings.reattachInProcess } : {},
|
|
3484
3502
|
...settings.thinkingLevel ? { thinkingLevel: settings.thinkingLevel } : {},
|
|
3485
3503
|
...settings.mcpServers ? { mcpServers: settings.mcpServers } : {},
|
|
3486
3504
|
...settings.providers ? { providers: settings.providers } : {},
|
|
@@ -3489,6 +3507,7 @@ function createPi(settings = {}) {
|
|
|
3489
3507
|
},
|
|
3490
3508
|
clientApp: PI_CLIENT_APP,
|
|
3491
3509
|
isResume: lifecycleState != null,
|
|
3510
|
+
...lifecycleState ? { resumeStateType: lifecycleState.type } : {},
|
|
3492
3511
|
permissionMode: startOpts.permissionMode,
|
|
3493
3512
|
builtinToolFiltering: startOpts.builtinToolFiltering,
|
|
3494
3513
|
...resumeData?.sessionFileName ? { resumeSessionFileName: resumeData.sessionFileName } : {},
|