diff --git a/packages/cloud-agent-sdk/src/cli-live-transport.test.ts b/packages/cloud-agent-sdk/src/cli-live-transport.test.ts index b6d35b5ea3..7aa79d0382 100644 --- a/packages/cloud-agent-sdk/src/cli-live-transport.test.ts +++ b/packages/cloud-agent-sdk/src/cli-live-transport.test.ts @@ -7,6 +7,7 @@ import type { RemoteModelState, } from './remote-model-catalog'; import type { RemoteCommandState } from './remote-command-catalog'; +import { configureCloudAgentSdkRuntime, resetCloudAgentSdkRuntime } from './runtime'; import { CommandDeliveredError, UserWebCommandError, @@ -2688,6 +2689,37 @@ describe('CliLiveTransport createSession', () => { expect(secondMutationId).not.toBe(firstMutationId); transport.destroy(); }); + + it('takes the mutationId from the configured runtime, not the global crypto', async () => { + // Hermes (React Native) has no global `crypto` binding, so a bare + // `crypto.randomUUID()` throws "Property crypto does not exist" and /new + // fails. Every id in this package must go through the runtime shim. + configureCloudAgentSdkRuntime({ randomUUID: () => 'runtime-uuid' }); + try { + const connection = createConnection(); + jest + .mocked(connection.sendCommand) + .mockResolvedValue({ protocolVersion: 1, sessionID: NEW_KILO_SESSION_ID }); + const { transport, userWebConnection } = createTransportWithSinks({ connection }); + + transport.connect(); + emitOwner(connection); + await Promise.resolve(); + await Promise.resolve(); + await Promise.resolve(); + + jest.mocked(userWebConnection.sendCommand).mockClear(); + await transport.createSession?.(); + + const createCall = jest + .mocked(userWebConnection.sendCommand) + .mock.calls.find(([, command]) => command === 'create_session'); + expect(createCall?.[4]).toBe('runtime-uuid'); + transport.destroy(); + } finally { + resetCloudAgentSdkRuntime(); + } + }); }); describe('CliLiveTransport exitSession', () => { diff --git a/packages/cloud-agent-sdk/src/cli-live-transport.ts b/packages/cloud-agent-sdk/src/cli-live-transport.ts index ebda25fc70..fc959f5e65 100644 --- a/packages/cloud-agent-sdk/src/cli-live-transport.ts +++ b/packages/cloud-agent-sdk/src/cli-live-transport.ts @@ -5,6 +5,7 @@ import { normalizeCliEvent, isChatEvent } from './normalizer'; import { parseRemoteCommandCatalog, type RemoteCommandState } from './remote-command-catalog'; import { parseCreateSessionResponse } from './create-session'; +import { cloudAgentSdkRuntime } from './runtime'; import { parseExitSessionResponse } from './exit-session'; import { cliConnectionDataSchema, @@ -875,7 +876,7 @@ function createCliLiveTransport(config: CliLiveTransportConfig): TransportFactor // snapshotted before the await and SESSION_OWNER_CHANGED is handled. // Extended fields degrade via a single bare retry on the exact // old-CLI delivered error; other failures are hard rejects. - const mutationId = input?.mutationId ?? crypto.randomUUID(); + const mutationId = input?.mutationId ?? cloudAgentSdkRuntime.randomUUID(); const wireData = buildCreateSessionWireData(input); const hasExtendedFields = wireData.agent !== undefined || @@ -895,7 +896,7 @@ function createCliLiveTransport(config: CliLiveTransportConfig): TransportFactor result = await sendCommand( 'create_session', { protocolVersion: 1 }, - crypto.randomUUID() + cloudAgentSdkRuntime.randomUUID() ); } else { throw error;