Skip to content

Commit 843e5c0

Browse files
Use RPC from json schema
1 parent c4f7090 commit 843e5c0

7 files changed

Lines changed: 147 additions & 128 deletions

File tree

nodejs/src/client.ts

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
StreamMessageWriter,
2525
} from "vscode-jsonrpc/node.js";
2626
import { createServerRpc, registerClientApiHandlers } from "./generated/rpc.js";
27-
import type { SessionStoreHandler } from "./generated/rpc.js";
27+
import type { SessionDataStoreHandler } from "./generated/rpc.js";
2828
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
2929
import { CopilotSession, NO_RESULT_PERMISSION_V2_ERROR } from "./session.js";
3030
import { getTraceContext } from "./telemetry.js";
@@ -45,7 +45,7 @@ import type {
4545
SessionLifecycleHandler,
4646
SessionListFilter,
4747
SessionMetadata,
48-
SessionStoreConfig,
48+
SessionDataStoreConfig,
4949
TelemetryConfig,
5050
Tool,
5151
ToolCallRequestPayload,
@@ -156,6 +156,7 @@ export class CopilotClient {
156156
| "onListModels"
157157
| "telemetry"
158158
| "onGetTraceContext"
159+
| "sessionDataStore"
159160
>
160161
> & {
161162
cliPath?: string;
@@ -178,8 +179,8 @@ export class CopilotClient {
178179
private _rpc: ReturnType<typeof createServerRpc> | null = null;
179180
private processExitPromise: Promise<never> | null = null; // Rejects when CLI process exits
180181
private negotiatedProtocolVersion: number | null = null;
181-
/** Connection-level storage provider config set via setStorageProvider(). */
182-
private storageProviderConfig: SessionStoreConfig | null = null;
182+
/** Connection-level session data store config, set via constructor option. */
183+
private sessionDataStoreConfig: SessionDataStoreConfig | null = null;
183184

184185
/**
185186
* Typed server-scoped RPC methods.
@@ -249,6 +250,7 @@ export class CopilotClient {
249250

250251
this.onListModels = options.onListModels;
251252
this.onGetTraceContext = options.onGetTraceContext;
253+
this.sessionDataStoreConfig = options.sessionDataStore ?? null;
252254

253255
this.options = {
254256
cliPath: options.cliUrl ? undefined : options.cliPath || getBundledCliPath(),
@@ -338,47 +340,20 @@ export class CopilotClient {
338340
// Verify protocol version compatibility
339341
await this.verifyProtocolVersion();
340342

343+
// If a session data store was configured, register as the storage provider
344+
if (this.sessionDataStoreConfig) {
345+
await this.connection!.sendRequest("sessionDataStore.setDataStore", {
346+
descriptor: this.sessionDataStoreConfig.descriptor,
347+
});
348+
}
349+
341350
this.state = "connected";
342351
} catch (error) {
343352
this.state = "error";
344353
throw error;
345354
}
346355
}
347356

348-
/**
349-
* Declare this client as the session data storage provider.
350-
* Must be called before creating any sessions. Only one client can be the
351-
* storage provider at a time.
352-
*
353-
* @param config - The storage provider configuration with callbacks for persistence
354-
* @throws Error if the client is not connected and autoStart is disabled
355-
*
356-
* @example
357-
* ```typescript
358-
* await client.setStorageProvider({
359-
* descriptor: "redis://localhost/sessions",
360-
* onLoad: async (sessionId) => loadEventsFromRedis(sessionId),
361-
* onAppend: async (events, sessionId) => appendEventsToRedis(events, sessionId),
362-
* onTruncate: async (upToEventId, sessionId) => truncateEventsInRedis(upToEventId, sessionId),
363-
* onListSessions: async () => listSessionsFromRedis(),
364-
* onDelete: async (sessionId) => deleteSessionFromRedis(sessionId),
365-
* });
366-
* ```
367-
*/
368-
async setStorageProvider(config: SessionStoreConfig): Promise<void> {
369-
if (!this.connection) {
370-
if (this.options.autoStart) {
371-
await this.start();
372-
} else {
373-
throw new Error("Client not connected. Call start() first.");
374-
}
375-
}
376-
await this.connection!.sendRequest("session.setStorageProvider", {
377-
descriptor: config.descriptor,
378-
});
379-
this.storageProviderConfig = config;
380-
}
381-
382357
/**
383358
* Stops the CLI server and closes all active sessions.
384359
*
@@ -436,7 +411,6 @@ export class CopilotClient {
436411
}
437412
}
438413
this.sessions.clear();
439-
this.storageProviderConfig = null;
440414

441415
// Close connection
442416
if (this.connection) {
@@ -521,7 +495,6 @@ export class CopilotClient {
521495

522496
// Clear sessions immediately without trying to destroy them
523497
this.sessions.clear();
524-
this.storageProviderConfig = null;
525498

526499
// Force close connection
527500
if (this.connection) {
@@ -1506,10 +1479,9 @@ export class CopilotClient {
15061479
}): Promise<{ output?: unknown }> => await this.handleHooksInvoke(params)
15071480
);
15081481

1509-
// Register session store RPC handlers via generated registration function.
1510-
// The handler routes each call to the appropriate SessionStoreConfig based on sessionId.
1482+
// Register session data store RPC handlers via generated registration function.
15111483
registerClientApiHandlers(this.connection, {
1512-
sessionStore: this.createSessionStoreHandler(),
1484+
sessionDataStore: this.createSessionDataStoreHandler(),
15131485
});
15141486

15151487
this.connection.onClose(() => {
@@ -1522,15 +1494,15 @@ export class CopilotClient {
15221494
}
15231495

15241496
/**
1525-
* Create a {@link SessionStoreHandler} that routes each RPC call to the
1526-
* connection-level storage provider set via {@link setStorageProvider}.
1497+
* Create a {@link SessionDataStoreHandler} that routes each RPC call to the
1498+
* connection-level session data store set via constructor option.
15271499
*/
1528-
private createSessionStoreHandler(): SessionStoreHandler {
1529-
const getStore = (): SessionStoreConfig => {
1530-
if (!this.storageProviderConfig) {
1531-
throw new Error("No storage provider configured. Call setStorageProvider() first.");
1500+
private createSessionDataStoreHandler(): SessionDataStoreHandler {
1501+
const getStore = (): SessionDataStoreConfig => {
1502+
if (!this.sessionDataStoreConfig) {
1503+
throw new Error("No session data store configured.");
15321504
}
1533-
return this.storageProviderConfig;
1505+
return this.sessionDataStoreConfig;
15341506
};
15351507

15361508
return {

nodejs/src/generated/rpc.ts

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,20 @@ export interface AccountGetQuotaResult {
179179
};
180180
}
181181

182+
export interface SessionDataStoreSetDataStoreResult {
183+
/**
184+
* Whether the data store was set successfully
185+
*/
186+
success: boolean;
187+
}
188+
189+
export interface SessionDataStoreSetDataStoreParams {
190+
/**
191+
* Opaque descriptor identifying the storage backend (e.g., 'redis://localhost/sessions')
192+
*/
193+
descriptor: string;
194+
}
195+
182196
export interface SessionModelGetCurrentResult {
183197
/**
184198
* Currently active model identifier
@@ -1010,7 +1024,7 @@ export interface SessionShellKillParams {
10101024
signal?: "SIGTERM" | "SIGKILL" | "SIGINT";
10111025
}
10121026

1013-
export interface SessionStoreLoadResult {
1027+
export interface SessionDataStoreLoadResult {
10141028
/**
10151029
* All persisted events for the session, in order
10161030
*/
@@ -1019,14 +1033,14 @@ export interface SessionStoreLoadResult {
10191033
}[];
10201034
}
10211035

1022-
export interface SessionStoreLoadParams {
1036+
export interface SessionDataStoreLoadParams {
10231037
/**
10241038
* The session to load events for
10251039
*/
10261040
sessionId: string;
10271041
}
10281042

1029-
export interface SessionStoreAppendParams {
1043+
export interface SessionDataStoreAppendParams {
10301044
/**
10311045
* The session to append events to
10321046
*/
@@ -1039,7 +1053,7 @@ export interface SessionStoreAppendParams {
10391053
}[];
10401054
}
10411055

1042-
export interface SessionStoreTruncateResult {
1056+
export interface SessionDataStoreTruncateResult {
10431057
/**
10441058
* Number of events removed
10451059
*/
@@ -1050,7 +1064,7 @@ export interface SessionStoreTruncateResult {
10501064
eventsKept: number;
10511065
}
10521066

1053-
export interface SessionStoreTruncateParams {
1067+
export interface SessionDataStoreTruncateParams {
10541068
/**
10551069
* The session to truncate
10561070
*/
@@ -1061,7 +1075,7 @@ export interface SessionStoreTruncateParams {
10611075
upToEventId: string;
10621076
}
10631077

1064-
export interface SessionStoreListResult {
1078+
export interface SessionDataStoreListResult {
10651079
sessions: {
10661080
sessionId: string;
10671081
/**
@@ -1075,7 +1089,7 @@ export interface SessionStoreListResult {
10751089
}[];
10761090
}
10771091

1078-
export interface SessionStoreDeleteParams {
1092+
export interface SessionDataStoreDeleteParams {
10791093
/**
10801094
* The session to delete
10811095
*/
@@ -1099,6 +1113,10 @@ export function createServerRpc(connection: MessageConnection) {
10991113
getQuota: async (): Promise<AccountGetQuotaResult> =>
11001114
connection.sendRequest("account.getQuota", {}),
11011115
},
1116+
sessionDataStore: {
1117+
setDataStore: async (params: SessionDataStoreSetDataStoreParams): Promise<SessionDataStoreSetDataStoreResult> =>
1118+
connection.sendRequest("sessionDataStore.setDataStore", params),
1119+
},
11021120
};
11031121
}
11041122

@@ -1215,20 +1233,20 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin
12151233
}
12161234

12171235
/**
1218-
* Handler interface for the `sessionStore` client API group.
1219-
* Implement this to provide a custom sessionStore backend.
1236+
* Handler interface for the `sessionDataStore` client API group.
1237+
* Implement this to provide a custom sessionDataStore backend.
12201238
*/
1221-
export interface SessionStoreHandler {
1222-
load(params: SessionStoreLoadParams): Promise<SessionStoreLoadResult>;
1223-
append(params: SessionStoreAppendParams): Promise<void>;
1224-
truncate(params: SessionStoreTruncateParams): Promise<SessionStoreTruncateResult>;
1225-
list(): Promise<SessionStoreListResult>;
1226-
delete(params: SessionStoreDeleteParams): Promise<void>;
1239+
export interface SessionDataStoreHandler {
1240+
load(params: SessionDataStoreLoadParams): Promise<SessionDataStoreLoadResult>;
1241+
append(params: SessionDataStoreAppendParams): Promise<void>;
1242+
truncate(params: SessionDataStoreTruncateParams): Promise<SessionDataStoreTruncateResult>;
1243+
list(): Promise<SessionDataStoreListResult>;
1244+
delete(params: SessionDataStoreDeleteParams): Promise<void>;
12271245
}
12281246

12291247
/** All client API handler groups. Each group is optional. */
12301248
export interface ClientApiHandlers {
1231-
sessionStore?: SessionStoreHandler;
1249+
sessionDataStore?: SessionDataStoreHandler;
12321250
}
12331251

12341252
/**
@@ -1241,12 +1259,12 @@ export function registerClientApiHandlers(
12411259
connection: MessageConnection,
12421260
handlers: ClientApiHandlers,
12431261
): void {
1244-
if (handlers.sessionStore) {
1245-
const h = handlers.sessionStore!;
1246-
connection.onRequest("sessionStore.load", (params: SessionStoreLoadParams) => h.load(params));
1247-
connection.onRequest("sessionStore.append", (params: SessionStoreAppendParams) => h.append(params));
1248-
connection.onRequest("sessionStore.truncate", (params: SessionStoreTruncateParams) => h.truncate(params));
1249-
connection.onRequest("sessionStore.list", () => h.list());
1250-
connection.onRequest("sessionStore.delete", (params: SessionStoreDeleteParams) => h.delete(params));
1262+
if (handlers.sessionDataStore) {
1263+
const h = handlers.sessionDataStore!;
1264+
connection.onRequest("sessionDataStore.load", (params: SessionDataStoreLoadParams) => h.load(params));
1265+
connection.onRequest("sessionDataStore.append", (params: SessionDataStoreAppendParams) => h.append(params));
1266+
connection.onRequest("sessionDataStore.truncate", (params: SessionDataStoreTruncateParams) => h.truncate(params));
1267+
connection.onRequest("sessionDataStore.list", () => h.list());
1268+
connection.onRequest("sessionDataStore.delete", (params: SessionDataStoreDeleteParams) => h.delete(params));
12511269
}
12521270
}

nodejs/src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@ export type {
4343
SessionContext,
4444
SessionListFilter,
4545
SessionMetadata,
46-
SessionStoreConfig,
47-
SessionStoreHandler,
48-
StorageProviderConfig,
46+
SessionDataStoreConfig,
47+
SessionDataStoreHandler,
4948
ClientApiHandlers,
5049
SystemMessageAppendConfig,
5150
SystemMessageConfig,

nodejs/src/types.ts

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ export type SessionEvent = GeneratedSessionEvent;
1212

1313
// Re-export generated client API types
1414
export type {
15-
SessionStoreHandler,
16-
SessionStoreLoadParams,
17-
SessionStoreLoadResult,
18-
SessionStoreAppendParams,
19-
SessionStoreTruncateParams,
20-
SessionStoreTruncateResult,
21-
SessionStoreListResult,
22-
SessionStoreDeleteParams,
15+
SessionDataStoreHandler,
16+
SessionDataStoreLoadParams,
17+
SessionDataStoreLoadResult,
18+
SessionDataStoreAppendParams,
19+
SessionDataStoreTruncateParams,
20+
SessionDataStoreTruncateResult,
21+
SessionDataStoreListResult,
22+
SessionDataStoreDeleteParams,
2323
ClientApiHandlers,
2424
} from "./generated/rpc.js";
2525

@@ -184,6 +184,14 @@ export interface CopilotClientOptions {
184184
* ```
185185
*/
186186
onGetTraceContext?: TraceContextProvider;
187+
188+
/**
189+
* Custom session data storage backend.
190+
* When provided, the client registers as the session data storage provider
191+
* on connection, routing all event persistence through these callbacks
192+
* instead of the server's default file-based storage.
193+
*/
194+
sessionDataStore?: SessionDataStoreConfig;
187195
}
188196

189197
/**
@@ -1021,19 +1029,14 @@ export interface SessionContext {
10211029
}
10221030

10231031
/**
1024-
* Callbacks for a session event store. When provided to {@link SessionConfig.sessionStore},
1025-
* the server routes all event persistence through these callbacks over RPC instead
1026-
* of using its default file-based storage.
1027-
*/
1028-
/**
1029-
* Configuration for a custom session store backend.
1032+
* Configuration for a custom session data store backend.
10301033
*
10311034
* The `descriptor` identifies the storage backend. The callback methods
1032-
* correspond to the generated {@link SessionStoreHandler} interface but
1035+
* correspond to the generated {@link SessionDataStoreHandler} interface but
10331036
* use a consumer-friendly signature where `sessionId` is a plain argument
10341037
* rather than embedded in a params object.
10351038
*/
1036-
export interface SessionStoreConfig {
1039+
export interface SessionDataStoreConfig {
10371040
/**
10381041
* Opaque descriptor identifying this storage backend.
10391042
* Used for UI display (e.g., `"redis://localhost/sessions"`).
@@ -1069,13 +1072,6 @@ export interface ListSessionsOptions {
10691072
filter?: SessionListFilter;
10701073
}
10711074

1072-
/**
1073-
* Configuration for becoming the session data storage provider.
1074-
* Same shape as SessionStoreConfig — call client.setStorageProvider(config)
1075-
* to claim storage before creating sessions.
1076-
*/
1077-
export type StorageProviderConfig = SessionStoreConfig;
1078-
10791075
/**
10801076
* Filter options for listing sessions
10811077
*/

0 commit comments

Comments
 (0)