@ai-sdk/harness-pi 1.0.109 → 1.0.111

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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # @ai-sdk/harness-pi
2
2
 
3
+ ## 1.0.111
4
+
5
+ ### Patch Changes
6
+
7
+ - @ai-sdk/harness@1.0.109
8
+
9
+ ## 1.0.110
10
+
11
+ ### Patch Changes
12
+
13
+ - 3df6dc6: fix(harness-pi): initialize cold resumed sessions before compaction
14
+ - 3cd6dd8: fix(harness-pi): surface terminal provider errors before successful step boundaries
15
+ - cdc12a1: feat(harness): add support for using adapter-native subscriptions where available
16
+ - c550630: fix(harness-pi): register explicit custom provider models and prefer authenticated providers during model resolution
17
+ - Updated dependencies [4d1bf28]
18
+ - Updated dependencies [cdc12a1]
19
+ - Updated dependencies [d70a334]
20
+ - Updated dependencies [81ba84c]
21
+ - Updated dependencies [813bb36]
22
+ - Updated dependencies [c43e4b7]
23
+ - @ai-sdk/harness@1.0.108
24
+ - @ai-sdk/provider-utils@5.0.40
25
+
3
26
  ## 1.0.109
4
27
 
5
28
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _ai_sdk_harness from '@ai-sdk/harness';
2
2
  import { HarnessV1Authentication, HarnessV1, HarnessV1BuiltinTool } from '@ai-sdk/harness';
3
- import { ExtensionFactory } from '@earendil-works/pi-coding-agent';
3
+ import { ProviderConfig, ExtensionFactory } from '@earendil-works/pi-coding-agent';
4
4
 
5
5
  /**
6
6
  * Pi auth options. Choose an explicit mode or rely on 'auto' (precedence:
@@ -17,6 +17,12 @@ type PiThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' |
17
17
  type PiHarnessSettings = {
18
18
  /** Where Pi sources API keys / gateway credentials from. */
19
19
  readonly auth?: PiAuthenticationMode;
20
+ /**
21
+ * Explicit Pi provider configurations keyed by provider id. Use this to
22
+ * register custom models and their API protocol without coupling model
23
+ * metadata to authentication environment variables.
24
+ */
25
+ readonly providers?: Readonly<Record<string, ProviderConfig>>;
20
26
  /**
21
27
  * Pi's extended-thinking budget level. Maps directly to the SDK's
22
28
  * `thinkingLevel` option on `createAgentSession`.
@@ -24,9 +30,9 @@ type PiHarnessSettings = {
24
30
  readonly thinkingLevel?: PiThinkingLevel;
25
31
  /**
26
32
  * Directory holding Pi's global agent config (auth.json, models.json,
27
- * settings.json). When omitted, a per-session temp dir is used. Pass the
28
- * user's agent dir (e.g. `~/.pi/agent/`) to reuse their CLI auth and
29
- * model settings.
33
+ * settings.json). When omitted, native subscription auth is discovered from
34
+ * Pi's default agent directory while model and general settings remain
35
+ * isolated per session.
30
36
  */
31
37
  readonly agentDir?: string;
