@copilotkit/runtime
Version:
<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />
208 lines (206 loc) • 7.47 kB
JavaScript
import "reflect-metadata";
import telemetry from "../../telemetry/telemetry-client.mjs";
import { isHandlerResponse } from "../shared/json-response.mjs";
import { generateThreadNameForNewThread } from "./thread-names.mjs";
import { resolveIntelligenceUser } from "../shared/resolve-intelligence-user.mjs";
import { logger } from "@copilotkit/shared";
import { EventType } from "@ag-ui/client";
//#region src/v2/runtime/handlers/intelligence/run.ts
/**
* Builds browser-facing realtime connection metadata owned by the runtime.
*/
function buildRealtimeConnectionInfo(params) {
return {
clientUrl: params.clientUrl,
topic: `thread:${params.threadId}`
};
}
function hasRunnerStartupBoundary(runner) {
return typeof runner.runWithStartupBoundary === "function" && (Object.prototype.hasOwnProperty.call(runner, "runWithStartupBoundary") || Object.prototype.hasOwnProperty.call(runner, "threads"));
}
async function handleIntelligenceRun({ runtime, request, agentId, agent, input }) {
if (!runtime.intelligence) return Response.json({
error: "Intelligence not configured",
message: "Intelligence mode requires a CopilotKitIntelligence"
}, { status: 500 });
const user = await resolveIntelligenceUser({
runtime,
request
});
if (isHandlerResponse(user)) return user;
const userId = user.id;
try {
const { thread, created } = await runtime.intelligence.getOrCreateThread({
threadId: input.threadId,
userId,
agentId
});
if (created && runtime.generateThreadNames && !thread.name?.trim()) generateThreadNameForNewThread({
runtime,
request,
agentId,
sourceInput: input,
thread,
userId
}).catch((nameError) => {
logger.error("Failed to generate thread name:", nameError);
});
} catch (error) {
logger.error("Failed to get or create thread:", error);
return Response.json({ error: "Failed to initialize thread" }, { status: 502 });
}
let canonicalThreadId = input.threadId;
let canonicalRunId = input.runId;
let joinToken;
try {
const lockResult = await runtime.intelligence.ɵacquireThreadLock({
threadId: input.threadId,
runId: input.runId,
userId,
agentId,
...runtime.lockKeyPrefix !== void 0 ? { lockKeyPrefix: runtime.lockKeyPrefix } : {},
ttlSeconds: runtime.lockTtlSeconds
});
canonicalThreadId = lockResult.threadId;
canonicalRunId = lockResult.runId;
joinToken = lockResult.joinToken;
} catch (error) {
logger.error("Thread lock denied:", error);
return Response.json({ error: "Thread lock denied" }, { status: 409 });
}
const cleanupLock = (reason) => runtime.intelligence.ɵcleanupThreadLock({
threadId: canonicalThreadId || input.threadId,
runId: canonicalRunId || input.runId
}).catch((cleanupError) => {
logger.error({
err: cleanupError,
reason
}, "Failed to cleanup thread lock");
});
if (!canonicalThreadId || !canonicalRunId || !joinToken) {
await cleanupLock("malformed-lock-response");
return Response.json({
error: "Run connection credentials not available",
message: "Intelligence platform did not return canonical threadId, runId, and joinToken"
}, { status: 502 });
}
const upstreamAuth = input.forwardedProps?.auth ?? {};
const copilotkitIntelligenceAuth = runtime.intelligence.ɵisMcpServerEnabled?.() ? { copilotkitIntelligence: {
userId,
apiKey: runtime.intelligence.ɵgetApiKey(),
mcpUrl: `${runtime.intelligence.ɵgetApiUrl()}/mcp`
} } : {};
const mergedAuth = {
...upstreamAuth,
...copilotkitIntelligenceAuth
};
const canonicalInput = {
...input,
threadId: canonicalThreadId,
runId: canonicalRunId,
forwardedProps: {
...input.forwardedProps,
...Object.keys(mergedAuth).length > 0 ? { auth: mergedAuth } : {}
}
};
let persistedInputMessages;
if (Array.isArray(input.messages)) try {
const history = await runtime.intelligence.getThreadMessages({ threadId: canonicalThreadId });
const historicMessageIds = new Set(history.messages.map((message) => message.id));
persistedInputMessages = input.messages.filter((message) => !historicMessageIds.has(message.id));
} catch (error) {
logger.error("Thread history lookup failed:", error);
await cleanupLock("thread-history-lookup-failed");
return Response.json({ error: "Thread history lookup failed" }, { status: 502 });
}
telemetry.capture("oss.runtime.agent_execution_stream_started", {});
let heartbeatTimer;
heartbeatTimer = setInterval(() => {
runtime.intelligence.ɵrenewThreadLock({
threadId: canonicalThreadId,
runId: canonicalRunId,
ttlSeconds: runtime.lockTtlSeconds,
...runtime.lockKeyPrefix !== void 0 ? { lockKeyPrefix: runtime.lockKeyPrefix } : {}
}).catch((err) => {
logger.error("Failed to renew thread lock:", err);
clearHeartbeat();
try {
agent.abortRun();
} catch (abortError) {
logger.error("Failed to abort agent after lock renewal failure:", abortError);
}
});
}, runtime.lockHeartbeatIntervalSeconds * 1e3);
const clearHeartbeat = () => {
if (heartbeatTimer !== void 0) {
clearInterval(heartbeatTimer);
heartbeatTimer = void 0;
}
};
const runStarted = { current: false };
let immediateStartupErrorMessage;
let immediateStartupCleanup;
const runRequest = {
threadId: canonicalThreadId,
agent,
input: canonicalInput,
...persistedInputMessages !== void 0 ? { persistedInputMessages } : {}
};
try {
const runStart = hasRunnerStartupBoundary(runtime.runner) ? runtime.runner.runWithStartupBoundary(runRequest) : {
events: runtime.runner.run(runRequest),
startup: Promise.resolve()
};
runStart.events.subscribe({
next: (event) => {
if (event.type === EventType.RUN_STARTED) runStarted.current = true;
if (event.type === EventType.RUN_ERROR && !runStarted.current) {
clearHeartbeat();
immediateStartupErrorMessage = "message" in event && typeof event.message === "string" ? event.message : "Runner failed before the run started";
immediateStartupCleanup = cleanupLock("runner-start-failed");
}
},
error: (error) => {
clearHeartbeat();
if (!runStarted.current) {
immediateStartupErrorMessage = error instanceof Error ? error.message : String(error);
immediateStartupCleanup = cleanupLock("runner-start-error");
} else cleanupLock("runner-error");
telemetry.capture("oss.runtime.agent_execution_stream_errored", { error: error instanceof Error ? error.message : String(error) });
logger.error("Error running agent:", error);
},
complete: () => {
clearHeartbeat();
telemetry.capture("oss.runtime.agent_execution_stream_ended", {});
}
});
await runStart.startup;
} catch (error) {
clearHeartbeat();
await (immediateStartupCleanup ?? cleanupLock("runner-start-threw"));
logger.error("Error starting agent runner:", error);
return Response.json({
error: "Failed to start runner",
message: error instanceof Error ? error.message : String(error)
}, { status: 502 });
}
if (immediateStartupErrorMessage) {
await immediateStartupCleanup;
return Response.json({
error: "Failed to start runner",
message: immediateStartupErrorMessage
}, { status: 502 });
}
return Response.json({
threadId: canonicalThreadId,
runId: canonicalRunId,
joinToken,
realtime: buildRealtimeConnectionInfo({
clientUrl: runtime.intelligence.ɵgetClientWsUrl(),
threadId: canonicalThreadId
})
}, { headers: { "Cache-Control": "no-cache" } });
}
//#endregion
export { handleIntelligenceRun };
//# sourceMappingURL=run.mjs.map