@ai-sdk/harness 1.0.106 → 1.0.108

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/dist/index.d.ts CHANGED
@@ -472,6 +472,12 @@ type HarnessV1PendingToolResult = {
472
472
  readonly toolName: string;
473
473
  readonly input: string;
474
474
  readonly providerOptions?: ProviderOptions;
475
+ /** Executed while suspending; submit on resume without running the tool again. */
476
+ readonly completedResult?: {
477
+ readonly output: unknown;
478
+ readonly isError?: boolean;
479
+ readonly toolResult?: ToolResultPart;
480
+ };
475
481
  };
476
482
  /**
477
483
  * Framework-owned settings captured when a turn begins. The same settings are
@@ -240,9 +240,70 @@ declare function getAiGatewayAuthFromEnv({ env, }: {
240
240
  * process environment for authentication discovery.
241
241
  */
242
242
  type HarnessV1AuthenticationEnvironment = Readonly<Record<string, string>>;
243
+ /**
244
+ * Authentication options shared by harness adapters. Adapter choices must be
245
+ * a non-empty union of concrete string values.
246
+ */
247
+ type HarnessV1Authentication<ADAPTER_CHOICES extends string = 'direct'> = [
248
+ ADAPTER_CHOICES
249
+ ] extends [never] ? never : string extends ADAPTER_CHOICES ? never : 'auto' | 'ai-gateway' | ADAPTER_CHOICES | HarnessV1AuthenticationEnvironment;
243
250
 
244
251
  declare function isHarnessAuthenticationEnvironment(value: unknown): value is HarnessV1AuthenticationEnvironment;
245
252
 
