Fix session ID handling and cleanup in copilot-sdk
Co-authored-by: htekdev <100806365+htekdev@users.noreply.github.com>
This commit is contained in:
parent
0e28bf70cd
commit
119cac7543
13441
package-lock.json
generated
Normal file
13441
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -141,12 +141,18 @@ export async function runCopilotCliAgent(params: {
|
|||||||
const text = result.text?.trim();
|
const text = result.text?.trim();
|
||||||
const payloads = text ? [{ text }] : undefined;
|
const payloads = text ? [{ text }] : undefined;
|
||||||
|
|
||||||
|
// When resuming a session, the SDK's sessionId should be authoritative.
|
||||||
|
// For new sessions, fall back to params.sessionId if SDK doesn't return one.
|
||||||
|
const resolvedSessionId = params.cliSessionId
|
||||||
|
? result.sessionId // Resuming: use SDK's session ID
|
||||||
|
: (result.sessionId ?? params.sessionId ?? ""); // New: SDK or fallback
|
||||||
|
|
||||||
return {
|
return {
|
||||||
payloads,
|
payloads,
|
||||||
meta: {
|
meta: {
|
||||||
durationMs: Date.now() - started,
|
durationMs: Date.now() - started,
|
||||||
agentMeta: {
|
agentMeta: {
|
||||||
sessionId: result.sessionId ?? params.sessionId ?? "",
|
sessionId: resolvedSessionId,
|
||||||
provider,
|
provider,
|
||||||
model: modelId,
|
model: modelId,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -18,13 +18,7 @@ import { isCopilotCliInstalled, readCopilotAuthStatusCached } from "./copilot-cr
|
|||||||
const log = createSubsystemLogger("agents/copilot-sdk");
|
const log = createSubsystemLogger("agents/copilot-sdk");
|
||||||
|
|
||||||
// Re-export SDK types that consumers may need.
|
// Re-export SDK types that consumers may need.
|
||||||
export type {
|
export type { CopilotClient, CopilotClientOptions, CopilotSession, SessionConfig, SessionEvent };
|
||||||
CopilotClient,
|
|
||||||
CopilotClientOptions,
|
|
||||||
CopilotSession,
|
|
||||||
SessionConfig,
|
|
||||||
SessionEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for creating a Moltbot-configured Copilot client.
|
* Options for creating a Moltbot-configured Copilot client.
|
||||||
@ -149,10 +143,12 @@ export type CopilotAgentResult = {
|
|||||||
* Creates a client, starts a session, sends the prompt, waits for completion,
|
* Creates a client, starts a session, sends the prompt, waits for completion,
|
||||||
* and cleans up. For multi-turn conversations, pass the returned `sessionId`
|
* and cleans up. For multi-turn conversations, pass the returned `sessionId`
|
||||||
* back in subsequent calls.
|
* back in subsequent calls.
|
||||||
|
*
|
||||||
|
* Note: When resuming a session, model and system prompt settings from the
|
||||||
|
* original session are preserved. New configuration values are not applied
|
||||||
|
* during resumption.
|
||||||
*/
|
*/
|
||||||
export async function runCopilotAgent(
|
export async function runCopilotAgent(params: RunCopilotAgentParams): Promise<CopilotAgentResult> {
|
||||||
params: RunCopilotAgentParams,
|
|
||||||
): Promise<CopilotAgentResult> {
|
|
||||||
const started = Date.now();
|
const started = Date.now();
|
||||||
const events: SessionEvent[] = [];
|
const events: SessionEvent[] = [];
|
||||||
let finalText = "";
|
let finalText = "";
|
||||||
@ -163,17 +159,20 @@ export async function runCopilotAgent(
|
|||||||
env: params.env,
|
env: params.env,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let session: CopilotSession | null = null;
|
||||||
|
let unsubscribe: (() => void) | null = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Start the client
|
// Start the client
|
||||||
await client.start();
|
await client.start();
|
||||||
|
|
||||||
// Configure session
|
// Configure session for new sessions
|
||||||
const sessionConfig: SessionConfig = {
|
const sessionConfig: SessionConfig = {
|
||||||
model: params.model,
|
model: params.model,
|
||||||
sessionId: params.sessionId,
|
sessionId: params.sessionId,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add system message if provided
|
// Add system message if provided (only applies to new sessions)
|
||||||
if (params.systemPrompt) {
|
if (params.systemPrompt) {
|
||||||
sessionConfig.systemMessage = {
|
sessionConfig.systemMessage = {
|
||||||
mode: "append",
|
mode: "append",
|
||||||
@ -182,7 +181,9 @@ export async function runCopilotAgent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create or resume session
|
// Create or resume session
|
||||||
let session: CopilotSession;
|
// Note: When resuming, the SDK preserves the original session's model/prompt.
|
||||||
|
// The ResumeSessionConfig type only supports tools, provider, streaming,
|
||||||
|
// onPermissionRequest, mcpServers, customAgents, skillDirectories, disabledSkills.
|
||||||
if (params.sessionId) {
|
if (params.sessionId) {
|
||||||
session = await client.resumeSession(params.sessionId, {
|
session = await client.resumeSession(params.sessionId, {
|
||||||
streaming: true,
|
streaming: true,
|
||||||
@ -194,7 +195,7 @@ export async function runCopilotAgent(
|
|||||||
const sessionId = session.sessionId;
|
const sessionId = session.sessionId;
|
||||||
|
|
||||||
// Set up event handler
|
// Set up event handler
|
||||||
const unsubscribe = session.on((event: SessionEvent) => {
|
unsubscribe = session.on((event: SessionEvent) => {
|
||||||
events.push(event);
|
events.push(event);
|
||||||
params.onEvent?.(event);
|
params.onEvent?.(event);
|
||||||
|
|
||||||
@ -207,34 +208,33 @@ export async function runCopilotAgent(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
// Send the message and wait for completion
|
||||||
// Send the message and wait for completion
|
const result = await session.sendAndWait({ prompt: params.prompt }, params.timeoutMs ?? 120000);
|
||||||
const result = await session.sendAndWait(
|
|
||||||
{ prompt: params.prompt },
|
|
||||||
params.timeoutMs ?? 120000,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extract text from result if available
|
// Extract text from result if available
|
||||||
if (result?.data?.content && typeof result.data.content === "string") {
|
if (result?.data?.content && typeof result.data.content === "string") {
|
||||||
finalText = result.data.content;
|
finalText = result.data.content;
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
text: finalText,
|
|
||||||
sessionId,
|
|
||||||
events,
|
|
||||||
durationMs: Date.now() - started,
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
unsubscribe();
|
|
||||||
// Note: We don't destroy the session if sessionId was provided for resumption
|
|
||||||
if (!params.sessionId) {
|
|
||||||
await session.destroy().catch(() => {
|
|
||||||
// Ignore cleanup errors
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
text: finalText,
|
||||||
|
sessionId,
|
||||||
|
events,
|
||||||
|
durationMs: Date.now() - started,
|
||||||
|
};
|
||||||
} finally {
|
} finally {
|
||||||
|
// Clean up in reverse order: unsubscribe, destroy session (if new), stop client
|
||||||
|
if (unsubscribe) {
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only destroy session if we created a new one (not resuming)
|
||||||
|
if (session && !params.sessionId) {
|
||||||
|
await session.destroy().catch(() => {
|
||||||
|
// Ignore cleanup errors
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Always stop the client
|
// Always stop the client
|
||||||
await client.stop().catch(() => {
|
await client.stop().catch(() => {
|
||||||
// Ignore cleanup errors
|
// Ignore cleanup errors
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user