@ai-sdk/harness-acp 1.0.25 → 1.0.28

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,32 @@
1
1
  # @ai-sdk/harness-acp
2
2
 
3
+ ## 1.0.28
4
+
5
+ ### Patch Changes
6
+
7
+ - 0e590d2: feat(harness): harden credential brokering to only apply with correct ephemeral secret
8
+ - Updated dependencies [3e125ba]
9
+ - Updated dependencies [0e590d2]
10
+ - @ai-sdk/provider-utils@5.0.32
11
+ - @ai-sdk/harness@1.0.90
12
+
13
+ ## 1.0.27
14
+
15
+ ### Patch Changes
16
+
17
+ - @ai-sdk/harness@1.0.89
18
+
19
+ ## 1.0.26
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [32349cc]
24
+ - Updated dependencies [a9782e1]
25
+ - Updated dependencies [35841f5]
26
+ - Updated dependencies [d2f3353]
27
+ - @ai-sdk/harness@1.0.88
28
+ - @ai-sdk/provider-utils@5.0.31
29
+
3
30
  ## 1.0.25
4
31
 
5
32
  ### Patch Changes
package/README.md CHANGED
@@ -35,13 +35,20 @@ const codexACP = createACP({
35
35
  },
36
36
  executable: 'codex-acp',
37
37
  credentialEnv: ['CODEX_API_KEY', 'OPENAI_API_KEY'],
38
- credentialBrokering: ({ env }) => {
39
- const credential = env.CODEX_API_KEY ?? env.OPENAI_API_KEY;
40
- if (!credential) return [];
38
+ credentialBrokering: ({ env, sandboxEnv }) => {
39
+ const environmentVariableName = env.CODEX_API_KEY
40
+ ? 'CODEX_API_KEY'
41
+ : 'OPENAI_API_KEY';
42
+ const credential = env[environmentVariableName];
43
+ const sandboxCredential = sandboxEnv?.[environmentVariableName];
44
+ if (!credential || !sandboxCredential) return [];
41
45
  return [
42
46
  createCredentialRequestTransformation({
43
- baseUrl: 'https://api.openai.com/v1',
44
- headers: { Authorization: `Bearer ${credential}` },
47
+ matchUrl: 'https://api.openai.com/v1',
48
+ matchHeaders: {
49
+ Authorization: `Bearer ${sandboxCredential}`,
50
+ },
51
+ transformHeaders: { Authorization: `Bearer ${credential}` },
45
52
  }),
46
53
  ];
47
54
  },
@@ -82,7 +89,8 @@ try {
82
89
 
83
90
  Set `CODEX_API_KEY` or `OPENAI_API_KEY` in the host environment. Sandboxes that
84
91
  support additive request transformations receive only credential placeholders;
85
- the real value is injected into matching outbound requests. Other sandboxes
92
+ the real value is injected only when a matching outbound request contains the
93
+ expected placeholder. Other sandboxes
86
94
  retain the legacy behavior of forwarding the value to the ACP process. Codex
87
95
  ACP supports only `permissionMode: 'allow-all'` because its
88
96
  restrictive modes enable Codex's internal sandbox. A bridge-backed ACP harness
@@ -12,7 +12,7 @@ import {
12
12
  ListToolsRequestSchema,
13
13
  McpError
14
14
  } from "@modelcontextprotocol/sdk/types.js";
15
- var VERSION = true ? "1.0.25" : "0.0.0-test";
15
+ var VERSION = true ? "1.0.28" : "0.0.0-test";
16
16
  function createHostToolMCPServer({
17
17
  tools: tools2,
18
18
  revision = 1,
package/dist/index.d.ts CHANGED
@@ -145,8 +145,9 @@ type ACPProviderAuthentication = {
145
145
  readonly env: Readonly<Record<string, ACPProfileValue>>;
146
146
  };
147
147
  };
148
- type ACPCredentialBrokering = ({ env, }: {
148
+ type ACPCredentialBrokering = ({ env, sandboxEnv, }: {
149
149
  env: Readonly<Record<string, string>>;
150
+ sandboxEnv?: Readonly<Record<string, string>>;
150
151
  }) => ReadonlyArray<HarnessV1RequestTransformation>;
151
152
  type ACPPermissionModeTarget = {
152
153
  readonly type: 'session-mode';
package/dist/index.js CHANGED
@@ -13,12 +13,12 @@ import {
13
13
  applyCredentialForwarding,
14
14
  createBridgeErrorHandler,
15
15
  createBridgeStartupError,
16
+ createSandboxCredentialEnvironment,
16
17
  classifyDiskLog,
17
18
  drainBridgeProcessStream,
18
19
  forwardBridgeProcessStream,
19
20
  getRestrictedSandboxSession,
20
21
  markBridgeStarting,
21
- maskSandboxCredentials,
22
22
  resolveSandboxDefaultWorkingDirectory,
23
23
  resolveSandboxHomeDir,
24
24
  SandboxChannel,
@@ -1318,6 +1318,21 @@ function createACPV1({
1318
1318
  sandboxSession,
1319
1319
  abortSignal: startOptions.abortSignal
1320
1320
  });
1321
+ const continueFrom = startOptions.continueFrom ?? startOptions.resumeFrom?.continueFrom;
1322
+ const lifecycleState = continueFrom ?? startOptions.resumeFrom;
1323
+ const isContinue = continueFrom != null;
1324
+ const isResume = lifecycleState != null;
1325
+ const lifecycleData = lifecycleState != null ? lifecycleState.data : void 0;
1326
+ if (lifecycleData != null && lifecycleState != null) {
1327
+ validateACPLifecycleCompatibility({
1328
+ harnessId: settings.harnessId,
1329
+ lifecycleHarnessId: lifecycleState.harnessId,
1330
+ implementationIdentity,
1331
+ authenticationProfile,
1332
+ lifecycleData,
1333
+ sandboxId
1334
+ });
1335
+ }
1321
1336
  const implementationEnvironment = resolveImplementationEnvironment({
1322
1337
  implementation,
1323
1338
  env
@@ -1340,30 +1355,35 @@ function createACPV1({
1340
1355
  })
1341
1356
  ])
1342
1357
  ];
1358
+ let sandboxCredentialEnvironment;
1343
1359
  if (settings.credentialBrokering != null && "addRequestTransformations" in sandboxSession && sandboxSession.addRequestTransformations != null) {
1344
1360
  const providerEnvironment = resolveProviderEnvironment({
1345
1361
  resolvedProviderAuthentication,
1346
1362
  clientApp
1347
1363
  });
1364
+ const brokeringEnvironment = {
1365
+ ...implementationEnvironment,
1366
+ ...providerEnvironment
1367
+ };
1368
+ sandboxCredentialEnvironment = lifecycleData?.sandboxCredentialEnvironment ?? await createSandboxCredentialEnvironment({
1369
+ environment: brokeringEnvironment,
1370
+ credentialEnvironmentVariables: credentialForwardingEnvironmentVariables,
1371
+ credentialForwarding: settings.credentialForwarding
1372
+ });
1373
+ sandboxImplementationEnvironment = {
1374
+ ...brokeringEnvironment,
1375
+ ...sandboxCredentialEnvironment
1376
+ };
1348
1377
  const requestTransformations = settings.credentialBrokering({
1349
- env: {
1350
- ...implementationEnvironment,
1351
- ...providerEnvironment
1352
- }
1378
+ env: brokeringEnvironment,
1379
+ sandboxEnv: sandboxImplementationEnvironment
1353
1380
  });
1354
1381
  if (requestTransformations.length > 0) {
1355
1382
  await sandboxSession.addRequestTransformations(
1356
1383
  requestTransformations
1357
1384
  );
1358
1385
  }
1359
- sandboxImplementationEnvironment = maskSandboxCredentials({
1360
- environment: implementationEnvironment,
1361
- credentialEnvironmentVariables
1362
- });
1363
- sandboxProviderEnvironment = resolveBrokeredProviderEnvironment({
1364
- resolvedProviderAuthentication,
1365
- clientApp
1366
- });
1386
+ sandboxProviderEnvironment = resolvedProviderAuthentication.providerAuthentication?.type === "ai-gateway" ? {} : void 0;
1367
1387
  } else if (settings.credentialBrokering != null) {
1368
1388
  warnCredentialBrokeringUnavailable();
1369
1389
  }
@@ -1401,21 +1421,6 @@ function createACPV1({
1401
1421
  sessionId: startOptions.sessionId
1402
1422
  });
1403
1423
  const bridgeStateDir = `${privateSessionDir}/bridge`;
1404
- const continueFrom = startOptions.continueFrom ?? startOptions.resumeFrom?.continueFrom;
1405
- const lifecycleState = continueFrom ?? startOptions.resumeFrom;
1406
- const isContinue = continueFrom != null;
1407
- const isResume = lifecycleState != null;
1408
- const lifecycleData = lifecycleState != null ? lifecycleState.data : void 0;
1409
- if (lifecycleData != null && lifecycleState != null) {
1410
- validateACPLifecycleCompatibility({
1411
- harnessId: settings.harnessId,
1412
- lifecycleHarnessId: lifecycleState.harnessId,
1413
- implementationIdentity,
1414
- authenticationProfile,
1415
- lifecycleData,
1416
- sandboxId
1417
- });
1418
- }
1419
1424
  const skills = startOptions.skills ?? [];
1420
1425
  const skillsFingerprint = createACPSkillsFingerprint({ skills });
1421
1426
  const shouldMaterializeSkills = shouldMaterializeACPSkills({
@@ -1513,6 +1518,7 @@ function createACPV1({
1513
1518
  turnStartConfig: lifecycleData.turnStartConfig,
1514
1519
  recoveryStatus: lifecycleData.recovery,
1515
1520
  restoration: lifecycleData.restoration,
1521
+ sandboxCredentialEnvironment,
1516
1522
  replayOnly: false,
1517
1523
  lossyRerun: false
1518
1524
  });
@@ -1590,11 +1596,11 @@ function createACPV1({
1590
1596
  };
1591
1597
  }
1592
1598
  }
1593
- const forwardedImplementationEnvironment = await applyCredentialForwarding({
1599
+ const forwardedImplementationEnvironment = sandboxCredentialEnvironment == null ? await applyCredentialForwarding({
1594
1600
  environment: sandboxImplementationEnvironment,
1595
1601
  credentialEnvironmentVariables: credentialForwardingEnvironmentVariables,
1596
1602
  credentialForwarding: settings.credentialForwarding
1597
- });
1603
+ }) : sandboxImplementationEnvironment;
1598
1604
  const port = resolveBridgePort({
1599
1605
  sandboxSession,
1600
1606
  override: portOverride,
@@ -1753,6 +1759,7 @@ function createACPV1({
1753
1759
  reason: respawnStrategy.reason
1754
1760
  } : void 0,
1755
1761
  restoration: coldRestoration == null ? lifecycleData?.restoration : { method: coldRestoration },
1762
+ sandboxCredentialEnvironment,
1756
1763
  replayOnly: respawnStrategy?.mode === "disk-replay",
1757
1764
  lossyRerun: respawnStrategy?.mode === "lossy-rerun"
1758
1765
  });
@@ -1782,36 +1789,6 @@ function resolveProviderEnvironment({
1782
1789
  }
1783
1790
  });
1784
1791
  }
1785
- function resolveBrokeredProviderEnvironment({
1786
- resolvedProviderAuthentication,
1787
- clientApp
1788
- }) {
1789
- const providerAuthentication = resolvedProviderAuthentication.providerAuthentication;
1790
- if (providerAuthentication?.type !== "ai-gateway") return {};
1791
- const baseUrl = requireResolvedEnvironmentValue({
1792
- environment: resolvedProviderAuthentication.env,
1793
- name: "AI_SDK_ACP_GATEWAY_BASE_URL"
1794
- });
1795
- return Object.fromEntries(
1796
- Object.entries(providerAuthentication.env).map(
1797
- ([environmentVariableName, value]) => {
1798
- const environment = resolveACPLaunchEnvironment({
1799
- providerAuthentication: {
1800
- type: "ai-gateway",
1801
- env: { [environmentVariableName]: value }
1802
- },
1803
- gateway: {
1804
- apiKey: environmentVariableName,
1805
- baseUrl,
1806
- clientAppName: clientApp.name,
1807
- clientAppVersion: clientApp.version
1808
- }
1809
- });
1810
- return [environmentVariableName, environment[environmentVariableName]];
1811
- }
1812
- )
1813
- );
1814
- }
1815
1792
  function resolveACPProviderCredentialEnvironmentVariables({
1816
1793
  providerAuthentication
1817
1794
  }) {
@@ -2018,6 +1995,7 @@ function createSession({
2018
1995
  turnStartConfig: turnStartConfigAtStart,
2019
1996
  recoveryStatus,
2020
1997
  restoration,
1998
+ sandboxCredentialEnvironment,
2021
1999
  replayOnly,
2022
2000
  lossyRerun
2023
2001
  }) {
@@ -2253,6 +2231,7 @@ function createSession({
2253
2231
  }) => ({
2254
2232
  implementationIdentity,
2255
2233
  authenticationProfile,
2234
+ ...sandboxCredentialEnvironment == null ? {} : { sandboxCredentialEnvironment },
2256
2235
  ...latestACPSessionId == null ? {} : { acpSessionId: latestACPSessionId },
2257
2236
  ...bridge == null ? {} : { bridge },
2258
2237
  ...latestTurnStartConfig == null ? {} : {
@@ -2632,7 +2611,7 @@ function deserializeBridgeError({
2632
2611
  }
2633
2612
 
2634
2613
  // src/version.ts
2635
- var VERSION = true ? "1.0.25" : "0.0.0-test";
2614
+ var VERSION = true ? "1.0.28" : "0.0.0-test";
2636
2615
 
2637
2616
  // src/acp-harness.ts
2638
2617
  var ACP_CLIENT_APP = {
@@ -2658,6 +2637,7 @@ var acpResumeStateSchema = z4.object({
2658
2637
  providerMode: z4.enum(["auto", "direct", "ai-gateway"]).optional(),
2659
2638
  gatewayCredentialSource: z4.enum(["AI_GATEWAY_API_KEY", "VERCEL_OIDC_TOKEN"]).nullable().optional()
2660
2639
  }).optional(),
2640
+ sandboxCredentialEnvironment: z4.record(z4.string(), z4.string()).optional(),
2661
2641
  acpSessionId: z4.string().optional(),
2662
2642
  bridge: acpBridgeCoordsSchema.optional(),
2663
2643
  coldSession: acpColdSessionStateSchema.optional(),