253
+ declare function parseJwtPayload({ token, }: {
254
+ token: string;
255
+ }): Promise<Readonly<Record<string, unknown>> | undefined>;
256
+ declare function getJwtExpiresAt({ token, }: {
257
+ token: string;
258
+ }): Promise<number | undefined>;
259
+
260
+ declare function readLinuxSecretServicePassword({ attributes, }: {
261
+ attributes: Readonly<Record<string, string>>;
262
+ }): Promise<string | undefined>;
263
+
264
+ declare function readMacOSKeychainPassword({ service, account, }: {
265
+ service: string;
266
+ account: string;
267
+ }): Promise<string | undefined>;
268
+
269
+ declare function shouldResolveNativeSubscription({ auth, env, hasDirectCredential, }: {
270
+ auth: Extract<HarnessV1Authentication, string> | undefined;
271
+ env: Readonly<Record<string, string | undefined>>;
272
+ hasDirectCredential: boolean;
273
+ }): boolean;
274
+
275
+ declare function readWindowsCredentialManagerPassword({ targetName, }: {
276
+ targetName: string;
277
+ }): Promise<string | undefined>;
278
+
279
+ type OAuthCredential = {
280
+ readonly accessToken: string;
281
+ readonly refreshToken: string;
282
+ readonly expiresAt: number;
283
+ };
284
+ type RefreshOAuthAccessTokenResult = {
285
+ readonly accessToken: string;
286
+ readonly expiresAt: number;
287
+ readonly refreshToken?: string;
288
+ };
289
+ declare function isAccessTokenExpiringSoon({ expiresAt, now, refreshWindowMs, }: {
290
+ readonly expiresAt: number;
291
+ readonly now?: number;
292
+ readonly refreshWindowMs?: number;
293
+ }): boolean;
294
+ declare function refreshOAuthAccessToken({ tokenUrl, clientId, refreshToken, requestFormat, headers, fetch: fetchImplementation, }: {
295
+ readonly tokenUrl: string;
296
+ readonly clientId: string;
297
+ readonly refreshToken: string;
298
+ readonly requestFormat?: 'json' | 'form';
299
+ readonly headers?: Record<string, string>;
300
+ readonly fetch?: typeof globalThis.fetch;
301
+ }): Promise<RefreshOAuthAccessTokenResult>;
302
+
303
+ declare function isMacOS(platform: NodeJS.Platform): boolean;
304
+ declare function isLinux(platform: NodeJS.Platform): boolean;
305
+ declare function isWindows(platform: NodeJS.Platform): boolean;
306
+
246
307
  /**
247
308
  * Connection details for a sandbox-exposed port. Headers are scoped to the
248
309
  * returned URL and must be included when opening the connection.
@@ -639,4 +700,4 @@ declare function resolveSandboxDefaultWorkingDirectory({ sandboxSession, abortSi
639
700
 
640
701
  declare function getRestrictedSandboxSession(sandboxSession: HarnessV1NetworkSandboxSession | Experimental_SandboxSession): Experimental_SandboxSession;
641
702
 
642
- export { type BridgeReadyErrorContext, type BridgeReadySource, type DiskLogRecoveryMode, type Experimental_BridgeUserMessageRequest, type Experimental_BridgeUserMessageResponse, type Experimental_BridgeUserMessageSubmitter, SandboxChannel, type SandboxChannelDebugEvent, type SandboxChannelOptions, type SandboxChannelReconnectOptions, type SkillFilePathMode, type WaitForBridgeReadyOptions, type WaitForBridgeReadyResult, type WriteInstructionsOptions, type WriteInstructionsResult, type WriteSkillsOptions, type WriteSkillsResult, applyCredentialForwarding, classifyDiskLog, createBridgeErrorHandler, createBridgeStartupError, createBridgeToken, createCredentialRequestTransformation, createReadBridgeAsset, createSandboxCredentialEnvironment, drainBridgeProcessStream, experimental_createBridgeUserMessageSubmitter, formatBridgeError, forwardBridgeProcessStream, generateSandboxCredentialPlaceholder, getAiGatewayAuthFromEnv, getRestrictedSandboxSession, isHarnessAuthenticationEnvironment, isSandboxCredentialPlaceholder, logBridgeError, markBridgeStarting, maskSandboxCredentials, resolveSandboxDefaultWorkingDirectory, resolveSandboxHomeDir, shellQuote, waitForBridgeReady, warnCredentialBrokeringUnavailable, withBridgeToken, writeInstructions, writeSkills };
703
+ export { type BridgeReadyErrorContext, type BridgeReadySource, type DiskLogRecoveryMode, type Experimental_BridgeUserMessageRequest, type Experimental_BridgeUserMessageResponse, type Experimental_BridgeUserMessageSubmitter, type OAuthCredential, type RefreshOAuthAccessTokenResult, SandboxChannel, type SandboxChannelDebugEvent, type SandboxChannelOptions, type SandboxChannelReconnectOptions, type SkillFilePathMode, type WaitForBridgeReadyOptions, type WaitForBridgeReadyResult, type WriteInstructionsOptions, type WriteInstructionsResult, type WriteSkillsOptions, type WriteSkillsResult, applyCredentialForwarding, classifyDiskLog, createBridgeErrorHandler, createBridgeStartupError, createBridgeToken, createCredentialRequestTransformation, createReadBridgeAsset, createSandboxCredentialEnvironment, drainBridgeProcessStream, experimental_createBridgeUserMessageSubmitter, formatBridgeError, forwardBridgeProcessStream, generateSandboxCredentialPlaceholder, getAiGatewayAuthFromEnv, getJwtExpiresAt, getRestrictedSandboxSession, isAccessTokenExpiringSoon, isHarnessAuthenticationEnvironment, isLinux, isMacOS, isSandboxCredentialPlaceholder, isWindows, logBridgeError, markBridgeStarting, maskSandboxCredentials, parseJwtPayload, readLinuxSecretServicePassword, readMacOSKeychainPassword, readWindowsCredentialManagerPassword, refreshOAuthAccessToken, resolveSandboxDefaultWorkingDirectory, resolveSandboxHomeDir, shellQuote, shouldResolveNativeSubscription, waitForBridgeReady, warnCredentialBrokeringUnavailable, withBridgeToken, writeInstructions, writeSkills };
@@ -450,6 +450,229 @@ function isHarnessAuthenticationEnvironment(value) {
450
450
  return true;
451
451
  }
452
452
 
453
+ // src/utils/native-subscription/jwt.ts
454
+ import { isRecord, safeParseJSON as safeParseJSON3 } from "@ai-sdk/provider-utils";
455
+ async function parseJwtPayload({
456
+ token
457
+ }) {
458
+ const segments = token.split(".");
459
+ if (segments.length !== 3) return void 0;
460
+ try {
461
+ const parsed = await safeParseJSON3({
462
+ text: Buffer.from(segments[1], "base64url").toString("utf8")
463
+ });
464
+ return parsed.success && isRecord(parsed.value) ? parsed.value : void 0;
465
+ } catch (e) {
466
+ return void 0;
467
+ }
468
+ }
469
+ async function getJwtExpiresAt({
470
+ token
471
+ }) {
472
+ const payload = await parseJwtPayload({ token });
473
+ const expiresAt = payload == null ? void 0 : payload.exp;
474
+ return typeof expiresAt === "number" && Number.isFinite(expiresAt) ? expiresAt * 1e3 : void 0;
475
+ }
476
+
477
+ // src/utils/native-subscription/linux-secret-service.ts
478
+ import { execFile } from "child_process";
479
+ import { promisify } from "util";
480
+ var execFileAsync = promisify(execFile);
481
+ async function readLinuxSecretServicePassword({
482
+ attributes
483
+ }) {
484
+ try {
485
+ const result = await execFileAsync("secret-tool", [
486
+ "lookup",
487
+ ...Object.entries(attributes).flatMap(([attribute, value]) => [
488
+ attribute,
489
+ value
490
+ ])
491
+ ]);
492
+ return result.stdout || void 0;
493
+ } catch (e) {
494
+ return void 0;
495
+ }
496
+ }
497
+
498
+ // src/utils/native-subscription/macos-keychain.ts
499
+ import { execFile as execFile2 } from "child_process";
500
+ import { promisify as promisify2 } from "util";
501
+ var execFileAsync2 = promisify2(execFile2);
502
+ async function readMacOSKeychainPassword({
503
+ service,
504
+ account
505
+ }) {
506
+ try {
507
+ const result = await execFileAsync2("/usr/bin/security", [
508
+ "find-generic-password",
509
+ "-s",
510
+ service,
511
+ "-a",
512
+ account,
513
+ "-w"
514
+ ]);
515
+ return result.stdout.trim() || void 0;
516
+ } catch (e) {
517
+ return void 0;
518
+ }
519
+ }
520
+
521
+ // src/utils/native-subscription/should-resolve-native.ts
522
+ function shouldResolveNativeSubscription({
523
+ auth,
524
+ env,
525
+ hasDirectCredential
526
+ }) {
527
+ return auth !== "ai-gateway" && !hasDirectCredential && (auth === "direct" || getAiGatewayAuthFromEnv({ env }).apiKey == null);
528
+ }
529
+
530
+ // src/utils/native-subscription/windows-credential-manager.ts
531
+ import { execFile as execFile3 } from "child_process";
532
+ import { promisify as promisify3 } from "util";
533
+ var execFileAsync3 = promisify3(execFile3);
534
+ var credentialManagerSource = `
535
+ using System;
536
+ using System.Runtime.InteropServices;
537
+ using System.Text;
538
+ public static class AISDKCredentialManager {
539
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
540
+ public struct Credential {
541
+ public UInt32 Flags; public UInt32 Type; public string TargetName;
542
+ public string Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
543
+ public UInt32 CredentialBlobSize; public IntPtr CredentialBlob;
544
+ public UInt32 Persist; public UInt32 AttributeCount; public IntPtr Attributes;
545
+ public string TargetAlias; public string UserName;
546
+ }
547
+ [DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
548
+ static extern bool CredRead(string target, UInt32 type, UInt32 flags, out IntPtr credential);
549
+ [DllImport("advapi32.dll", SetLastError = true)] static extern void CredFree(IntPtr credential);
550
+ public static string Read(string target) {
551
+ IntPtr pointer;
552
+ if (!CredRead(target, 1, 0, out pointer)) return null;
553
+ try {
554
+ Credential value = Marshal.PtrToStructure<Credential>(pointer);
555
+ byte[] bytes = new byte[value.CredentialBlobSize];
556
+ Marshal.Copy(value.CredentialBlob, bytes, 0, bytes.Length);
557
+ return Encoding.Unicode.GetString(bytes);
558
+ } finally { CredFree(pointer); }
559
+ }
560
+ }`;
561
+ async function readWindowsCredentialManagerPassword({
562
+ targetName
563
+ }) {
564
+ try {
565
+ const result = await execFileAsync3(
566
+ "powershell.exe",
567
+ [
568
+ "-NoProfile",
569
+ "-NonInteractive",
570
+ "-Command",
571
+ `Add-Type -TypeDefinition $env:AI_SDK_WINDOWS_CREDENTIAL_MANAGER_SOURCE; $value = [AISDKCredentialManager]::Read($env:AI_SDK_WINDOWS_CREDENTIAL_MANAGER_TARGET); if ($null -ne $value) { [Console]::Out.Write($value) }`
572
+ ],
573
+ {
574
+ env: {
575
+ ...process.env,
576
+ AI_SDK_WINDOWS_CREDENTIAL_MANAGER_SOURCE: credentialManagerSource,
577
+ AI_SDK_WINDOWS_CREDENTIAL_MANAGER_TARGET: targetName
578
+ },
579
+ windowsHide: true
580
+ }
581
+ );
582
+ return result.stdout || void 0;
583
+ } catch (e) {
584
+ return void 0;
585
+ }
586
+ }
587
+
588
+ // src/utils/oauth-access-token.ts
589
+ import { isRecord as isRecord2, safeParseJSON as safeParseJSON4 } from "@ai-sdk/provider-utils";
590
+ var DEFAULT_REFRESH_WINDOW_MS = 3e5;
591
+ function isAccessTokenExpiringSoon({
592
+ expiresAt,
593
+ now = Date.now(),
594
+ refreshWindowMs = DEFAULT_REFRESH_WINDOW_MS
595
+ }) {
596
+ return expiresAt <= now + refreshWindowMs;
597
+ }
598
+ async function refreshOAuthAccessToken({
599
+ tokenUrl,
600
+ clientId,
601
+ refreshToken,
602
+ requestFormat = "form",
603
+ headers,
604
+ fetch: fetchImplementation = globalThis.fetch
605
+ }) {
606
+ const values = {
607
+ grant_type: "refresh_token",
608
+ client_id: clientId,
609
+ refresh_token: refreshToken
610
+ };
611
+ const response = await fetchImplementation(tokenUrl, {
612
+ method: "POST",
613
+ headers: {
614
+ "content-type": requestFormat === "json" ? "application/json" : "application/x-www-form-urlencoded",
615
+ ...headers
616
+ },
617
+ body: requestFormat === "json" ? JSON.stringify(values) : new URLSearchParams(values).toString()
618
+ });
619
+ const responseText = await response.text();
620
+ if (!response.ok) {
621
+ throw new Error(
622
+ `OAuth access token refresh failed with status ${response.status}.`
623
+ );
624
+ }
625
+ const parsed = await safeParseJSON4({ text: responseText });
626
+ if (!parsed.success || !isRecord2(parsed.value)) {
627
+ throw new Error("OAuth access token refresh returned invalid JSON.");
628
+ }
629
+ const accessToken = parsed.value.access_token;
630
+ if (typeof accessToken !== "string" || accessToken.length === 0) {
631
+ throw new Error(
632
+ "OAuth access token refresh response is missing access_token."
633
+ );
634
+ }
635
+ const expiresAt = await resolveExpiresAt({
636
+ accessToken,
637
+ expiresIn: parsed.value.expires_in
638
+ });
639
+ const rotatedRefreshToken = parsed.value.refresh_token;
640
+ if (rotatedRefreshToken != null && (typeof rotatedRefreshToken !== "string" || rotatedRefreshToken.length === 0)) {
641
+ throw new Error(
642
+ "OAuth access token refresh response contains an invalid refresh_token."
643
+ );
644
+ }
645
+ return {
646
+ accessToken,
647
+ expiresAt,
648
+ ...typeof rotatedRefreshToken === "string" ? { refreshToken: rotatedRefreshToken } : {}
649
+ };
650
+ }
651
+ async function resolveExpiresAt({
652
+ accessToken,
653
+ expiresIn
654
+ }) {
655
+ if (typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn >= 0) {
656
+ return Date.now() + expiresIn * 1e3;
657
+ }
658
+ const jwtExpiresAt = await getJwtExpiresAt({ token: accessToken });
659
+ if (jwtExpiresAt != null) return jwtExpiresAt;
660
+ throw new Error(
661
+ "OAuth access token refresh response does not include a usable expiry."
662
+ );
663
+ }
664
+
665
+ // src/utils/os.ts
666
+ function isMacOS(platform) {
667
+ return platform === "darwin";
668
+ }
669
+ function isLinux(platform) {
670
+ return platform === "linux";
671
+ }
672
+ function isWindows(platform) {
673
+ return platform === "win32";
674
+ }
675
+
453
676
  // src/utils/sandbox-credential-brokering.ts
454
677
  import { randomBytes } from "crypto";
455
678
  var SANDBOX_CREDENTIAL_PLACEHOLDER_PREFIX = "aisdkhc_";
@@ -576,7 +799,7 @@ function shellQuote(value) {
576
799
  // src/utils/write-instructions.ts
577
800
  import path2 from "path";
578
801
  import {
579
- safeParseJSON as safeParseJSON3
802
+ safeParseJSON as safeParseJSON5
580
803
  } from "@ai-sdk/provider-utils";
581
804
  var INSTRUCTIONS_METADATA_VERSION = 1;
582
805
  async function writeInstructions({
@@ -766,7 +989,7 @@ async function readInstructionsMetadata({
766
989
  abortSignal
767
990
  });
768
991
  if (content == null) return void 0;
769
- const parsed = await safeParseJSON3({ text: content });
992
+ const parsed = await safeParseJSON5({ text: content });
770
993
  if (!parsed.success || !isInstructionsMetadata(parsed.value)) {
771
994
  throw new Error(
772
995
  `Invalid AI SDK harness instructions metadata: ${metadataPath}`
@@ -843,7 +1066,7 @@ async function runSandboxCommand({
843
1066
  import { createHash } from "crypto";
844
1067
  import path3 from "path";
845
1068
  import {
846
- safeParseJSON as safeParseJSON4
1069
+ safeParseJSON as safeParseJSON6
847
1070
  } from "@ai-sdk/provider-utils";
848
1071
  var SKILLS_MANIFEST_FILENAME = ".ai-sdk-harness-skills.json";
849
1072
  var SKILLS_MANIFEST_VERSION = 1;
@@ -1056,7 +1279,7 @@ async function readSkillsManifest({
1056
1279
  abortSignal
1057
1280
  });
1058
1281
  if (content == null) return void 0;
1059
- const parsed = await safeParseJSON4({ text: content });
1282
+ const parsed = await safeParseJSON6({ text: content });
1060
1283
  if (!parsed.success || !isSkillsManifest(parsed.value)) {
1061
1284
  throw new Error(`Invalid AI SDK harness skills manifest: ${manifestPath}`);
1062
1285
  }
@@ -1258,7 +1481,7 @@ function resolveSkillsRootDir({
1258
1481
 
1259
1482
  // src/utils/bridge-ready.ts
1260
1483
  import {
1261
- safeParseJSON as safeParseJSON5
1484
+ safeParseJSON as safeParseJSON7
1262
1485
  } from "@ai-sdk/provider-utils";
1263
1486
  import { z as z4 } from "zod/v4";
1264
1487
 
@@ -1750,7 +1973,7 @@ async function waitForBridgeReady({
1750
1973
  if (value === void 0) continue;
1751
1974
  for (const line of decoder.push(value)) {
1752
1975
  pushTail({ lines: stdoutTail, line });
1753
- const parsed = await safeParseJSON5({
1976
+ const parsed = await safeParseJSON7({
1754
1977
  text: line,
1755
1978
  schema: harnessV1BridgeReadySchema
1756
1979
  });
@@ -1787,7 +2010,7 @@ async function readBridgeMetaReady({
1787
2010
  })
1788
2011
  ).catch(() => null);
1789
2012
  if (raw == null) return void 0;
1790
- const parsed = await safeParseJSON5({ text: raw, schema: bridgeMetaSchema });
2013
+ const parsed = await safeParseJSON7({ text: raw, schema: bridgeMetaSchema });
1791
2014
  if (!parsed.success) return void 0;
1792
2015
  if (parsed.value.type !== bridgeType) return void 0;
1793
2016
  if (parsed.value.state !== "waiting") return void 0;
@@ -2072,15 +2295,26 @@ export {
2072
2295
  forwardBridgeProcessStream,
2073
2296
  generateSandboxCredentialPlaceholder,
2074
2297
  getAiGatewayAuthFromEnv,
2298
+ getJwtExpiresAt,
2075
2299
  getRestrictedSandboxSession,
2300
+ isAccessTokenExpiringSoon,
2076
2301
  isHarnessAuthenticationEnvironment,
2302
+ isLinux,
2303
+ isMacOS,
2077
2304
  isSandboxCredentialPlaceholder,
2305
+ isWindows,
2078
2306
  logBridgeError,
2079
2307
  markBridgeStarting,
2080
2308
  maskSandboxCredentials,
2309
+ parseJwtPayload,
2310
+ readLinuxSecretServicePassword,
2311
+ readMacOSKeychainPassword,
2312
+ readWindowsCredentialManagerPassword,
2313
+ refreshOAuthAccessToken,
2081
2314
  resolveSandboxDefaultWorkingDirectory,
2082
2315
  resolveSandboxHomeDir,
2083
2316
  shellQuote,
2317
+ shouldResolveNativeSubscription,
2084
2318
  waitForBridgeReady,
2085
2319
  warnCredentialBrokeringUnavailable,
2086
2320
  withBridgeToken,