32
38
  /**
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.109" : "0.0.0-test";
139
+ var VERSION = true ? "1.0.111" : "0.0.0-test";
140
140
 
141
141
  // src/pi-auth.ts
142
142
  var DEFAULT_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh";
@@ -534,6 +534,28 @@ async function registerCustomProviders({
534
534
  }
535
535
  }
536
536
 
537
+ // src/pi-subscription.ts
538
+ import { homedir } from "os";
539
+ import { resolve } from "path";
540
+ import { isHarnessAuthenticationEnvironment as isHarnessAuthenticationEnvironment2 } from "@ai-sdk/harness/utils";
541
+ function resolvePiSubscriptionAgentDir({
542
+ options,
543
+ env,
544
+ agentDir,
545
+ homeDirectory = homedir()
546
+ }) {
547
+ if (isHarnessAuthenticationEnvironment2(options) || options === "ai-gateway") {
548
+ return void 0;
549
+ }
550
+ const resolvedEnvironment = resolvePiEnv({ options, env });
551
+ if (resolvedEnvironment.AI_GATEWAY_API_KEY != null) {
552
+ return void 0;
553
+ }
554
+ return resolve(
555
+ agentDir ?? env.PI_CODING_AGENT_DIR ?? `${homeDirectory}/.pi/agent`
556
+ );
557
+ }
558
+
537
559
  // src/pi-events.ts
538
560
  import { z as z2 } from "zod/v4";
539
561
  var piSessionEventSchema = z2.looseObject({
@@ -662,13 +684,14 @@ function createPiModelResolver({
662
684
  const gatewayMatch = useGateway ? models.find((m) => m.provider === "vercel-ai-gateway" && matches(m)) : void 0;
663
685
  if (gatewayMatch) return gatewayMatch;
664
686
  const scopedMatch = findScopedMatch(effectiveId, models);
665
- if (scopedMatch && !modelRegistry.hasConfiguredAuth(scopedMatch)) {
666
- const authenticatedFlatMatches = models.filter(
667
- (m) => m.id === effectiveId && modelRegistry.hasConfiguredAuth(m)
668
- );
669
- if (authenticatedFlatMatches.length === 1) {
670
- return authenticatedFlatMatches[0];
671
- }
687
+ if (scopedMatch && modelRegistry.hasConfiguredAuth(scopedMatch)) {
688
+ return scopedMatch;
689
+ }
690
+ const authenticatedFlatMatches = models.filter(
691
+ (m) => matches(m) && modelRegistry.hasConfiguredAuth(m)
692
+ );
693
+ if (authenticatedFlatMatches.length === 1) {
694
+ return authenticatedFlatMatches[0];
672
695
  }
673
696
  return scopedMatch ?? models.find(matches);
674
697
  };
@@ -1286,7 +1309,9 @@ function translatePiEvent(event, state) {
1286
1309
  } else {
1287
1310
  state.pendingStepToolCallIds.clear();
1288
1311
  state.stepToolCallCount = void 0;
1289
- parts.push(...finishStep(state));
1312
+ if (!getPiTerminalError(event)) {
1313
+ parts.push(...finishStep(state));
1314
+ }
1290
1315
  }
1291
1316
  return parts;
1292
1317
  }
@@ -2168,9 +2193,14 @@ async function createPiSession(input) {
2168
2193
  readableRoots: [{ sandboxDir: sandboxSkillRootDir }]
2169
2194
  });
2170
2195
  const agentDir = input.agentDir ?? hostAgentDir;
2196
+ const nativeAgentDir = resolvePiSubscriptionAgentDir({
2197
+ options: input.settings.auth,
2198
+ env: process.env,
2199
+ agentDir: input.agentDir
2200
+ });
2171
2201
  const modelRuntime = await createPiModelRuntime({
2172
2202
  auth: input.settings.auth,
2173
- authPath: path6.join(agentDir, "auth.json"),
2203
+ authPath: path6.join(nativeAgentDir ?? hostAgentDir, "auth.json"),
2174
2204
  modelsPath: path6.join(agentDir, "models.json")
2175
2205
  });
2176
2206
  const modelRegistry = new ModelRegistry(modelRuntime);
@@ -2189,6 +2219,14 @@ async function createPiSession(input) {
2189
2219
  clientApp: input.clientApp,
2190
2220
  headers: input.settings.headers
2191
2221
  });
2222
+ for (const [provider, config] of Object.entries(
2223
+ input.settings.providers ?? {}
2224
+ )) {
2225
+ modelRegistry.registerProvider(provider, {
2226
+ ...modelRegistry.getRegisteredProviderConfig(provider),
2227
+ ...config
2228
+ });
2229
+ }
2192
2230
  const resolveModel = createPiModelResolver({
2193
2231
  modelRegistry,
2194
2232
  env: resolverEnv
@@ -2405,8 +2443,8 @@ async function createPiSession(input) {
2405
2443
  deferredRerun?.cancel();
2406
2444
  let resolveDone;
2407
2445
  let rejectDone;
2408
- const done = new Promise((resolve, reject) => {
2409
- resolveDone = resolve;
2446
+ const done = new Promise((resolve2, reject) => {
2447
+ resolveDone = resolve2;
2410
2448
  rejectDone = reject;
2411
2449
  });
2412
2450
  let settled = false;
@@ -2538,8 +2576,8 @@ async function createPiSession(input) {
2538
2576
  currentEmit?.(part);
2539
2577
  }
2540
2578
  }
2541
- return new Promise((resolve) => {
2542
- pendingToolApprovals.set(args.toolCallId, { resolve });
2579
+ return new Promise((resolve2) => {
2580
+ pendingToolApprovals.set(args.toolCallId, { resolve: resolve2 });
2543
2581
  });
2544
2582
  }
2545
2583
  function buildToolDefinitions(userTools) {
@@ -2579,7 +2617,7 @@ async function createPiSession(input) {
2579
2617
  let resourcesReloaded = false;
2580
2618
  if (piSession) {
2581
2619
  await disposePiSession();
2582
- await new Promise((resolve) => setTimeout(resolve, 25));
2620
+ await new Promise((resolve2) => setTimeout(resolve2, 25));
2583
2621
  if (hasExtensionFactories) {
2584
2622
  await resourceLoader.reload();
2585
2623
  resourcesReloaded = true;
@@ -2889,7 +2927,15 @@ async function createPiSession(input) {
2889
2927
  if (stopped) {
2890
2928
  throw new Error("Pi session has been stopped.");
2891
2929
  }
2892
- await piSession?.compact(customInstructions);
2930
+ if (piSession == null) {
2931
+ await rebuildPiSession([], true);
2932
+ lastToolsSignature = JSON.stringify([]);
2933
+ }
2934
+ const session = piSession;
2935
+ if (session == null) {
2936
+ throw new Error("Pi session failed to initialize.");
2937
+ }
2938
+ await session.compact(customInstructions);
2893
2939
  },
2894
2940
  doDestroy: async () => {
2895
2941
  if (stopped) return;
@@ -3207,8 +3253,8 @@ function buildUserToolDefinition(spec, pending) {
3207
3253
  description: spec.description ?? `User-registered tool ${spec.name}`,
3208
3254
  parameters: toolSpecToTypeBoxParameters(schema),
3209
3255
  async execute(toolCallId) {
3210
- return new Promise((resolve) => {
3211
- pending.set(toolCallId, { resolve });
3256
+ return new Promise((resolve2) => {
3257
+ pending.set(toolCallId, { resolve: resolve2 });
3212
3258
  }).then((output) => asPiToolResult(serializeToolOutput(output)));
3213
3259
  }
3214
3260
  });
@@ -3309,6 +3355,7 @@ function createPi(settings = {}) {
3309
3355
  ...settings.auth ? { auth: settings.auth } : {},
3310
3356
  ...settings.thinkingLevel ? { thinkingLevel: settings.thinkingLevel } : {},
3311
3357
  ...settings.mcpServers ? { mcpServers: settings.mcpServers } : {},
3358
+ ...settings.providers ? { providers: settings.providers } : {},
3312
3359
  ...settings.extensionFactories ? { extensionFactories: settings.extensionFactories } : {},
3313
3360
  ...startOpts.headers ? { headers: startOpts.headers } : {}
3314
3361
  },