@copilotkit/web-inspector 1.70.0 → 1.70.2
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/dist/components/learning-view.cjs +1415 -0
- package/dist/components/learning-view.cjs.map +1 -0
- package/dist/components/learning-view.mjs +1415 -0
- package/dist/components/learning-view.mjs.map +1 -0
- package/dist/index.cjs +1437 -609
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -27
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +64 -27
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1440 -612
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +3224 -734
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/home-briefing.cjs +19 -5
- package/dist/lib/home-briefing.cjs.map +1 -1
- package/dist/lib/home-briefing.mjs +19 -6
- package/dist/lib/home-briefing.mjs.map +1 -1
- package/dist/lib/inspector-learning.cjs +37 -0
- package/dist/lib/inspector-learning.cjs.map +1 -0
- package/dist/lib/inspector-learning.mjs +36 -0
- package/dist/lib/inspector-learning.mjs.map +1 -0
- package/dist/lib/learning-setup.cjs +83 -0
- package/dist/lib/learning-setup.cjs.map +1 -0
- package/dist/lib/learning-setup.mjs +78 -0
- package/dist/lib/learning-setup.mjs.map +1 -0
- package/dist/lib/persistence.cjs +56 -3
- package/dist/lib/persistence.cjs.map +1 -1
- package/dist/lib/persistence.mjs +54 -4
- package/dist/lib/persistence.mjs.map +1 -1
- package/dist/lib/telemetry.cjs +65 -0
- package/dist/lib/telemetry.cjs.map +1 -1
- package/dist/lib/telemetry.d.cts.map +1 -1
- package/dist/lib/telemetry.d.mts.map +1 -1
- package/dist/lib/telemetry.mjs +56 -1
- package/dist/lib/telemetry.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/styles/generated.cjs +1 -1
- package/dist/styles/generated.cjs.map +1 -1
- package/dist/styles/generated.mjs +1 -1
- package/dist/styles/generated.mjs.map +1 -1
- package/package.json +5 -3
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
|
|
2
2
|
//#region src/lib/home-briefing.ts
|
|
3
|
+
/**
|
|
4
|
+
* A self-contained handoff for a coding agent. It answers the onboarding
|
|
5
|
+
* workflow's session and feedback consent gates up front, while keeping the
|
|
6
|
+
* feature guide—not a generic product-onboarding branch—in control of the
|
|
7
|
+
* implementation plan.
|
|
8
|
+
*/
|
|
9
|
+
function homeFeatureImplementationPrompt(service, context) {
|
|
10
|
+
return `Identify your coding-agent slug (for example, \`codex\` or \`claude-code\`). From the target project root, run \`npx copilotkit@latest onboard start --run ${context.onboardingRunId} --coding-agent <coding-agent-slug>\` and use its output as onboarding context. If it requires a CopilotKit CLI session check, you have permission to run it; never reveal credentials or send optional diagnostic feedback reports.
|
|
11
|
+
|
|
12
|
+
This task is specifically to enable ${service.label}, not to re-onboard the application. First inspect the existing CopilotKit runtime, provider, agent, and UI wiring, and confirm that ${service.label} is not already enabled. Then read the ${service.label} guide (${service.docsUrl}) and make a short plan before editing. Preserve the project's framework, package manager, installed CopilotKit version, existing agent IDs, routes, provider layout, and working behavior. Do not create, select, or alter a CopilotKit Intelligence project—or add Intelligence configuration—unless this feature's official guide explicitly requires it or the user asks.
|
|
13
|
+
|
|
14
|
+
Implement the smallest complete integration: wire every feature-required client and runtime configuration into the chat-to-agent path people already use, reuse local patterns, and do not invent environment values or hardcode secrets. Add or update focused tests and run the relevant project checks. Finish only after local validation proves ${service.label} works—not merely that the code compiles. Use a feature-specific runtime or Inspector capability check and, when the feature supports one, a representative UI interaction that proves the user-facing result. If the project overrides default rendering (for example, with a wildcard tool renderer), make that override compatible with this feature; a capability flag alone is not success. Summarize the changed files, validation, and any manual setup still required.`;
|
|
15
|
+
}
|
|
3
16
|
const SERVICE_DOCS_URL = {
|
|
4
17
|
threads: "https://docs.copilotkit.ai/threads",
|
|
5
|
-
memory: "https://docs.copilotkit.ai/
|
|
18
|
+
memory: "https://docs.copilotkit.ai/intelligence/intelligence-platform",
|
|
6
19
|
a2ui: "https://docs.copilotkit.ai/generative-ui/a2ui",
|
|
7
20
|
"open-gen-ui": "https://docs.copilotkit.ai/generative-ui/open-generative-ui",
|
|
8
|
-
suggestions: "https://docs.copilotkit.ai/
|
|
21
|
+
suggestions: "https://docs.copilotkit.ai/reference/hooks/useConfigureSuggestions",
|
|
9
22
|
audio: "https://docs.copilotkit.ai/voice",
|
|
10
|
-
websocket: "https://docs.copilotkit.ai/
|
|
23
|
+
websocket: "https://docs.copilotkit.ai/intelligence/intelligence-platform"
|
|
11
24
|
};
|
|
12
25
|
/** Return the Home hero button for a trusted metadata action. */
|
|
13
26
|
function homeHeroActionFromMetadata(action) {
|
|
@@ -240,7 +253,7 @@ function buildHomeModel(input) {
|
|
|
240
253
|
},
|
|
241
254
|
{
|
|
242
255
|
id: "memory",
|
|
243
|
-
label: "
|
|
256
|
+
label: "Learning",
|
|
244
257
|
enabled: intelligenceConnected && input.memoriesOn,
|
|
245
258
|
docsUrl: SERVICE_DOCS_URL.memory
|
|
246
259
|
},
|
|
@@ -264,7 +277,7 @@ function buildHomeModel(input) {
|
|
|
264
277
|
},
|
|
265
278
|
{
|
|
266
279
|
id: "audio",
|
|
267
|
-
label: "
|
|
280
|
+
label: "Voice",
|
|
268
281
|
enabled: input.audioOn,
|
|
269
282
|
docsUrl: SERVICE_DOCS_URL.audio
|
|
270
283
|
},
|
|
@@ -286,5 +299,6 @@ function buildHomeModel(input) {
|
|
|
286
299
|
|
|
287
300
|
//#endregion
|
|
288
301
|
exports.buildHomeModel = buildHomeModel;
|
|
302
|
+
exports.homeFeatureImplementationPrompt = homeFeatureImplementationPrompt;
|
|
289
303
|
exports.runtimeConnectionNeedsAttention = runtimeConnectionNeedsAttention;
|
|
290
304
|
//# sourceMappingURL=home-briefing.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home-briefing.cjs","names":[],"sources":["../../src/lib/home-briefing.ts"],"sourcesContent":["import type { InspectorMetadataProjection } from \"./inspector-metadata.js\";\n\nexport type HomeHeroActionKind =\n | \"enable_intelligence\"\n | \"manage_plan\"\n | \"renew\";\n\nexport type HomeHeroAction = {\n kind: HomeHeroActionKind;\n url: string;\n label: string;\n};\n\nexport type HomeConnection = \"connected\" | \"disconnected\";\n\nexport type HomeRuntimeConnectionState =\n | \"connected\"\n | \"connecting\"\n | \"disconnected\"\n | \"error\"\n | \"unavailable\";\n\nexport type HomeRuntimeHealthTone = \"success\" | \"active\" | \"error\" | \"muted\";\n\nexport type HomeServiceId =\n | \"threads\"\n | \"memory\"\n | \"a2ui\"\n | \"open-gen-ui\"\n | \"suggestions\"\n | \"audio\"\n | \"websocket\";\n\nexport type HomeServiceTile = {\n id: HomeServiceId;\n label: string;\n enabled: boolean;\n url?: string;\n docsUrl: string;\n};\n\nexport type HomeModel = {\n hero: {\n connection: HomeConnection;\n title: string;\n body: string;\n action?: HomeHeroAction;\n };\n project?: {\n organizationName: string;\n projectName: string;\n planLabel?: string;\n license: string;\n usage?: {\n used: number;\n limitLabel: string;\n ratio?: number;\n };\n };\n projectLinked: boolean;\n runtime: {\n url?: string;\n health: {\n state: \"healthy\" | \"checking\" | \"offline\" | \"error\" | \"unavailable\";\n label: string;\n runtime: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n liveUpdates: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n lastEvent: {\n label: string;\n tone: HomeRuntimeHealthTone;\n id?: string;\n agentId?: string;\n type?: string;\n timestamp?: number;\n };\n };\n };\n services: HomeServiceTile[];\n news: {\n title: string;\n previewText: string;\n documentHtml?: string;\n empty: boolean;\n };\n};\n\nexport type HomeBriefingInput = {\n intelligenceConnected: boolean;\n threadsAvailable: boolean;\n metadata: InspectorMetadataProjection;\n runtimeUrl?: string;\n runtimeConnectionState: HomeRuntimeConnectionState;\n lastRuntimeEvent?: {\n id: string;\n agentId: string;\n type: string;\n timestamp: number;\n };\n memoriesOn: boolean;\n a2uiOn: boolean;\n openGenUiOn: boolean;\n suggestionsOn: boolean;\n audioOn: boolean;\n websocketUrl?: string;\n announcementPreviewText?: string;\n announcementMarkdown?: string;\n announcementHtml?: string;\n intelligenceSignupUrl?: string;\n};\n\nconst SERVICE_DOCS_URL: Record<HomeServiceId, string> = {\n threads: \"https://docs.copilotkit.ai/threads\",\n memory: \"https://docs.copilotkit.ai/premium/intelligence-platform\",\n a2ui: \"https://docs.copilotkit.ai/generative-ui/a2ui\",\n \"open-gen-ui\": \"https://docs.copilotkit.ai/generative-ui/open-generative-ui\",\n suggestions: \"https://docs.copilotkit.ai/agentic-chat-ui\",\n audio: \"https://docs.copilotkit.ai/voice\",\n websocket: \"https://docs.copilotkit.ai/premium/intelligence-platform\",\n};\n\n/** Return the Home hero button for a trusted metadata action. */\nexport function homeHeroActionFromMetadata(action: {\n kind: HomeHeroActionKind;\n url: string;\n}): HomeHeroAction {\n if (action.kind === \"manage_plan\") {\n return { kind: action.kind, url: action.url, label: \"Manage plan\" };\n }\n\n if (action.kind === \"renew\") {\n return { kind: action.kind, url: action.url, label: \"Renew plan\" };\n }\n\n return {\n kind: action.kind,\n url: action.url,\n label: \"Setup Intelligence\",\n };\n}\n\n/** Return a short preview from markdown, without links or headings. */\nexport function announcementPreview(markdown: string, maxLength = 140): string {\n const plain = markdown\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .replace(/[#*_`]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (plain.length <= maxLength) {\n return plain;\n }\n\n return `${plain.slice(0, maxLength).trimEnd()}…`;\n}\n\nfunction connectIntelligenceAction(\n action: HomeHeroAction | undefined,\n connectUrl?: string,\n licenseState?: InspectorMetadataProjection[\"licenseState\"],\n): HomeHeroAction | undefined {\n if (action) {\n return action;\n }\n\n if (connectUrl && (licenseState === \"none\" || licenseState === \"unknown\")) {\n return homeHeroActionFromMetadata({\n kind: \"enable_intelligence\",\n url: connectUrl,\n });\n }\n\n return undefined;\n}\n\nfunction heroForState(args: {\n connected: boolean;\n action?: HomeHeroAction;\n connectUrl?: string;\n licenseState: InspectorMetadataProjection[\"licenseState\"];\n}): HomeModel[\"hero\"] {\n if (!args.connected) {\n const renewing = args.action?.kind === \"renew\";\n return {\n connection: \"disconnected\",\n // Not \"Intelligence is not setup\" — that reads as a defect in the tool,\n // and a defect gets dismissed. The heading names the product; the\n // argument for it is made by the rotating copy on Home, which changes\n // with the picture beside it.\n title: renewing ? \"Renew Intelligence\" : \"CopilotKit Intelligence\",\n // In install mode this is NOT the visible paragraph. The visible copy\n // rotates every few seconds, which would make a screen reader announce a\n // new sentence four times a loop, so the rotating text is hidden from\n // assistive tech and this one stable sentence is exposed instead. It has\n // to carry the whole chain on its own.\n body: renewing\n ? \"Renew Intelligence to restore persistent Threads and Memory.\"\n : \"Intelligence keeps every thread your users have, finds evidence-backed patterns in them, and proposes skills you approve before your agent uses them.\",\n action: connectIntelligenceAction(\n args.action,\n args.connectUrl,\n args.licenseState,\n ),\n };\n }\n\n return {\n connection: \"connected\",\n title: \"Connected to Intelligence\",\n body: \"Use Workbench to inspect threads and memory.\",\n action:\n args.action?.kind === \"enable_intelligence\" ? undefined : args.action,\n };\n}\n\nfunction usageFromMetadata(metadata: InspectorMetadataProjection):\n | {\n used: number;\n limitLabel: string;\n ratio?: number;\n }\n | undefined {\n const usage = metadata.usage;\n if (!usage) {\n return undefined;\n }\n\n if (usage.limit.kind === \"finite\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / ${usage.limit.value}`,\n ratio: usage.limit.value === 0 ? 1 : usage.used / usage.limit.value,\n };\n }\n\n if (usage.limit.kind === \"unlimited\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / unlimited`,\n };\n }\n\n return {\n used: usage.used,\n limitLabel: `${usage.used} used`,\n };\n}\n\nfunction newsFromAnnouncement(args: {\n previewText?: string;\n markdown?: string;\n html?: string;\n}): HomeModel[\"news\"] {\n const markdown = args.markdown?.trim();\n if (markdown && args.html) {\n const heading = markdown.match(/^#{1,3}\\s+(.+)$/m)?.[1]?.trim();\n return {\n title: heading || \"The latest from CopilotKit\",\n previewText:\n args.previewText?.trim() || announcementPreview(markdown, 160),\n documentHtml: args.html,\n empty: false,\n };\n }\n\n return {\n title: \"You're all caught up\",\n previewText: \"Latest CopilotKit updates will appear here.\",\n empty: true,\n };\n}\n\nfunction runtimeEventSignal(\n event: HomeBriefingInput[\"lastRuntimeEvent\"],\n): HomeModel[\"runtime\"][\"health\"][\"lastEvent\"] {\n if (!event) {\n return { label: \"No events yet\", tone: \"muted\" };\n }\n\n const eventDetails = {\n id: event.id,\n agentId: event.agentId,\n type: event.type,\n timestamp: event.timestamp,\n };\n\n if (event.type === \"RUN_ERROR\" || event.type === \"ERROR\") {\n return {\n label: event.type === \"RUN_ERROR\" ? \"Run error\" : \"Error\",\n tone: \"error\",\n ...eventDetails,\n };\n }\n\n if (event.type === \"RUN_FINISHED\") {\n return {\n label: \"Run completed\",\n tone: \"success\",\n ...eventDetails,\n };\n }\n\n if (\n event.type.endsWith(\"_START\") ||\n event.type.endsWith(\"_STARTED\") ||\n event.type.endsWith(\"_CONTENT\") ||\n event.type.endsWith(\"_ARGS\") ||\n event.type.endsWith(\"_DELTA\")\n ) {\n return {\n label: \"Last event is in progress\",\n tone: \"active\",\n ...eventDetails,\n };\n }\n\n return {\n label: \"Last event received\",\n tone: \"success\",\n ...eventDetails,\n };\n}\n\n/**\n * Whether the runtime *connection* needs attention — the single condition\n * shared by System Health and the launcher's error signal, so the two can\n * never disagree about whether the wiring is broken.\n *\n * Exactly one state counts. `disconnected` is also the initial value, so\n * counting it would raise the signal on every page load; `connecting` is a\n * normal startup step; `unavailable` means no Core is attached, which is not\n * a defect of the developer's wiring.\n *\n * Note the deliberate asymmetry with `health.state`: a failed *run* also\n * drives System Health to \"Needs attention\" while the connection is fine.\n * That is an event rather than a state, and it is excluded from the launcher\n * on purpose — see the launcher-signal comments in index.ts.\n */\nexport function runtimeConnectionNeedsAttention(\n state: HomeRuntimeConnectionState,\n): boolean {\n return state === \"error\";\n}\n\nfunction runtimeHealthFromInput(\n input: HomeBriefingInput,\n): HomeModel[\"runtime\"][\"health\"] {\n const lastEvent = runtimeEventSignal(input.lastRuntimeEvent);\n\n if (input.runtimeConnectionState === \"connected\") {\n return {\n state: lastEvent.tone === \"error\" ? \"error\" : \"healthy\",\n label: lastEvent.tone === \"error\" ? \"Needs attention\" : \"Healthy\",\n runtime: { label: \"Available\", tone: \"success\" },\n liveUpdates: { label: \"Ready\", tone: \"success\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"connecting\") {\n return {\n state: \"checking\",\n label: \"Checking\",\n runtime: { label: \"Checking\", tone: \"active\" },\n liveUpdates: { label: \"Connecting\", tone: \"active\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"unavailable\") {\n return {\n state: \"unavailable\",\n label: \"Unavailable\",\n runtime: { label: \"Unavailable\", tone: \"muted\" },\n liveUpdates: { label: \"Not attached\", tone: \"muted\" },\n lastEvent,\n };\n }\n\n const needsAttention = runtimeConnectionNeedsAttention(\n input.runtimeConnectionState,\n );\n return {\n state: needsAttention ? \"error\" : \"offline\",\n label: needsAttention ? \"Runtime error\" : \"Offline\",\n runtime: { label: \"Offline\", tone: \"error\" },\n liveUpdates: {\n label: needsAttention ? \"Error\" : \"Disconnected\",\n tone: \"error\",\n },\n lastEvent,\n };\n}\n\n/** Build the Home briefing from data the Inspector already has. */\nexport function buildHomeModel(input: HomeBriefingInput): HomeModel {\n const metadataAction =\n input.metadata.threadsFooterAction ?? input.metadata.lockedAction;\n const action = metadataAction\n ? homeHeroActionFromMetadata({\n kind: metadataAction.kind,\n url: metadataAction.url,\n })\n : undefined;\n\n const identity = input.metadata.identity;\n const projectLinked = Boolean(identity);\n const intelligenceConnected =\n input.metadata.licenseState === \"valid\" ||\n (input.metadata.licenseState === \"unknown\" && input.intelligenceConnected);\n const usage = usageFromMetadata(input.metadata);\n\n return {\n hero: heroForState({\n connected: intelligenceConnected,\n action,\n connectUrl: input.intelligenceSignupUrl,\n licenseState: input.metadata.licenseState,\n }),\n projectLinked,\n project: identity\n ? {\n organizationName: identity.organizationName,\n projectName: identity.projectName,\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : input.metadata.plan || usage\n ? {\n organizationName: \"Not linked\",\n projectName: \"This runtime is not linked to a project\",\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : undefined,\n runtime: {\n url: input.runtimeUrl,\n health: runtimeHealthFromInput(input),\n },\n services: [\n {\n id: \"threads\",\n label: \"Threads\",\n enabled: intelligenceConnected && input.threadsAvailable,\n url: input.runtimeUrl,\n docsUrl: SERVICE_DOCS_URL.threads,\n },\n {\n id: \"memory\",\n label: \"Memory\",\n enabled: intelligenceConnected && input.memoriesOn,\n docsUrl: SERVICE_DOCS_URL.memory,\n },\n {\n id: \"a2ui\",\n label: \"A2UI\",\n enabled: input.a2uiOn,\n docsUrl: SERVICE_DOCS_URL.a2ui,\n },\n {\n id: \"open-gen-ui\",\n label: \"Open Gen UI\",\n enabled: input.openGenUiOn,\n docsUrl: SERVICE_DOCS_URL[\"open-gen-ui\"],\n },\n {\n id: \"suggestions\",\n label: \"Suggestions\",\n enabled: input.suggestionsOn,\n docsUrl: SERVICE_DOCS_URL.suggestions,\n },\n {\n id: \"audio\",\n label: \"Audio\",\n enabled: input.audioOn,\n docsUrl: SERVICE_DOCS_URL.audio,\n },\n {\n id: \"websocket\",\n label: \"Websocket\",\n enabled: intelligenceConnected && Boolean(input.websocketUrl),\n url: input.websocketUrl,\n docsUrl: SERVICE_DOCS_URL.websocket,\n },\n ],\n news: newsFromAnnouncement({\n previewText: input.announcementPreviewText,\n markdown: input.announcementMarkdown,\n html: input.announcementHtml ?? undefined,\n }),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"home-briefing.cjs","names":[],"sources":["../../src/lib/home-briefing.ts"],"sourcesContent":["import type { InspectorMetadataProjection } from \"./inspector-metadata.js\";\n\nexport type HomeHeroActionKind =\n | \"enable_intelligence\"\n | \"manage_plan\"\n | \"renew\";\n\nexport type HomeHeroAction = {\n kind: HomeHeroActionKind;\n url: string;\n label: string;\n};\n\nexport type HomeConnection = \"connected\" | \"disconnected\";\n\nexport type HomeRuntimeConnectionState =\n | \"connected\"\n | \"connecting\"\n | \"disconnected\"\n | \"error\"\n | \"unavailable\";\n\nexport type HomeRuntimeHealthTone = \"success\" | \"active\" | \"error\" | \"muted\";\n\nexport type HomeServiceId =\n | \"threads\"\n | \"memory\"\n | \"a2ui\"\n | \"open-gen-ui\"\n | \"suggestions\"\n | \"audio\"\n | \"websocket\";\n\nexport type HomeServiceTile = {\n id: HomeServiceId;\n label: string;\n enabled: boolean;\n url?: string;\n docsUrl: string;\n};\n\nexport type HomeFeatureImplementationPromptContext = {\n onboardingRunId: string;\n};\n\n/**\n * A self-contained handoff for a coding agent. It answers the onboarding\n * workflow's session and feedback consent gates up front, while keeping the\n * feature guide—not a generic product-onboarding branch—in control of the\n * implementation plan.\n */\nexport function homeFeatureImplementationPrompt(\n service: Pick<HomeServiceTile, \"label\" | \"docsUrl\">,\n context: HomeFeatureImplementationPromptContext,\n): string {\n return `Identify your coding-agent slug (for example, \\`codex\\` or \\`claude-code\\`). From the target project root, run \\`npx copilotkit@latest onboard start --run ${context.onboardingRunId} --coding-agent <coding-agent-slug>\\` and use its output as onboarding context. If it requires a CopilotKit CLI session check, you have permission to run it; never reveal credentials or send optional diagnostic feedback reports.\n\nThis task is specifically to enable ${service.label}, not to re-onboard the application. First inspect the existing CopilotKit runtime, provider, agent, and UI wiring, and confirm that ${service.label} is not already enabled. Then read the ${service.label} guide (${service.docsUrl}) and make a short plan before editing. Preserve the project's framework, package manager, installed CopilotKit version, existing agent IDs, routes, provider layout, and working behavior. Do not create, select, or alter a CopilotKit Intelligence project—or add Intelligence configuration—unless this feature's official guide explicitly requires it or the user asks.\n\nImplement the smallest complete integration: wire every feature-required client and runtime configuration into the chat-to-agent path people already use, reuse local patterns, and do not invent environment values or hardcode secrets. Add or update focused tests and run the relevant project checks. Finish only after local validation proves ${service.label} works—not merely that the code compiles. Use a feature-specific runtime or Inspector capability check and, when the feature supports one, a representative UI interaction that proves the user-facing result. If the project overrides default rendering (for example, with a wildcard tool renderer), make that override compatible with this feature; a capability flag alone is not success. Summarize the changed files, validation, and any manual setup still required.`;\n}\n\nexport type HomeModel = {\n hero: {\n connection: HomeConnection;\n title: string;\n body: string;\n action?: HomeHeroAction;\n };\n project?: {\n organizationName: string;\n projectName: string;\n planLabel?: string;\n license: string;\n usage?: {\n used: number;\n limitLabel: string;\n ratio?: number;\n };\n };\n projectLinked: boolean;\n runtime: {\n url?: string;\n health: {\n state: \"healthy\" | \"checking\" | \"offline\" | \"error\" | \"unavailable\";\n label: string;\n runtime: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n liveUpdates: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n lastEvent: {\n label: string;\n tone: HomeRuntimeHealthTone;\n id?: string;\n agentId?: string;\n type?: string;\n timestamp?: number;\n };\n };\n };\n services: HomeServiceTile[];\n news: {\n title: string;\n previewText: string;\n documentHtml?: string;\n empty: boolean;\n };\n};\n\nexport type HomeBriefingInput = {\n intelligenceConnected: boolean;\n threadsAvailable: boolean;\n metadata: InspectorMetadataProjection;\n runtimeUrl?: string;\n runtimeConnectionState: HomeRuntimeConnectionState;\n lastRuntimeEvent?: {\n id: string;\n agentId: string;\n type: string;\n timestamp: number;\n };\n memoriesOn: boolean;\n a2uiOn: boolean;\n openGenUiOn: boolean;\n suggestionsOn: boolean;\n audioOn: boolean;\n websocketUrl?: string;\n announcementPreviewText?: string;\n announcementMarkdown?: string;\n announcementHtml?: string;\n intelligenceSignupUrl?: string;\n};\n\nconst SERVICE_DOCS_URL: Record<HomeServiceId, string> = {\n threads: \"https://docs.copilotkit.ai/threads\",\n memory: \"https://docs.copilotkit.ai/intelligence/intelligence-platform\",\n a2ui: \"https://docs.copilotkit.ai/generative-ui/a2ui\",\n \"open-gen-ui\": \"https://docs.copilotkit.ai/generative-ui/open-generative-ui\",\n suggestions:\n \"https://docs.copilotkit.ai/reference/hooks/useConfigureSuggestions\",\n audio: \"https://docs.copilotkit.ai/voice\",\n websocket: \"https://docs.copilotkit.ai/intelligence/intelligence-platform\",\n};\n\n/** Return the Home hero button for a trusted metadata action. */\nexport function homeHeroActionFromMetadata(action: {\n kind: HomeHeroActionKind;\n url: string;\n}): HomeHeroAction {\n if (action.kind === \"manage_plan\") {\n return { kind: action.kind, url: action.url, label: \"Manage plan\" };\n }\n\n if (action.kind === \"renew\") {\n return { kind: action.kind, url: action.url, label: \"Renew plan\" };\n }\n\n return {\n kind: action.kind,\n url: action.url,\n label: \"Setup Intelligence\",\n };\n}\n\n/** Return a short preview from markdown, without links or headings. */\nexport function announcementPreview(markdown: string, maxLength = 140): string {\n const plain = markdown\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .replace(/[#*_`]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (plain.length <= maxLength) {\n return plain;\n }\n\n return `${plain.slice(0, maxLength).trimEnd()}…`;\n}\n\nfunction connectIntelligenceAction(\n action: HomeHeroAction | undefined,\n connectUrl?: string,\n licenseState?: InspectorMetadataProjection[\"licenseState\"],\n): HomeHeroAction | undefined {\n if (action) {\n return action;\n }\n\n if (connectUrl && (licenseState === \"none\" || licenseState === \"unknown\")) {\n return homeHeroActionFromMetadata({\n kind: \"enable_intelligence\",\n url: connectUrl,\n });\n }\n\n return undefined;\n}\n\nfunction heroForState(args: {\n connected: boolean;\n action?: HomeHeroAction;\n connectUrl?: string;\n licenseState: InspectorMetadataProjection[\"licenseState\"];\n}): HomeModel[\"hero\"] {\n if (!args.connected) {\n const renewing = args.action?.kind === \"renew\";\n return {\n connection: \"disconnected\",\n // Not \"Intelligence is not setup\" — that reads as a defect in the tool,\n // and a defect gets dismissed. The heading names the product; the\n // argument for it is made by the rotating copy on Home, which changes\n // with the picture beside it.\n title: renewing ? \"Renew Intelligence\" : \"CopilotKit Intelligence\",\n // In install mode this is NOT the visible paragraph. The visible copy\n // rotates every few seconds, which would make a screen reader announce a\n // new sentence four times a loop, so the rotating text is hidden from\n // assistive tech and this one stable sentence is exposed instead. It has\n // to carry the whole chain on its own.\n body: renewing\n ? \"Renew Intelligence to restore persistent Threads and Memory.\"\n : \"Intelligence keeps every thread your users have, finds evidence-backed patterns in them, and proposes skills you approve before your agent uses them.\",\n action: connectIntelligenceAction(\n args.action,\n args.connectUrl,\n args.licenseState,\n ),\n };\n }\n\n return {\n connection: \"connected\",\n title: \"Connected to Intelligence\",\n body: \"Use Workbench to inspect threads and memory.\",\n action:\n args.action?.kind === \"enable_intelligence\" ? undefined : args.action,\n };\n}\n\nfunction usageFromMetadata(metadata: InspectorMetadataProjection):\n | {\n used: number;\n limitLabel: string;\n ratio?: number;\n }\n | undefined {\n const usage = metadata.usage;\n if (!usage) {\n return undefined;\n }\n\n if (usage.limit.kind === \"finite\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / ${usage.limit.value}`,\n ratio: usage.limit.value === 0 ? 1 : usage.used / usage.limit.value,\n };\n }\n\n if (usage.limit.kind === \"unlimited\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / unlimited`,\n };\n }\n\n return {\n used: usage.used,\n limitLabel: `${usage.used} used`,\n };\n}\n\nfunction newsFromAnnouncement(args: {\n previewText?: string;\n markdown?: string;\n html?: string;\n}): HomeModel[\"news\"] {\n const markdown = args.markdown?.trim();\n if (markdown && args.html) {\n const heading = markdown.match(/^#{1,3}\\s+(.+)$/m)?.[1]?.trim();\n return {\n title: heading || \"The latest from CopilotKit\",\n previewText:\n args.previewText?.trim() || announcementPreview(markdown, 160),\n documentHtml: args.html,\n empty: false,\n };\n }\n\n return {\n title: \"You're all caught up\",\n previewText: \"Latest CopilotKit updates will appear here.\",\n empty: true,\n };\n}\n\nfunction runtimeEventSignal(\n event: HomeBriefingInput[\"lastRuntimeEvent\"],\n): HomeModel[\"runtime\"][\"health\"][\"lastEvent\"] {\n if (!event) {\n return { label: \"No events yet\", tone: \"muted\" };\n }\n\n const eventDetails = {\n id: event.id,\n agentId: event.agentId,\n type: event.type,\n timestamp: event.timestamp,\n };\n\n if (event.type === \"RUN_ERROR\" || event.type === \"ERROR\") {\n return {\n label: event.type === \"RUN_ERROR\" ? \"Run error\" : \"Error\",\n tone: \"error\",\n ...eventDetails,\n };\n }\n\n if (event.type === \"RUN_FINISHED\") {\n return {\n label: \"Run completed\",\n tone: \"success\",\n ...eventDetails,\n };\n }\n\n if (\n event.type.endsWith(\"_START\") ||\n event.type.endsWith(\"_STARTED\") ||\n event.type.endsWith(\"_CONTENT\") ||\n event.type.endsWith(\"_ARGS\") ||\n event.type.endsWith(\"_DELTA\")\n ) {\n return {\n label: \"Last event is in progress\",\n tone: \"active\",\n ...eventDetails,\n };\n }\n\n return {\n label: \"Last event received\",\n tone: \"success\",\n ...eventDetails,\n };\n}\n\n/**\n * Whether the runtime *connection* needs attention — the single condition\n * shared by System Health and the launcher's error signal, so the two can\n * never disagree about whether the wiring is broken.\n *\n * Exactly one state counts. `disconnected` is also the initial value, so\n * counting it would raise the signal on every page load; `connecting` is a\n * normal startup step; `unavailable` means no Core is attached, which is not\n * a defect of the developer's wiring.\n *\n * Note the deliberate asymmetry with `health.state`: a failed *run* also\n * drives System Health to \"Needs attention\" while the connection is fine.\n * That is an event rather than a state, and it is excluded from the launcher\n * on purpose — see the launcher-signal comments in index.ts.\n */\nexport function runtimeConnectionNeedsAttention(\n state: HomeRuntimeConnectionState,\n): boolean {\n return state === \"error\";\n}\n\nfunction runtimeHealthFromInput(\n input: HomeBriefingInput,\n): HomeModel[\"runtime\"][\"health\"] {\n const lastEvent = runtimeEventSignal(input.lastRuntimeEvent);\n\n if (input.runtimeConnectionState === \"connected\") {\n return {\n state: lastEvent.tone === \"error\" ? \"error\" : \"healthy\",\n label: lastEvent.tone === \"error\" ? \"Needs attention\" : \"Healthy\",\n runtime: { label: \"Available\", tone: \"success\" },\n liveUpdates: { label: \"Ready\", tone: \"success\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"connecting\") {\n return {\n state: \"checking\",\n label: \"Checking\",\n runtime: { label: \"Checking\", tone: \"active\" },\n liveUpdates: { label: \"Connecting\", tone: \"active\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"unavailable\") {\n return {\n state: \"unavailable\",\n label: \"Unavailable\",\n runtime: { label: \"Unavailable\", tone: \"muted\" },\n liveUpdates: { label: \"Not attached\", tone: \"muted\" },\n lastEvent,\n };\n }\n\n const needsAttention = runtimeConnectionNeedsAttention(\n input.runtimeConnectionState,\n );\n return {\n state: needsAttention ? \"error\" : \"offline\",\n label: needsAttention ? \"Runtime error\" : \"Offline\",\n runtime: { label: \"Offline\", tone: \"error\" },\n liveUpdates: {\n label: needsAttention ? \"Error\" : \"Disconnected\",\n tone: \"error\",\n },\n lastEvent,\n };\n}\n\n/** Build the Home briefing from data the Inspector already has. */\nexport function buildHomeModel(input: HomeBriefingInput): HomeModel {\n const metadataAction =\n input.metadata.threadsFooterAction ?? input.metadata.lockedAction;\n const action = metadataAction\n ? homeHeroActionFromMetadata({\n kind: metadataAction.kind,\n url: metadataAction.url,\n })\n : undefined;\n\n const identity = input.metadata.identity;\n const projectLinked = Boolean(identity);\n const intelligenceConnected =\n input.metadata.licenseState === \"valid\" ||\n (input.metadata.licenseState === \"unknown\" && input.intelligenceConnected);\n const usage = usageFromMetadata(input.metadata);\n\n return {\n hero: heroForState({\n connected: intelligenceConnected,\n action,\n connectUrl: input.intelligenceSignupUrl,\n licenseState: input.metadata.licenseState,\n }),\n projectLinked,\n project: identity\n ? {\n organizationName: identity.organizationName,\n projectName: identity.projectName,\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : input.metadata.plan || usage\n ? {\n organizationName: \"Not linked\",\n projectName: \"This runtime is not linked to a project\",\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : undefined,\n runtime: {\n url: input.runtimeUrl,\n health: runtimeHealthFromInput(input),\n },\n services: [\n {\n id: \"threads\",\n label: \"Threads\",\n enabled: intelligenceConnected && input.threadsAvailable,\n url: input.runtimeUrl,\n docsUrl: SERVICE_DOCS_URL.threads,\n },\n {\n id: \"memory\",\n label: \"Learning\",\n enabled: intelligenceConnected && input.memoriesOn,\n docsUrl: SERVICE_DOCS_URL.memory,\n },\n {\n id: \"a2ui\",\n label: \"A2UI\",\n enabled: input.a2uiOn,\n docsUrl: SERVICE_DOCS_URL.a2ui,\n },\n {\n id: \"open-gen-ui\",\n label: \"Open Gen UI\",\n enabled: input.openGenUiOn,\n docsUrl: SERVICE_DOCS_URL[\"open-gen-ui\"],\n },\n {\n id: \"suggestions\",\n label: \"Suggestions\",\n enabled: input.suggestionsOn,\n docsUrl: SERVICE_DOCS_URL.suggestions,\n },\n {\n id: \"audio\",\n label: \"Voice\",\n enabled: input.audioOn,\n docsUrl: SERVICE_DOCS_URL.audio,\n },\n {\n id: \"websocket\",\n label: \"Websocket\",\n enabled: intelligenceConnected && Boolean(input.websocketUrl),\n url: input.websocketUrl,\n docsUrl: SERVICE_DOCS_URL.websocket,\n },\n ],\n news: newsFromAnnouncement({\n previewText: input.announcementPreviewText,\n markdown: input.announcementMarkdown,\n html: input.announcementHtml ?? undefined,\n }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
//#region src/lib/home-briefing.ts
|
|
2
|
+
/**
|
|
3
|
+
* A self-contained handoff for a coding agent. It answers the onboarding
|
|
4
|
+
* workflow's session and feedback consent gates up front, while keeping the
|
|
5
|
+
* feature guide—not a generic product-onboarding branch—in control of the
|
|
6
|
+
* implementation plan.
|
|
7
|
+
*/
|
|
8
|
+
function homeFeatureImplementationPrompt(service, context) {
|
|
9
|
+
return `Identify your coding-agent slug (for example, \`codex\` or \`claude-code\`). From the target project root, run \`npx copilotkit@latest onboard start --run ${context.onboardingRunId} --coding-agent <coding-agent-slug>\` and use its output as onboarding context. If it requires a CopilotKit CLI session check, you have permission to run it; never reveal credentials or send optional diagnostic feedback reports.
|
|
10
|
+
|
|
11
|
+
This task is specifically to enable ${service.label}, not to re-onboard the application. First inspect the existing CopilotKit runtime, provider, agent, and UI wiring, and confirm that ${service.label} is not already enabled. Then read the ${service.label} guide (${service.docsUrl}) and make a short plan before editing. Preserve the project's framework, package manager, installed CopilotKit version, existing agent IDs, routes, provider layout, and working behavior. Do not create, select, or alter a CopilotKit Intelligence project—or add Intelligence configuration—unless this feature's official guide explicitly requires it or the user asks.
|
|
12
|
+
|
|
13
|
+
Implement the smallest complete integration: wire every feature-required client and runtime configuration into the chat-to-agent path people already use, reuse local patterns, and do not invent environment values or hardcode secrets. Add or update focused tests and run the relevant project checks. Finish only after local validation proves ${service.label} works—not merely that the code compiles. Use a feature-specific runtime or Inspector capability check and, when the feature supports one, a representative UI interaction that proves the user-facing result. If the project overrides default rendering (for example, with a wildcard tool renderer), make that override compatible with this feature; a capability flag alone is not success. Summarize the changed files, validation, and any manual setup still required.`;
|
|
14
|
+
}
|
|
2
15
|
const SERVICE_DOCS_URL = {
|
|
3
16
|
threads: "https://docs.copilotkit.ai/threads",
|
|
4
|
-
memory: "https://docs.copilotkit.ai/
|
|
17
|
+
memory: "https://docs.copilotkit.ai/intelligence/intelligence-platform",
|
|
5
18
|
a2ui: "https://docs.copilotkit.ai/generative-ui/a2ui",
|
|
6
19
|
"open-gen-ui": "https://docs.copilotkit.ai/generative-ui/open-generative-ui",
|
|
7
|
-
suggestions: "https://docs.copilotkit.ai/
|
|
20
|
+
suggestions: "https://docs.copilotkit.ai/reference/hooks/useConfigureSuggestions",
|
|
8
21
|
audio: "https://docs.copilotkit.ai/voice",
|
|
9
|
-
websocket: "https://docs.copilotkit.ai/
|
|
22
|
+
websocket: "https://docs.copilotkit.ai/intelligence/intelligence-platform"
|
|
10
23
|
};
|
|
11
24
|
/** Return the Home hero button for a trusted metadata action. */
|
|
12
25
|
function homeHeroActionFromMetadata(action) {
|
|
@@ -239,7 +252,7 @@ function buildHomeModel(input) {
|
|
|
239
252
|
},
|
|
240
253
|
{
|
|
241
254
|
id: "memory",
|
|
242
|
-
label: "
|
|
255
|
+
label: "Learning",
|
|
243
256
|
enabled: intelligenceConnected && input.memoriesOn,
|
|
244
257
|
docsUrl: SERVICE_DOCS_URL.memory
|
|
245
258
|
},
|
|
@@ -263,7 +276,7 @@ function buildHomeModel(input) {
|
|
|
263
276
|
},
|
|
264
277
|
{
|
|
265
278
|
id: "audio",
|
|
266
|
-
label: "
|
|
279
|
+
label: "Voice",
|
|
267
280
|
enabled: input.audioOn,
|
|
268
281
|
docsUrl: SERVICE_DOCS_URL.audio
|
|
269
282
|
},
|
|
@@ -284,5 +297,5 @@ function buildHomeModel(input) {
|
|
|
284
297
|
}
|
|
285
298
|
|
|
286
299
|
//#endregion
|
|
287
|
-
export { buildHomeModel, runtimeConnectionNeedsAttention };
|
|
300
|
+
export { buildHomeModel, homeFeatureImplementationPrompt, runtimeConnectionNeedsAttention };
|
|
288
301
|
//# sourceMappingURL=home-briefing.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home-briefing.mjs","names":[],"sources":["../../src/lib/home-briefing.ts"],"sourcesContent":["import type { InspectorMetadataProjection } from \"./inspector-metadata.js\";\n\nexport type HomeHeroActionKind =\n | \"enable_intelligence\"\n | \"manage_plan\"\n | \"renew\";\n\nexport type HomeHeroAction = {\n kind: HomeHeroActionKind;\n url: string;\n label: string;\n};\n\nexport type HomeConnection = \"connected\" | \"disconnected\";\n\nexport type HomeRuntimeConnectionState =\n | \"connected\"\n | \"connecting\"\n | \"disconnected\"\n | \"error\"\n | \"unavailable\";\n\nexport type HomeRuntimeHealthTone = \"success\" | \"active\" | \"error\" | \"muted\";\n\nexport type HomeServiceId =\n | \"threads\"\n | \"memory\"\n | \"a2ui\"\n | \"open-gen-ui\"\n | \"suggestions\"\n | \"audio\"\n | \"websocket\";\n\nexport type HomeServiceTile = {\n id: HomeServiceId;\n label: string;\n enabled: boolean;\n url?: string;\n docsUrl: string;\n};\n\nexport type HomeModel = {\n hero: {\n connection: HomeConnection;\n title: string;\n body: string;\n action?: HomeHeroAction;\n };\n project?: {\n organizationName: string;\n projectName: string;\n planLabel?: string;\n license: string;\n usage?: {\n used: number;\n limitLabel: string;\n ratio?: number;\n };\n };\n projectLinked: boolean;\n runtime: {\n url?: string;\n health: {\n state: \"healthy\" | \"checking\" | \"offline\" | \"error\" | \"unavailable\";\n label: string;\n runtime: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n liveUpdates: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n lastEvent: {\n label: string;\n tone: HomeRuntimeHealthTone;\n id?: string;\n agentId?: string;\n type?: string;\n timestamp?: number;\n };\n };\n };\n services: HomeServiceTile[];\n news: {\n title: string;\n previewText: string;\n documentHtml?: string;\n empty: boolean;\n };\n};\n\nexport type HomeBriefingInput = {\n intelligenceConnected: boolean;\n threadsAvailable: boolean;\n metadata: InspectorMetadataProjection;\n runtimeUrl?: string;\n runtimeConnectionState: HomeRuntimeConnectionState;\n lastRuntimeEvent?: {\n id: string;\n agentId: string;\n type: string;\n timestamp: number;\n };\n memoriesOn: boolean;\n a2uiOn: boolean;\n openGenUiOn: boolean;\n suggestionsOn: boolean;\n audioOn: boolean;\n websocketUrl?: string;\n announcementPreviewText?: string;\n announcementMarkdown?: string;\n announcementHtml?: string;\n intelligenceSignupUrl?: string;\n};\n\nconst SERVICE_DOCS_URL: Record<HomeServiceId, string> = {\n threads: \"https://docs.copilotkit.ai/threads\",\n memory: \"https://docs.copilotkit.ai/premium/intelligence-platform\",\n a2ui: \"https://docs.copilotkit.ai/generative-ui/a2ui\",\n \"open-gen-ui\": \"https://docs.copilotkit.ai/generative-ui/open-generative-ui\",\n suggestions: \"https://docs.copilotkit.ai/agentic-chat-ui\",\n audio: \"https://docs.copilotkit.ai/voice\",\n websocket: \"https://docs.copilotkit.ai/premium/intelligence-platform\",\n};\n\n/** Return the Home hero button for a trusted metadata action. */\nexport function homeHeroActionFromMetadata(action: {\n kind: HomeHeroActionKind;\n url: string;\n}): HomeHeroAction {\n if (action.kind === \"manage_plan\") {\n return { kind: action.kind, url: action.url, label: \"Manage plan\" };\n }\n\n if (action.kind === \"renew\") {\n return { kind: action.kind, url: action.url, label: \"Renew plan\" };\n }\n\n return {\n kind: action.kind,\n url: action.url,\n label: \"Setup Intelligence\",\n };\n}\n\n/** Return a short preview from markdown, without links or headings. */\nexport function announcementPreview(markdown: string, maxLength = 140): string {\n const plain = markdown\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .replace(/[#*_`]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (plain.length <= maxLength) {\n return plain;\n }\n\n return `${plain.slice(0, maxLength).trimEnd()}…`;\n}\n\nfunction connectIntelligenceAction(\n action: HomeHeroAction | undefined,\n connectUrl?: string,\n licenseState?: InspectorMetadataProjection[\"licenseState\"],\n): HomeHeroAction | undefined {\n if (action) {\n return action;\n }\n\n if (connectUrl && (licenseState === \"none\" || licenseState === \"unknown\")) {\n return homeHeroActionFromMetadata({\n kind: \"enable_intelligence\",\n url: connectUrl,\n });\n }\n\n return undefined;\n}\n\nfunction heroForState(args: {\n connected: boolean;\n action?: HomeHeroAction;\n connectUrl?: string;\n licenseState: InspectorMetadataProjection[\"licenseState\"];\n}): HomeModel[\"hero\"] {\n if (!args.connected) {\n const renewing = args.action?.kind === \"renew\";\n return {\n connection: \"disconnected\",\n // Not \"Intelligence is not setup\" — that reads as a defect in the tool,\n // and a defect gets dismissed. The heading names the product; the\n // argument for it is made by the rotating copy on Home, which changes\n // with the picture beside it.\n title: renewing ? \"Renew Intelligence\" : \"CopilotKit Intelligence\",\n // In install mode this is NOT the visible paragraph. The visible copy\n // rotates every few seconds, which would make a screen reader announce a\n // new sentence four times a loop, so the rotating text is hidden from\n // assistive tech and this one stable sentence is exposed instead. It has\n // to carry the whole chain on its own.\n body: renewing\n ? \"Renew Intelligence to restore persistent Threads and Memory.\"\n : \"Intelligence keeps every thread your users have, finds evidence-backed patterns in them, and proposes skills you approve before your agent uses them.\",\n action: connectIntelligenceAction(\n args.action,\n args.connectUrl,\n args.licenseState,\n ),\n };\n }\n\n return {\n connection: \"connected\",\n title: \"Connected to Intelligence\",\n body: \"Use Workbench to inspect threads and memory.\",\n action:\n args.action?.kind === \"enable_intelligence\" ? undefined : args.action,\n };\n}\n\nfunction usageFromMetadata(metadata: InspectorMetadataProjection):\n | {\n used: number;\n limitLabel: string;\n ratio?: number;\n }\n | undefined {\n const usage = metadata.usage;\n if (!usage) {\n return undefined;\n }\n\n if (usage.limit.kind === \"finite\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / ${usage.limit.value}`,\n ratio: usage.limit.value === 0 ? 1 : usage.used / usage.limit.value,\n };\n }\n\n if (usage.limit.kind === \"unlimited\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / unlimited`,\n };\n }\n\n return {\n used: usage.used,\n limitLabel: `${usage.used} used`,\n };\n}\n\nfunction newsFromAnnouncement(args: {\n previewText?: string;\n markdown?: string;\n html?: string;\n}): HomeModel[\"news\"] {\n const markdown = args.markdown?.trim();\n if (markdown && args.html) {\n const heading = markdown.match(/^#{1,3}\\s+(.+)$/m)?.[1]?.trim();\n return {\n title: heading || \"The latest from CopilotKit\",\n previewText:\n args.previewText?.trim() || announcementPreview(markdown, 160),\n documentHtml: args.html,\n empty: false,\n };\n }\n\n return {\n title: \"You're all caught up\",\n previewText: \"Latest CopilotKit updates will appear here.\",\n empty: true,\n };\n}\n\nfunction runtimeEventSignal(\n event: HomeBriefingInput[\"lastRuntimeEvent\"],\n): HomeModel[\"runtime\"][\"health\"][\"lastEvent\"] {\n if (!event) {\n return { label: \"No events yet\", tone: \"muted\" };\n }\n\n const eventDetails = {\n id: event.id,\n agentId: event.agentId,\n type: event.type,\n timestamp: event.timestamp,\n };\n\n if (event.type === \"RUN_ERROR\" || event.type === \"ERROR\") {\n return {\n label: event.type === \"RUN_ERROR\" ? \"Run error\" : \"Error\",\n tone: \"error\",\n ...eventDetails,\n };\n }\n\n if (event.type === \"RUN_FINISHED\") {\n return {\n label: \"Run completed\",\n tone: \"success\",\n ...eventDetails,\n };\n }\n\n if (\n event.type.endsWith(\"_START\") ||\n event.type.endsWith(\"_STARTED\") ||\n event.type.endsWith(\"_CONTENT\") ||\n event.type.endsWith(\"_ARGS\") ||\n event.type.endsWith(\"_DELTA\")\n ) {\n return {\n label: \"Last event is in progress\",\n tone: \"active\",\n ...eventDetails,\n };\n }\n\n return {\n label: \"Last event received\",\n tone: \"success\",\n ...eventDetails,\n };\n}\n\n/**\n * Whether the runtime *connection* needs attention — the single condition\n * shared by System Health and the launcher's error signal, so the two can\n * never disagree about whether the wiring is broken.\n *\n * Exactly one state counts. `disconnected` is also the initial value, so\n * counting it would raise the signal on every page load; `connecting` is a\n * normal startup step; `unavailable` means no Core is attached, which is not\n * a defect of the developer's wiring.\n *\n * Note the deliberate asymmetry with `health.state`: a failed *run* also\n * drives System Health to \"Needs attention\" while the connection is fine.\n * That is an event rather than a state, and it is excluded from the launcher\n * on purpose — see the launcher-signal comments in index.ts.\n */\nexport function runtimeConnectionNeedsAttention(\n state: HomeRuntimeConnectionState,\n): boolean {\n return state === \"error\";\n}\n\nfunction runtimeHealthFromInput(\n input: HomeBriefingInput,\n): HomeModel[\"runtime\"][\"health\"] {\n const lastEvent = runtimeEventSignal(input.lastRuntimeEvent);\n\n if (input.runtimeConnectionState === \"connected\") {\n return {\n state: lastEvent.tone === \"error\" ? \"error\" : \"healthy\",\n label: lastEvent.tone === \"error\" ? \"Needs attention\" : \"Healthy\",\n runtime: { label: \"Available\", tone: \"success\" },\n liveUpdates: { label: \"Ready\", tone: \"success\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"connecting\") {\n return {\n state: \"checking\",\n label: \"Checking\",\n runtime: { label: \"Checking\", tone: \"active\" },\n liveUpdates: { label: \"Connecting\", tone: \"active\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"unavailable\") {\n return {\n state: \"unavailable\",\n label: \"Unavailable\",\n runtime: { label: \"Unavailable\", tone: \"muted\" },\n liveUpdates: { label: \"Not attached\", tone: \"muted\" },\n lastEvent,\n };\n }\n\n const needsAttention = runtimeConnectionNeedsAttention(\n input.runtimeConnectionState,\n );\n return {\n state: needsAttention ? \"error\" : \"offline\",\n label: needsAttention ? \"Runtime error\" : \"Offline\",\n runtime: { label: \"Offline\", tone: \"error\" },\n liveUpdates: {\n label: needsAttention ? \"Error\" : \"Disconnected\",\n tone: \"error\",\n },\n lastEvent,\n };\n}\n\n/** Build the Home briefing from data the Inspector already has. */\nexport function buildHomeModel(input: HomeBriefingInput): HomeModel {\n const metadataAction =\n input.metadata.threadsFooterAction ?? input.metadata.lockedAction;\n const action = metadataAction\n ? homeHeroActionFromMetadata({\n kind: metadataAction.kind,\n url: metadataAction.url,\n })\n : undefined;\n\n const identity = input.metadata.identity;\n const projectLinked = Boolean(identity);\n const intelligenceConnected =\n input.metadata.licenseState === \"valid\" ||\n (input.metadata.licenseState === \"unknown\" && input.intelligenceConnected);\n const usage = usageFromMetadata(input.metadata);\n\n return {\n hero: heroForState({\n connected: intelligenceConnected,\n action,\n connectUrl: input.intelligenceSignupUrl,\n licenseState: input.metadata.licenseState,\n }),\n projectLinked,\n project: identity\n ? {\n organizationName: identity.organizationName,\n projectName: identity.projectName,\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : input.metadata.plan || usage\n ? {\n organizationName: \"Not linked\",\n projectName: \"This runtime is not linked to a project\",\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : undefined,\n runtime: {\n url: input.runtimeUrl,\n health: runtimeHealthFromInput(input),\n },\n services: [\n {\n id: \"threads\",\n label: \"Threads\",\n enabled: intelligenceConnected && input.threadsAvailable,\n url: input.runtimeUrl,\n docsUrl: SERVICE_DOCS_URL.threads,\n },\n {\n id: \"memory\",\n label: \"Memory\",\n enabled: intelligenceConnected && input.memoriesOn,\n docsUrl: SERVICE_DOCS_URL.memory,\n },\n {\n id: \"a2ui\",\n label: \"A2UI\",\n enabled: input.a2uiOn,\n docsUrl: SERVICE_DOCS_URL.a2ui,\n },\n {\n id: \"open-gen-ui\",\n label: \"Open Gen UI\",\n enabled: input.openGenUiOn,\n docsUrl: SERVICE_DOCS_URL[\"open-gen-ui\"],\n },\n {\n id: \"suggestions\",\n label: \"Suggestions\",\n enabled: input.suggestionsOn,\n docsUrl: SERVICE_DOCS_URL.suggestions,\n },\n {\n id: \"audio\",\n label: \"Audio\",\n enabled: input.audioOn,\n docsUrl: SERVICE_DOCS_URL.audio,\n },\n {\n id: \"websocket\",\n label: \"Websocket\",\n enabled: intelligenceConnected && Boolean(input.websocketUrl),\n url: input.websocketUrl,\n docsUrl: SERVICE_DOCS_URL.websocket,\n },\n ],\n news: newsFromAnnouncement({\n previewText: input.announcementPreviewText,\n markdown: input.announcementMarkdown,\n html: input.announcementHtml ?? undefined,\n }),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"home-briefing.mjs","names":[],"sources":["../../src/lib/home-briefing.ts"],"sourcesContent":["import type { InspectorMetadataProjection } from \"./inspector-metadata.js\";\n\nexport type HomeHeroActionKind =\n | \"enable_intelligence\"\n | \"manage_plan\"\n | \"renew\";\n\nexport type HomeHeroAction = {\n kind: HomeHeroActionKind;\n url: string;\n label: string;\n};\n\nexport type HomeConnection = \"connected\" | \"disconnected\";\n\nexport type HomeRuntimeConnectionState =\n | \"connected\"\n | \"connecting\"\n | \"disconnected\"\n | \"error\"\n | \"unavailable\";\n\nexport type HomeRuntimeHealthTone = \"success\" | \"active\" | \"error\" | \"muted\";\n\nexport type HomeServiceId =\n | \"threads\"\n | \"memory\"\n | \"a2ui\"\n | \"open-gen-ui\"\n | \"suggestions\"\n | \"audio\"\n | \"websocket\";\n\nexport type HomeServiceTile = {\n id: HomeServiceId;\n label: string;\n enabled: boolean;\n url?: string;\n docsUrl: string;\n};\n\nexport type HomeFeatureImplementationPromptContext = {\n onboardingRunId: string;\n};\n\n/**\n * A self-contained handoff for a coding agent. It answers the onboarding\n * workflow's session and feedback consent gates up front, while keeping the\n * feature guide—not a generic product-onboarding branch—in control of the\n * implementation plan.\n */\nexport function homeFeatureImplementationPrompt(\n service: Pick<HomeServiceTile, \"label\" | \"docsUrl\">,\n context: HomeFeatureImplementationPromptContext,\n): string {\n return `Identify your coding-agent slug (for example, \\`codex\\` or \\`claude-code\\`). From the target project root, run \\`npx copilotkit@latest onboard start --run ${context.onboardingRunId} --coding-agent <coding-agent-slug>\\` and use its output as onboarding context. If it requires a CopilotKit CLI session check, you have permission to run it; never reveal credentials or send optional diagnostic feedback reports.\n\nThis task is specifically to enable ${service.label}, not to re-onboard the application. First inspect the existing CopilotKit runtime, provider, agent, and UI wiring, and confirm that ${service.label} is not already enabled. Then read the ${service.label} guide (${service.docsUrl}) and make a short plan before editing. Preserve the project's framework, package manager, installed CopilotKit version, existing agent IDs, routes, provider layout, and working behavior. Do not create, select, or alter a CopilotKit Intelligence project—or add Intelligence configuration—unless this feature's official guide explicitly requires it or the user asks.\n\nImplement the smallest complete integration: wire every feature-required client and runtime configuration into the chat-to-agent path people already use, reuse local patterns, and do not invent environment values or hardcode secrets. Add or update focused tests and run the relevant project checks. Finish only after local validation proves ${service.label} works—not merely that the code compiles. Use a feature-specific runtime or Inspector capability check and, when the feature supports one, a representative UI interaction that proves the user-facing result. If the project overrides default rendering (for example, with a wildcard tool renderer), make that override compatible with this feature; a capability flag alone is not success. Summarize the changed files, validation, and any manual setup still required.`;\n}\n\nexport type HomeModel = {\n hero: {\n connection: HomeConnection;\n title: string;\n body: string;\n action?: HomeHeroAction;\n };\n project?: {\n organizationName: string;\n projectName: string;\n planLabel?: string;\n license: string;\n usage?: {\n used: number;\n limitLabel: string;\n ratio?: number;\n };\n };\n projectLinked: boolean;\n runtime: {\n url?: string;\n health: {\n state: \"healthy\" | \"checking\" | \"offline\" | \"error\" | \"unavailable\";\n label: string;\n runtime: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n liveUpdates: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n lastEvent: {\n label: string;\n tone: HomeRuntimeHealthTone;\n id?: string;\n agentId?: string;\n type?: string;\n timestamp?: number;\n };\n };\n };\n services: HomeServiceTile[];\n news: {\n title: string;\n previewText: string;\n documentHtml?: string;\n empty: boolean;\n };\n};\n\nexport type HomeBriefingInput = {\n intelligenceConnected: boolean;\n threadsAvailable: boolean;\n metadata: InspectorMetadataProjection;\n runtimeUrl?: string;\n runtimeConnectionState: HomeRuntimeConnectionState;\n lastRuntimeEvent?: {\n id: string;\n agentId: string;\n type: string;\n timestamp: number;\n };\n memoriesOn: boolean;\n a2uiOn: boolean;\n openGenUiOn: boolean;\n suggestionsOn: boolean;\n audioOn: boolean;\n websocketUrl?: string;\n announcementPreviewText?: string;\n announcementMarkdown?: string;\n announcementHtml?: string;\n intelligenceSignupUrl?: string;\n};\n\nconst SERVICE_DOCS_URL: Record<HomeServiceId, string> = {\n threads: \"https://docs.copilotkit.ai/threads\",\n memory: \"https://docs.copilotkit.ai/intelligence/intelligence-platform\",\n a2ui: \"https://docs.copilotkit.ai/generative-ui/a2ui\",\n \"open-gen-ui\": \"https://docs.copilotkit.ai/generative-ui/open-generative-ui\",\n suggestions:\n \"https://docs.copilotkit.ai/reference/hooks/useConfigureSuggestions\",\n audio: \"https://docs.copilotkit.ai/voice\",\n websocket: \"https://docs.copilotkit.ai/intelligence/intelligence-platform\",\n};\n\n/** Return the Home hero button for a trusted metadata action. */\nexport function homeHeroActionFromMetadata(action: {\n kind: HomeHeroActionKind;\n url: string;\n}): HomeHeroAction {\n if (action.kind === \"manage_plan\") {\n return { kind: action.kind, url: action.url, label: \"Manage plan\" };\n }\n\n if (action.kind === \"renew\") {\n return { kind: action.kind, url: action.url, label: \"Renew plan\" };\n }\n\n return {\n kind: action.kind,\n url: action.url,\n label: \"Setup Intelligence\",\n };\n}\n\n/** Return a short preview from markdown, without links or headings. */\nexport function announcementPreview(markdown: string, maxLength = 140): string {\n const plain = markdown\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .replace(/[#*_`]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (plain.length <= maxLength) {\n return plain;\n }\n\n return `${plain.slice(0, maxLength).trimEnd()}…`;\n}\n\nfunction connectIntelligenceAction(\n action: HomeHeroAction | undefined,\n connectUrl?: string,\n licenseState?: InspectorMetadataProjection[\"licenseState\"],\n): HomeHeroAction | undefined {\n if (action) {\n return action;\n }\n\n if (connectUrl && (licenseState === \"none\" || licenseState === \"unknown\")) {\n return homeHeroActionFromMetadata({\n kind: \"enable_intelligence\",\n url: connectUrl,\n });\n }\n\n return undefined;\n}\n\nfunction heroForState(args: {\n connected: boolean;\n action?: HomeHeroAction;\n connectUrl?: string;\n licenseState: InspectorMetadataProjection[\"licenseState\"];\n}): HomeModel[\"hero\"] {\n if (!args.connected) {\n const renewing = args.action?.kind === \"renew\";\n return {\n connection: \"disconnected\",\n // Not \"Intelligence is not setup\" — that reads as a defect in the tool,\n // and a defect gets dismissed. The heading names the product; the\n // argument for it is made by the rotating copy on Home, which changes\n // with the picture beside it.\n title: renewing ? \"Renew Intelligence\" : \"CopilotKit Intelligence\",\n // In install mode this is NOT the visible paragraph. The visible copy\n // rotates every few seconds, which would make a screen reader announce a\n // new sentence four times a loop, so the rotating text is hidden from\n // assistive tech and this one stable sentence is exposed instead. It has\n // to carry the whole chain on its own.\n body: renewing\n ? \"Renew Intelligence to restore persistent Threads and Memory.\"\n : \"Intelligence keeps every thread your users have, finds evidence-backed patterns in them, and proposes skills you approve before your agent uses them.\",\n action: connectIntelligenceAction(\n args.action,\n args.connectUrl,\n args.licenseState,\n ),\n };\n }\n\n return {\n connection: \"connected\",\n title: \"Connected to Intelligence\",\n body: \"Use Workbench to inspect threads and memory.\",\n action:\n args.action?.kind === \"enable_intelligence\" ? undefined : args.action,\n };\n}\n\nfunction usageFromMetadata(metadata: InspectorMetadataProjection):\n | {\n used: number;\n limitLabel: string;\n ratio?: number;\n }\n | undefined {\n const usage = metadata.usage;\n if (!usage) {\n return undefined;\n }\n\n if (usage.limit.kind === \"finite\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / ${usage.limit.value}`,\n ratio: usage.limit.value === 0 ? 1 : usage.used / usage.limit.value,\n };\n }\n\n if (usage.limit.kind === \"unlimited\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / unlimited`,\n };\n }\n\n return {\n used: usage.used,\n limitLabel: `${usage.used} used`,\n };\n}\n\nfunction newsFromAnnouncement(args: {\n previewText?: string;\n markdown?: string;\n html?: string;\n}): HomeModel[\"news\"] {\n const markdown = args.markdown?.trim();\n if (markdown && args.html) {\n const heading = markdown.match(/^#{1,3}\\s+(.+)$/m)?.[1]?.trim();\n return {\n title: heading || \"The latest from CopilotKit\",\n previewText:\n args.previewText?.trim() || announcementPreview(markdown, 160),\n documentHtml: args.html,\n empty: false,\n };\n }\n\n return {\n title: \"You're all caught up\",\n previewText: \"Latest CopilotKit updates will appear here.\",\n empty: true,\n };\n}\n\nfunction runtimeEventSignal(\n event: HomeBriefingInput[\"lastRuntimeEvent\"],\n): HomeModel[\"runtime\"][\"health\"][\"lastEvent\"] {\n if (!event) {\n return { label: \"No events yet\", tone: \"muted\" };\n }\n\n const eventDetails = {\n id: event.id,\n agentId: event.agentId,\n type: event.type,\n timestamp: event.timestamp,\n };\n\n if (event.type === \"RUN_ERROR\" || event.type === \"ERROR\") {\n return {\n label: event.type === \"RUN_ERROR\" ? \"Run error\" : \"Error\",\n tone: \"error\",\n ...eventDetails,\n };\n }\n\n if (event.type === \"RUN_FINISHED\") {\n return {\n label: \"Run completed\",\n tone: \"success\",\n ...eventDetails,\n };\n }\n\n if (\n event.type.endsWith(\"_START\") ||\n event.type.endsWith(\"_STARTED\") ||\n event.type.endsWith(\"_CONTENT\") ||\n event.type.endsWith(\"_ARGS\") ||\n event.type.endsWith(\"_DELTA\")\n ) {\n return {\n label: \"Last event is in progress\",\n tone: \"active\",\n ...eventDetails,\n };\n }\n\n return {\n label: \"Last event received\",\n tone: \"success\",\n ...eventDetails,\n };\n}\n\n/**\n * Whether the runtime *connection* needs attention — the single condition\n * shared by System Health and the launcher's error signal, so the two can\n * never disagree about whether the wiring is broken.\n *\n * Exactly one state counts. `disconnected` is also the initial value, so\n * counting it would raise the signal on every page load; `connecting` is a\n * normal startup step; `unavailable` means no Core is attached, which is not\n * a defect of the developer's wiring.\n *\n * Note the deliberate asymmetry with `health.state`: a failed *run* also\n * drives System Health to \"Needs attention\" while the connection is fine.\n * That is an event rather than a state, and it is excluded from the launcher\n * on purpose — see the launcher-signal comments in index.ts.\n */\nexport function runtimeConnectionNeedsAttention(\n state: HomeRuntimeConnectionState,\n): boolean {\n return state === \"error\";\n}\n\nfunction runtimeHealthFromInput(\n input: HomeBriefingInput,\n): HomeModel[\"runtime\"][\"health\"] {\n const lastEvent = runtimeEventSignal(input.lastRuntimeEvent);\n\n if (input.runtimeConnectionState === \"connected\") {\n return {\n state: lastEvent.tone === \"error\" ? \"error\" : \"healthy\",\n label: lastEvent.tone === \"error\" ? \"Needs attention\" : \"Healthy\",\n runtime: { label: \"Available\", tone: \"success\" },\n liveUpdates: { label: \"Ready\", tone: \"success\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"connecting\") {\n return {\n state: \"checking\",\n label: \"Checking\",\n runtime: { label: \"Checking\", tone: \"active\" },\n liveUpdates: { label: \"Connecting\", tone: \"active\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"unavailable\") {\n return {\n state: \"unavailable\",\n label: \"Unavailable\",\n runtime: { label: \"Unavailable\", tone: \"muted\" },\n liveUpdates: { label: \"Not attached\", tone: \"muted\" },\n lastEvent,\n };\n }\n\n const needsAttention = runtimeConnectionNeedsAttention(\n input.runtimeConnectionState,\n );\n return {\n state: needsAttention ? \"error\" : \"offline\",\n label: needsAttention ? \"Runtime error\" : \"Offline\",\n runtime: { label: \"Offline\", tone: \"error\" },\n liveUpdates: {\n label: needsAttention ? \"Error\" : \"Disconnected\",\n tone: \"error\",\n },\n lastEvent,\n };\n}\n\n/** Build the Home briefing from data the Inspector already has. */\nexport function buildHomeModel(input: HomeBriefingInput): HomeModel {\n const metadataAction =\n input.metadata.threadsFooterAction ?? input.metadata.lockedAction;\n const action = metadataAction\n ? homeHeroActionFromMetadata({\n kind: metadataAction.kind,\n url: metadataAction.url,\n })\n : undefined;\n\n const identity = input.metadata.identity;\n const projectLinked = Boolean(identity);\n const intelligenceConnected =\n input.metadata.licenseState === \"valid\" ||\n (input.metadata.licenseState === \"unknown\" && input.intelligenceConnected);\n const usage = usageFromMetadata(input.metadata);\n\n return {\n hero: heroForState({\n connected: intelligenceConnected,\n action,\n connectUrl: input.intelligenceSignupUrl,\n licenseState: input.metadata.licenseState,\n }),\n projectLinked,\n project: identity\n ? {\n organizationName: identity.organizationName,\n projectName: identity.projectName,\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : input.metadata.plan || usage\n ? {\n organizationName: \"Not linked\",\n projectName: \"This runtime is not linked to a project\",\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : undefined,\n runtime: {\n url: input.runtimeUrl,\n health: runtimeHealthFromInput(input),\n },\n services: [\n {\n id: \"threads\",\n label: \"Threads\",\n enabled: intelligenceConnected && input.threadsAvailable,\n url: input.runtimeUrl,\n docsUrl: SERVICE_DOCS_URL.threads,\n },\n {\n id: \"memory\",\n label: \"Learning\",\n enabled: intelligenceConnected && input.memoriesOn,\n docsUrl: SERVICE_DOCS_URL.memory,\n },\n {\n id: \"a2ui\",\n label: \"A2UI\",\n enabled: input.a2uiOn,\n docsUrl: SERVICE_DOCS_URL.a2ui,\n },\n {\n id: \"open-gen-ui\",\n label: \"Open Gen UI\",\n enabled: input.openGenUiOn,\n docsUrl: SERVICE_DOCS_URL[\"open-gen-ui\"],\n },\n {\n id: \"suggestions\",\n label: \"Suggestions\",\n enabled: input.suggestionsOn,\n docsUrl: SERVICE_DOCS_URL.suggestions,\n },\n {\n id: \"audio\",\n label: \"Voice\",\n enabled: input.audioOn,\n docsUrl: SERVICE_DOCS_URL.audio,\n },\n {\n id: \"websocket\",\n label: \"Websocket\",\n enabled: intelligenceConnected && Boolean(input.websocketUrl),\n url: input.websocketUrl,\n docsUrl: SERVICE_DOCS_URL.websocket,\n },\n ],\n news: newsFromAnnouncement({\n previewText: input.announcementPreviewText,\n markdown: input.announcementMarkdown,\n html: input.announcementHtml ?? undefined,\n }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
let _copilotkit_shared = require("@copilotkit/shared");
|
|
2
|
+
|
|
3
|
+
//#region src/lib/inspector-learning.ts
|
|
4
|
+
var InspectorLearningUnsupportedError = class extends Error {};
|
|
5
|
+
/** Loads one Learning projection through either negotiated Runtime transport. */
|
|
6
|
+
async function fetchInspectorLearning(input) {
|
|
7
|
+
const base = input.runtimeUrl.replace(/\/+$/u, "");
|
|
8
|
+
const single = input.runtimeTransport === "single";
|
|
9
|
+
const url = single ? base : `${base}/inspector-learning`;
|
|
10
|
+
const query = new URLSearchParams();
|
|
11
|
+
if (input.request.agentId) query.set("agentId", input.request.agentId);
|
|
12
|
+
if (input.request.skillsPage) query.set("skillsPage", String(input.request.skillsPage));
|
|
13
|
+
if (input.request.insightsPage) query.set("insightsPage", String(input.request.insightsPage));
|
|
14
|
+
const response = await input.fetch(single ? url : `${url}?${query}`, {
|
|
15
|
+
method: single ? "POST" : "GET",
|
|
16
|
+
headers: single ? {
|
|
17
|
+
...input.headers,
|
|
18
|
+
"Content-Type": "application/json"
|
|
19
|
+
} : { ...input.headers },
|
|
20
|
+
credentials: input.credentials,
|
|
21
|
+
signal: input.signal,
|
|
22
|
+
...single ? { body: JSON.stringify({
|
|
23
|
+
method: "inspector/learning",
|
|
24
|
+
params: Object.fromEntries(query)
|
|
25
|
+
}) } : {}
|
|
26
|
+
});
|
|
27
|
+
if (response.status === 404) throw new InspectorLearningUnsupportedError();
|
|
28
|
+
if (!response.ok) throw new Error(`Learning snapshot failed (HTTP ${response.status}).`);
|
|
29
|
+
const snapshot = (0, _copilotkit_shared.parseInspectorLearningSnapshotV1)(await response.json());
|
|
30
|
+
if (!snapshot) throw new Error("Learning snapshot response is invalid.");
|
|
31
|
+
return snapshot;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
exports.InspectorLearningUnsupportedError = InspectorLearningUnsupportedError;
|
|
36
|
+
exports.fetchInspectorLearning = fetchInspectorLearning;
|
|
37
|
+
//# sourceMappingURL=inspector-learning.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspector-learning.cjs","names":[],"sources":["../../src/lib/inspector-learning.ts"],"sourcesContent":["import { parseInspectorLearningSnapshotV1 } from \"@copilotkit/shared\";\nimport type {\n InspectorLearningRequestV1,\n InspectorLearningSnapshotV1,\n} from \"@copilotkit/shared\";\n\nexport class InspectorLearningUnsupportedError extends Error {}\n\n/** Loads one Learning projection through either negotiated Runtime transport. */\nexport async function fetchInspectorLearning(input: {\n readonly runtimeUrl: string;\n readonly runtimeTransport: \"rest\" | \"single\" | \"auto\";\n readonly request: InspectorLearningRequestV1;\n readonly fetch: typeof globalThis.fetch;\n readonly headers?: Readonly<Record<string, string>>;\n readonly credentials?: RequestCredentials;\n readonly signal?: AbortSignal;\n}): Promise<InspectorLearningSnapshotV1> {\n const base = input.runtimeUrl.replace(/\\/+$/u, \"\");\n const single = input.runtimeTransport === \"single\";\n const url = single ? base : `${base}/inspector-learning`;\n const query = new URLSearchParams();\n if (input.request.agentId) query.set(\"agentId\", input.request.agentId);\n if (input.request.skillsPage)\n query.set(\"skillsPage\", String(input.request.skillsPage));\n if (input.request.insightsPage) {\n query.set(\"insightsPage\", String(input.request.insightsPage));\n }\n const response = await input.fetch(single ? url : `${url}?${query}`, {\n method: single ? \"POST\" : \"GET\",\n headers: single\n ? { ...input.headers, \"Content-Type\": \"application/json\" }\n : { ...input.headers },\n credentials: input.credentials,\n signal: input.signal,\n ...(single\n ? {\n body: JSON.stringify({\n method: \"inspector/learning\",\n params: Object.fromEntries(query),\n }),\n }\n : {}),\n });\n if (response.status === 404) throw new InspectorLearningUnsupportedError();\n if (!response.ok)\n throw new Error(`Learning snapshot failed (HTTP ${response.status}).`);\n const snapshot = parseInspectorLearningSnapshotV1(await response.json());\n if (!snapshot) throw new Error(\"Learning snapshot response is invalid.\");\n return snapshot;\n}\n"],"mappings":";;;AAMA,IAAa,oCAAb,cAAuD,MAAM;;AAG7D,eAAsB,uBAAuB,OAQJ;CACvC,MAAM,OAAO,MAAM,WAAW,QAAQ,SAAS,GAAG;CAClD,MAAM,SAAS,MAAM,qBAAqB;CAC1C,MAAM,MAAM,SAAS,OAAO,GAAG,KAAK;CACpC,MAAM,QAAQ,IAAI,iBAAiB;AACnC,KAAI,MAAM,QAAQ,QAAS,OAAM,IAAI,WAAW,MAAM,QAAQ,QAAQ;AACtE,KAAI,MAAM,QAAQ,WAChB,OAAM,IAAI,cAAc,OAAO,MAAM,QAAQ,WAAW,CAAC;AAC3D,KAAI,MAAM,QAAQ,aAChB,OAAM,IAAI,gBAAgB,OAAO,MAAM,QAAQ,aAAa,CAAC;CAE/D,MAAM,WAAW,MAAM,MAAM,MAAM,SAAS,MAAM,GAAG,IAAI,GAAG,SAAS;EACnE,QAAQ,SAAS,SAAS;EAC1B,SAAS,SACL;GAAE,GAAG,MAAM;GAAS,gBAAgB;GAAoB,GACxD,EAAE,GAAG,MAAM,SAAS;EACxB,aAAa,MAAM;EACnB,QAAQ,MAAM;EACd,GAAI,SACA,EACE,MAAM,KAAK,UAAU;GACnB,QAAQ;GACR,QAAQ,OAAO,YAAY,MAAM;GAClC,CAAC,EACH,GACD,EAAE;EACP,CAAC;AACF,KAAI,SAAS,WAAW,IAAK,OAAM,IAAI,mCAAmC;AAC1E,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,kCAAkC,SAAS,OAAO,IAAI;CACxE,MAAM,oEAA4C,MAAM,SAAS,MAAM,CAAC;AACxE,KAAI,CAAC,SAAU,OAAM,IAAI,MAAM,yCAAyC;AACxE,QAAO"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { parseInspectorLearningSnapshotV1 } from "@copilotkit/shared";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/inspector-learning.ts
|
|
4
|
+
var InspectorLearningUnsupportedError = class extends Error {};
|
|
5
|
+
/** Loads one Learning projection through either negotiated Runtime transport. */
|
|
6
|
+
async function fetchInspectorLearning(input) {
|
|
7
|
+
const base = input.runtimeUrl.replace(/\/+$/u, "");
|
|
8
|
+
const single = input.runtimeTransport === "single";
|
|
9
|
+
const url = single ? base : `${base}/inspector-learning`;
|
|
10
|
+
const query = new URLSearchParams();
|
|
11
|
+
if (input.request.agentId) query.set("agentId", input.request.agentId);
|
|
12
|
+
if (input.request.skillsPage) query.set("skillsPage", String(input.request.skillsPage));
|
|
13
|
+
if (input.request.insightsPage) query.set("insightsPage", String(input.request.insightsPage));
|
|
14
|
+
const response = await input.fetch(single ? url : `${url}?${query}`, {
|
|
15
|
+
method: single ? "POST" : "GET",
|
|
16
|
+
headers: single ? {
|
|
17
|
+
...input.headers,
|
|
18
|
+
"Content-Type": "application/json"
|
|
19
|
+
} : { ...input.headers },
|
|
20
|
+
credentials: input.credentials,
|
|
21
|
+
signal: input.signal,
|
|
22
|
+
...single ? { body: JSON.stringify({
|
|
23
|
+
method: "inspector/learning",
|
|
24
|
+
params: Object.fromEntries(query)
|
|
25
|
+
}) } : {}
|
|
26
|
+
});
|
|
27
|
+
if (response.status === 404) throw new InspectorLearningUnsupportedError();
|
|
28
|
+
if (!response.ok) throw new Error(`Learning snapshot failed (HTTP ${response.status}).`);
|
|
29
|
+
const snapshot = parseInspectorLearningSnapshotV1(await response.json());
|
|
30
|
+
if (!snapshot) throw new Error("Learning snapshot response is invalid.");
|
|
31
|
+
return snapshot;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { InspectorLearningUnsupportedError, fetchInspectorLearning };
|
|
36
|
+
//# sourceMappingURL=inspector-learning.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspector-learning.mjs","names":[],"sources":["../../src/lib/inspector-learning.ts"],"sourcesContent":["import { parseInspectorLearningSnapshotV1 } from \"@copilotkit/shared\";\nimport type {\n InspectorLearningRequestV1,\n InspectorLearningSnapshotV1,\n} from \"@copilotkit/shared\";\n\nexport class InspectorLearningUnsupportedError extends Error {}\n\n/** Loads one Learning projection through either negotiated Runtime transport. */\nexport async function fetchInspectorLearning(input: {\n readonly runtimeUrl: string;\n readonly runtimeTransport: \"rest\" | \"single\" | \"auto\";\n readonly request: InspectorLearningRequestV1;\n readonly fetch: typeof globalThis.fetch;\n readonly headers?: Readonly<Record<string, string>>;\n readonly credentials?: RequestCredentials;\n readonly signal?: AbortSignal;\n}): Promise<InspectorLearningSnapshotV1> {\n const base = input.runtimeUrl.replace(/\\/+$/u, \"\");\n const single = input.runtimeTransport === \"single\";\n const url = single ? base : `${base}/inspector-learning`;\n const query = new URLSearchParams();\n if (input.request.agentId) query.set(\"agentId\", input.request.agentId);\n if (input.request.skillsPage)\n query.set(\"skillsPage\", String(input.request.skillsPage));\n if (input.request.insightsPage) {\n query.set(\"insightsPage\", String(input.request.insightsPage));\n }\n const response = await input.fetch(single ? url : `${url}?${query}`, {\n method: single ? \"POST\" : \"GET\",\n headers: single\n ? { ...input.headers, \"Content-Type\": \"application/json\" }\n : { ...input.headers },\n credentials: input.credentials,\n signal: input.signal,\n ...(single\n ? {\n body: JSON.stringify({\n method: \"inspector/learning\",\n params: Object.fromEntries(query),\n }),\n }\n : {}),\n });\n if (response.status === 404) throw new InspectorLearningUnsupportedError();\n if (!response.ok)\n throw new Error(`Learning snapshot failed (HTTP ${response.status}).`);\n const snapshot = parseInspectorLearningSnapshotV1(await response.json());\n if (!snapshot) throw new Error(\"Learning snapshot response is invalid.\");\n return snapshot;\n}\n"],"mappings":";;;AAMA,IAAa,oCAAb,cAAuD,MAAM;;AAG7D,eAAsB,uBAAuB,OAQJ;CACvC,MAAM,OAAO,MAAM,WAAW,QAAQ,SAAS,GAAG;CAClD,MAAM,SAAS,MAAM,qBAAqB;CAC1C,MAAM,MAAM,SAAS,OAAO,GAAG,KAAK;CACpC,MAAM,QAAQ,IAAI,iBAAiB;AACnC,KAAI,MAAM,QAAQ,QAAS,OAAM,IAAI,WAAW,MAAM,QAAQ,QAAQ;AACtE,KAAI,MAAM,QAAQ,WAChB,OAAM,IAAI,cAAc,OAAO,MAAM,QAAQ,WAAW,CAAC;AAC3D,KAAI,MAAM,QAAQ,aAChB,OAAM,IAAI,gBAAgB,OAAO,MAAM,QAAQ,aAAa,CAAC;CAE/D,MAAM,WAAW,MAAM,MAAM,MAAM,SAAS,MAAM,GAAG,IAAI,GAAG,SAAS;EACnE,QAAQ,SAAS,SAAS;EAC1B,SAAS,SACL;GAAE,GAAG,MAAM;GAAS,gBAAgB;GAAoB,GACxD,EAAE,GAAG,MAAM,SAAS;EACxB,aAAa,MAAM;EACnB,QAAQ,MAAM;EACd,GAAI,SACA,EACE,MAAM,KAAK,UAAU;GACnB,QAAQ;GACR,QAAQ,OAAO,YAAY,MAAM;GAClC,CAAC,EACH,GACD,EAAE;EACP,CAAC;AACF,KAAI,SAAS,WAAW,IAAK,OAAM,IAAI,mCAAmC;AAC1E,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,kCAAkC,SAAS,OAAO,IAAI;CACxE,MAAM,WAAW,iCAAiC,MAAM,SAAS,MAAM,CAAC;AACxE,KAAI,CAAC,SAAU,OAAM,IAAI,MAAM,yCAAyC;AACxE,QAAO"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/lib/learning-setup.ts
|
|
3
|
+
const LEARNING_SETUP_STORAGE_KEY = "cpk:inspector:learning-setup:v1";
|
|
4
|
+
const LEARNING_SETUP_MAX_AGE_MS = 10080 * 60 * 1e3;
|
|
5
|
+
let inMemoryMarker = null;
|
|
6
|
+
function normalizeLearningRuntimeUrl(runtimeUrl, baseUri) {
|
|
7
|
+
try {
|
|
8
|
+
const browserBaseUri = baseUri ?? (typeof document === "undefined" ? void 0 : document.baseURI);
|
|
9
|
+
const url = browserBaseUri ? new URL(runtimeUrl, browserBaseUri) : new URL(runtimeUrl);
|
|
10
|
+
url.search = "";
|
|
11
|
+
url.hash = "";
|
|
12
|
+
url.pathname = url.pathname === "/" ? "/" : url.pathname.replace(/\/+$/u, "");
|
|
13
|
+
return url.toString();
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function parseMarker(raw, now) {
|
|
19
|
+
if (!raw) return null;
|
|
20
|
+
try {
|
|
21
|
+
const value = JSON.parse(raw);
|
|
22
|
+
const started = typeof value.startedAt === "string" ? Date.parse(value.startedAt) : NaN;
|
|
23
|
+
if (value.version !== 1 || typeof value.runtimeUrl !== "string" || value.agentId !== null && typeof value.agentId !== "string" || !Number.isFinite(started) || started > now || now - started > LEARNING_SETUP_MAX_AGE_MS) return null;
|
|
24
|
+
return value;
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function readLearningSetupMarker(now = Date.now()) {
|
|
30
|
+
try {
|
|
31
|
+
const raw = localStorage.getItem(LEARNING_SETUP_STORAGE_KEY);
|
|
32
|
+
const persisted = parseMarker(raw, now);
|
|
33
|
+
if (persisted) return persisted;
|
|
34
|
+
if (raw !== null) localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);
|
|
35
|
+
} catch {}
|
|
36
|
+
return parseMarker(inMemoryMarker ? JSON.stringify(inMemoryMarker) : null, now);
|
|
37
|
+
}
|
|
38
|
+
function writeLearningSetupMarker(input) {
|
|
39
|
+
const runtimeUrl = normalizeLearningRuntimeUrl(input.runtimeUrl);
|
|
40
|
+
if (!runtimeUrl) throw new Error("Runtime URL is unavailable.");
|
|
41
|
+
const marker = {
|
|
42
|
+
version: 1,
|
|
43
|
+
runtimeUrl,
|
|
44
|
+
agentId: input.agentId,
|
|
45
|
+
startedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString()
|
|
46
|
+
};
|
|
47
|
+
inMemoryMarker = marker;
|
|
48
|
+
try {
|
|
49
|
+
localStorage.setItem(LEARNING_SETUP_STORAGE_KEY, JSON.stringify(marker));
|
|
50
|
+
} catch {}
|
|
51
|
+
return marker;
|
|
52
|
+
}
|
|
53
|
+
function clearLearningSetupMarker() {
|
|
54
|
+
inMemoryMarker = null;
|
|
55
|
+
try {
|
|
56
|
+
localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
function learningSetupMarkerMatches(marker, runtimeUrl, agentId) {
|
|
60
|
+
return marker !== null && marker.runtimeUrl === normalizeLearningRuntimeUrl(runtimeUrl) && marker.agentId === agentId;
|
|
61
|
+
}
|
|
62
|
+
/** Keeps multiple Inspector instances on the same origin in sync. */
|
|
63
|
+
function subscribeToLearningSetupMarker(listener) {
|
|
64
|
+
const handleStorage = (event) => {
|
|
65
|
+
if (event.key === LEARNING_SETUP_STORAGE_KEY) {
|
|
66
|
+
const marker = parseMarker(event.newValue, Date.now());
|
|
67
|
+
if (event.newValue !== null && marker === null) try {
|
|
68
|
+
localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);
|
|
69
|
+
} catch {}
|
|
70
|
+
listener(marker);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
window.addEventListener("storage", handleStorage);
|
|
74
|
+
return () => window.removeEventListener("storage", handleStorage);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
exports.clearLearningSetupMarker = clearLearningSetupMarker;
|
|
79
|
+
exports.learningSetupMarkerMatches = learningSetupMarkerMatches;
|
|
80
|
+
exports.readLearningSetupMarker = readLearningSetupMarker;
|
|
81
|
+
exports.subscribeToLearningSetupMarker = subscribeToLearningSetupMarker;
|
|
82
|
+
exports.writeLearningSetupMarker = writeLearningSetupMarker;
|
|
83
|
+
//# sourceMappingURL=learning-setup.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learning-setup.cjs","names":[],"sources":["../../src/lib/learning-setup.ts"],"sourcesContent":["export const LEARNING_SETUP_STORAGE_KEY = \"cpk:inspector:learning-setup:v1\";\nexport const LEARNING_SETUP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1_000;\n\nexport interface LearningSetupMarker {\n readonly version: 1;\n readonly runtimeUrl: string;\n readonly agentId: string | null;\n readonly startedAt: string;\n}\n\nlet inMemoryMarker: LearningSetupMarker | null = null;\n\nexport function normalizeLearningRuntimeUrl(\n runtimeUrl: string,\n baseUri?: string,\n): string | null {\n try {\n const browserBaseUri =\n baseUri ??\n (typeof document === \"undefined\" ? undefined : document.baseURI);\n const url = browserBaseUri\n ? new URL(runtimeUrl, browserBaseUri)\n : new URL(runtimeUrl);\n url.search = \"\";\n url.hash = \"\";\n url.pathname =\n url.pathname === \"/\" ? \"/\" : url.pathname.replace(/\\/+$/u, \"\");\n return url.toString();\n } catch {\n return null;\n }\n}\n\nfunction parseMarker(\n raw: string | null,\n now: number,\n): LearningSetupMarker | null {\n if (!raw) return null;\n try {\n const value = JSON.parse(raw) as Partial<LearningSetupMarker>;\n const started =\n typeof value.startedAt === \"string\" ? Date.parse(value.startedAt) : NaN;\n if (\n value.version !== 1 ||\n typeof value.runtimeUrl !== \"string\" ||\n (value.agentId !== null && typeof value.agentId !== \"string\") ||\n !Number.isFinite(started) ||\n started > now ||\n now - started > LEARNING_SETUP_MAX_AGE_MS\n ) {\n return null;\n }\n return value as LearningSetupMarker;\n } catch {\n return null;\n }\n}\n\nexport function readLearningSetupMarker(\n now = Date.now(),\n): LearningSetupMarker | null {\n try {\n const raw = localStorage.getItem(LEARNING_SETUP_STORAGE_KEY);\n const persisted = parseMarker(raw, now);\n if (persisted) return persisted;\n if (raw !== null) localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);\n } catch {\n // The page-local fallback below preserves the interaction.\n }\n return parseMarker(\n inMemoryMarker ? JSON.stringify(inMemoryMarker) : null,\n now,\n );\n}\n\nexport function writeLearningSetupMarker(input: {\n readonly runtimeUrl: string;\n readonly agentId: string | null;\n readonly now?: Date;\n}): LearningSetupMarker {\n const runtimeUrl = normalizeLearningRuntimeUrl(input.runtimeUrl);\n if (!runtimeUrl) throw new Error(\"Runtime URL is unavailable.\");\n const marker: LearningSetupMarker = {\n version: 1,\n runtimeUrl,\n agentId: input.agentId,\n startedAt: (input.now ?? new Date()).toISOString(),\n };\n inMemoryMarker = marker;\n try {\n localStorage.setItem(LEARNING_SETUP_STORAGE_KEY, JSON.stringify(marker));\n } catch {\n // Storage is optional; retain the marker in memory.\n }\n return marker;\n}\n\nexport function clearLearningSetupMarker(): void {\n inMemoryMarker = null;\n try {\n localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);\n } catch {\n // Best effort only.\n }\n}\n\nexport function learningSetupMarkerMatches(\n marker: LearningSetupMarker | null,\n runtimeUrl: string,\n agentId: string | null,\n): boolean {\n return (\n marker !== null &&\n marker.runtimeUrl === normalizeLearningRuntimeUrl(runtimeUrl) &&\n marker.agentId === agentId\n );\n}\n\n/** Keeps multiple Inspector instances on the same origin in sync. */\nexport function subscribeToLearningSetupMarker(\n listener: (marker: LearningSetupMarker | null) => void,\n): () => void {\n const handleStorage = (event: StorageEvent) => {\n if (event.key === LEARNING_SETUP_STORAGE_KEY) {\n const marker = parseMarker(event.newValue, Date.now());\n if (event.newValue !== null && marker === null) {\n try {\n localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);\n } catch {\n // Storage is optional; still notify the listener below.\n }\n }\n listener(marker);\n }\n };\n window.addEventListener(\"storage\", handleStorage);\n return () => window.removeEventListener(\"storage\", handleStorage);\n}\n\nexport const _test = {\n resetMemory: () => {\n inMemoryMarker = null;\n },\n};\n"],"mappings":";;AAAA,MAAa,6BAA6B;AAC1C,MAAa,4BAA4B,QAAc,KAAK;AAS5D,IAAI,iBAA6C;AAEjD,SAAgB,4BACd,YACA,SACe;AACf,KAAI;EACF,MAAM,iBACJ,YACC,OAAO,aAAa,cAAc,SAAY,SAAS;EAC1D,MAAM,MAAM,iBACR,IAAI,IAAI,YAAY,eAAe,GACnC,IAAI,IAAI,WAAW;AACvB,MAAI,SAAS;AACb,MAAI,OAAO;AACX,MAAI,WACF,IAAI,aAAa,MAAM,MAAM,IAAI,SAAS,QAAQ,SAAS,GAAG;AAChE,SAAO,IAAI,UAAU;SACf;AACN,SAAO;;;AAIX,SAAS,YACP,KACA,KAC4B;AAC5B,KAAI,CAAC,IAAK,QAAO;AACjB,KAAI;EACF,MAAM,QAAQ,KAAK,MAAM,IAAI;EAC7B,MAAM,UACJ,OAAO,MAAM,cAAc,WAAW,KAAK,MAAM,MAAM,UAAU,GAAG;AACtE,MACE,MAAM,YAAY,KAClB,OAAO,MAAM,eAAe,YAC3B,MAAM,YAAY,QAAQ,OAAO,MAAM,YAAY,YACpD,CAAC,OAAO,SAAS,QAAQ,IACzB,UAAU,OACV,MAAM,UAAU,0BAEhB,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;AAIX,SAAgB,wBACd,MAAM,KAAK,KAAK,EACY;AAC5B,KAAI;EACF,MAAM,MAAM,aAAa,QAAQ,2BAA2B;EAC5D,MAAM,YAAY,YAAY,KAAK,IAAI;AACvC,MAAI,UAAW,QAAO;AACtB,MAAI,QAAQ,KAAM,cAAa,WAAW,2BAA2B;SAC/D;AAGR,QAAO,YACL,iBAAiB,KAAK,UAAU,eAAe,GAAG,MAClD,IACD;;AAGH,SAAgB,yBAAyB,OAIjB;CACtB,MAAM,aAAa,4BAA4B,MAAM,WAAW;AAChE,KAAI,CAAC,WAAY,OAAM,IAAI,MAAM,8BAA8B;CAC/D,MAAM,SAA8B;EAClC,SAAS;EACT;EACA,SAAS,MAAM;EACf,YAAY,MAAM,uBAAO,IAAI,MAAM,EAAE,aAAa;EACnD;AACD,kBAAiB;AACjB,KAAI;AACF,eAAa,QAAQ,4BAA4B,KAAK,UAAU,OAAO,CAAC;SAClE;AAGR,QAAO;;AAGT,SAAgB,2BAAiC;AAC/C,kBAAiB;AACjB,KAAI;AACF,eAAa,WAAW,2BAA2B;SAC7C;;AAKV,SAAgB,2BACd,QACA,YACA,SACS;AACT,QACE,WAAW,QACX,OAAO,eAAe,4BAA4B,WAAW,IAC7D,OAAO,YAAY;;;AAKvB,SAAgB,+BACd,UACY;CACZ,MAAM,iBAAiB,UAAwB;AAC7C,MAAI,MAAM,QAAQ,4BAA4B;GAC5C,MAAM,SAAS,YAAY,MAAM,UAAU,KAAK,KAAK,CAAC;AACtD,OAAI,MAAM,aAAa,QAAQ,WAAW,KACxC,KAAI;AACF,iBAAa,WAAW,2BAA2B;WAC7C;AAIV,YAAS,OAAO;;;AAGpB,QAAO,iBAAiB,WAAW,cAAc;AACjD,cAAa,OAAO,oBAAoB,WAAW,cAAc"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/lib/learning-setup.ts
|
|
2
|
+
const LEARNING_SETUP_STORAGE_KEY = "cpk:inspector:learning-setup:v1";
|
|
3
|
+
const LEARNING_SETUP_MAX_AGE_MS = 10080 * 60 * 1e3;
|
|
4
|
+
let inMemoryMarker = null;
|
|
5
|
+
function normalizeLearningRuntimeUrl(runtimeUrl, baseUri) {
|
|
6
|
+
try {
|
|
7
|
+
const browserBaseUri = baseUri ?? (typeof document === "undefined" ? void 0 : document.baseURI);
|
|
8
|
+
const url = browserBaseUri ? new URL(runtimeUrl, browserBaseUri) : new URL(runtimeUrl);
|
|
9
|
+
url.search = "";
|
|
10
|
+
url.hash = "";
|
|
11
|
+
url.pathname = url.pathname === "/" ? "/" : url.pathname.replace(/\/+$/u, "");
|
|
12
|
+
return url.toString();
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function parseMarker(raw, now) {
|
|
18
|
+
if (!raw) return null;
|
|
19
|
+
try {
|
|
20
|
+
const value = JSON.parse(raw);
|
|
21
|
+
const started = typeof value.startedAt === "string" ? Date.parse(value.startedAt) : NaN;
|
|
22
|
+
if (value.version !== 1 || typeof value.runtimeUrl !== "string" || value.agentId !== null && typeof value.agentId !== "string" || !Number.isFinite(started) || started > now || now - started > LEARNING_SETUP_MAX_AGE_MS) return null;
|
|
23
|
+
return value;
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function readLearningSetupMarker(now = Date.now()) {
|
|
29
|
+
try {
|
|
30
|
+
const raw = localStorage.getItem(LEARNING_SETUP_STORAGE_KEY);
|
|
31
|
+
const persisted = parseMarker(raw, now);
|
|
32
|
+
if (persisted) return persisted;
|
|
33
|
+
if (raw !== null) localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);
|
|
34
|
+
} catch {}
|
|
35
|
+
return parseMarker(inMemoryMarker ? JSON.stringify(inMemoryMarker) : null, now);
|
|
36
|
+
}
|
|
37
|
+
function writeLearningSetupMarker(input) {
|
|
38
|
+
const runtimeUrl = normalizeLearningRuntimeUrl(input.runtimeUrl);
|
|
39
|
+
if (!runtimeUrl) throw new Error("Runtime URL is unavailable.");
|
|
40
|
+
const marker = {
|
|
41
|
+
version: 1,
|
|
42
|
+
runtimeUrl,
|
|
43
|
+
agentId: input.agentId,
|
|
44
|
+
startedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString()
|
|
45
|
+
};
|
|
46
|
+
inMemoryMarker = marker;
|
|
47
|
+
try {
|
|
48
|
+
localStorage.setItem(LEARNING_SETUP_STORAGE_KEY, JSON.stringify(marker));
|
|
49
|
+
} catch {}
|
|
50
|
+
return marker;
|
|
51
|
+
}
|
|
52
|
+
function clearLearningSetupMarker() {
|
|
53
|
+
inMemoryMarker = null;
|
|
54
|
+
try {
|
|
55
|
+
localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);
|
|
56
|
+
} catch {}
|
|
57
|
+
}
|
|
58
|
+
function learningSetupMarkerMatches(marker, runtimeUrl, agentId) {
|
|
59
|
+
return marker !== null && marker.runtimeUrl === normalizeLearningRuntimeUrl(runtimeUrl) && marker.agentId === agentId;
|
|
60
|
+
}
|
|
61
|
+
/** Keeps multiple Inspector instances on the same origin in sync. */
|
|
62
|
+
function subscribeToLearningSetupMarker(listener) {
|
|
63
|
+
const handleStorage = (event) => {
|
|
64
|
+
if (event.key === LEARNING_SETUP_STORAGE_KEY) {
|
|
65
|
+
const marker = parseMarker(event.newValue, Date.now());
|
|
66
|
+
if (event.newValue !== null && marker === null) try {
|
|
67
|
+
localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);
|
|
68
|
+
} catch {}
|
|
69
|
+
listener(marker);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
window.addEventListener("storage", handleStorage);
|
|
73
|
+
return () => window.removeEventListener("storage", handleStorage);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { clearLearningSetupMarker, learningSetupMarkerMatches, readLearningSetupMarker, subscribeToLearningSetupMarker, writeLearningSetupMarker };
|
|
78
|
+
//# sourceMappingURL=learning-setup.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learning-setup.mjs","names":[],"sources":["../../src/lib/learning-setup.ts"],"sourcesContent":["export const LEARNING_SETUP_STORAGE_KEY = \"cpk:inspector:learning-setup:v1\";\nexport const LEARNING_SETUP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1_000;\n\nexport interface LearningSetupMarker {\n readonly version: 1;\n readonly runtimeUrl: string;\n readonly agentId: string | null;\n readonly startedAt: string;\n}\n\nlet inMemoryMarker: LearningSetupMarker | null = null;\n\nexport function normalizeLearningRuntimeUrl(\n runtimeUrl: string,\n baseUri?: string,\n): string | null {\n try {\n const browserBaseUri =\n baseUri ??\n (typeof document === \"undefined\" ? undefined : document.baseURI);\n const url = browserBaseUri\n ? new URL(runtimeUrl, browserBaseUri)\n : new URL(runtimeUrl);\n url.search = \"\";\n url.hash = \"\";\n url.pathname =\n url.pathname === \"/\" ? \"/\" : url.pathname.replace(/\\/+$/u, \"\");\n return url.toString();\n } catch {\n return null;\n }\n}\n\nfunction parseMarker(\n raw: string | null,\n now: number,\n): LearningSetupMarker | null {\n if (!raw) return null;\n try {\n const value = JSON.parse(raw) as Partial<LearningSetupMarker>;\n const started =\n typeof value.startedAt === \"string\" ? Date.parse(value.startedAt) : NaN;\n if (\n value.version !== 1 ||\n typeof value.runtimeUrl !== \"string\" ||\n (value.agentId !== null && typeof value.agentId !== \"string\") ||\n !Number.isFinite(started) ||\n started > now ||\n now - started > LEARNING_SETUP_MAX_AGE_MS\n ) {\n return null;\n }\n return value as LearningSetupMarker;\n } catch {\n return null;\n }\n}\n\nexport function readLearningSetupMarker(\n now = Date.now(),\n): LearningSetupMarker | null {\n try {\n const raw = localStorage.getItem(LEARNING_SETUP_STORAGE_KEY);\n const persisted = parseMarker(raw, now);\n if (persisted) return persisted;\n if (raw !== null) localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);\n } catch {\n // The page-local fallback below preserves the interaction.\n }\n return parseMarker(\n inMemoryMarker ? JSON.stringify(inMemoryMarker) : null,\n now,\n );\n}\n\nexport function writeLearningSetupMarker(input: {\n readonly runtimeUrl: string;\n readonly agentId: string | null;\n readonly now?: Date;\n}): LearningSetupMarker {\n const runtimeUrl = normalizeLearningRuntimeUrl(input.runtimeUrl);\n if (!runtimeUrl) throw new Error(\"Runtime URL is unavailable.\");\n const marker: LearningSetupMarker = {\n version: 1,\n runtimeUrl,\n agentId: input.agentId,\n startedAt: (input.now ?? new Date()).toISOString(),\n };\n inMemoryMarker = marker;\n try {\n localStorage.setItem(LEARNING_SETUP_STORAGE_KEY, JSON.stringify(marker));\n } catch {\n // Storage is optional; retain the marker in memory.\n }\n return marker;\n}\n\nexport function clearLearningSetupMarker(): void {\n inMemoryMarker = null;\n try {\n localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);\n } catch {\n // Best effort only.\n }\n}\n\nexport function learningSetupMarkerMatches(\n marker: LearningSetupMarker | null,\n runtimeUrl: string,\n agentId: string | null,\n): boolean {\n return (\n marker !== null &&\n marker.runtimeUrl === normalizeLearningRuntimeUrl(runtimeUrl) &&\n marker.agentId === agentId\n );\n}\n\n/** Keeps multiple Inspector instances on the same origin in sync. */\nexport function subscribeToLearningSetupMarker(\n listener: (marker: LearningSetupMarker | null) => void,\n): () => void {\n const handleStorage = (event: StorageEvent) => {\n if (event.key === LEARNING_SETUP_STORAGE_KEY) {\n const marker = parseMarker(event.newValue, Date.now());\n if (event.newValue !== null && marker === null) {\n try {\n localStorage.removeItem(LEARNING_SETUP_STORAGE_KEY);\n } catch {\n // Storage is optional; still notify the listener below.\n }\n }\n listener(marker);\n }\n };\n window.addEventListener(\"storage\", handleStorage);\n return () => window.removeEventListener(\"storage\", handleStorage);\n}\n\nexport const _test = {\n resetMemory: () => {\n inMemoryMarker = null;\n },\n};\n"],"mappings":";AAAA,MAAa,6BAA6B;AAC1C,MAAa,4BAA4B,QAAc,KAAK;AAS5D,IAAI,iBAA6C;AAEjD,SAAgB,4BACd,YACA,SACe;AACf,KAAI;EACF,MAAM,iBACJ,YACC,OAAO,aAAa,cAAc,SAAY,SAAS;EAC1D,MAAM,MAAM,iBACR,IAAI,IAAI,YAAY,eAAe,GACnC,IAAI,IAAI,WAAW;AACvB,MAAI,SAAS;AACb,MAAI,OAAO;AACX,MAAI,WACF,IAAI,aAAa,MAAM,MAAM,IAAI,SAAS,QAAQ,SAAS,GAAG;AAChE,SAAO,IAAI,UAAU;SACf;AACN,SAAO;;;AAIX,SAAS,YACP,KACA,KAC4B;AAC5B,KAAI,CAAC,IAAK,QAAO;AACjB,KAAI;EACF,MAAM,QAAQ,KAAK,MAAM,IAAI;EAC7B,MAAM,UACJ,OAAO,MAAM,cAAc,WAAW,KAAK,MAAM,MAAM,UAAU,GAAG;AACtE,MACE,MAAM,YAAY,KAClB,OAAO,MAAM,eAAe,YAC3B,MAAM,YAAY,QAAQ,OAAO,MAAM,YAAY,YACpD,CAAC,OAAO,SAAS,QAAQ,IACzB,UAAU,OACV,MAAM,UAAU,0BAEhB,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;AAIX,SAAgB,wBACd,MAAM,KAAK,KAAK,EACY;AAC5B,KAAI;EACF,MAAM,MAAM,aAAa,QAAQ,2BAA2B;EAC5D,MAAM,YAAY,YAAY,KAAK,IAAI;AACvC,MAAI,UAAW,QAAO;AACtB,MAAI,QAAQ,KAAM,cAAa,WAAW,2BAA2B;SAC/D;AAGR,QAAO,YACL,iBAAiB,KAAK,UAAU,eAAe,GAAG,MAClD,IACD;;AAGH,SAAgB,yBAAyB,OAIjB;CACtB,MAAM,aAAa,4BAA4B,MAAM,WAAW;AAChE,KAAI,CAAC,WAAY,OAAM,IAAI,MAAM,8BAA8B;CAC/D,MAAM,SAA8B;EAClC,SAAS;EACT;EACA,SAAS,MAAM;EACf,YAAY,MAAM,uBAAO,IAAI,MAAM,EAAE,aAAa;EACnD;AACD,kBAAiB;AACjB,KAAI;AACF,eAAa,QAAQ,4BAA4B,KAAK,UAAU,OAAO,CAAC;SAClE;AAGR,QAAO;;AAGT,SAAgB,2BAAiC;AAC/C,kBAAiB;AACjB,KAAI;AACF,eAAa,WAAW,2BAA2B;SAC7C;;AAKV,SAAgB,2BACd,QACA,YACA,SACS;AACT,QACE,WAAW,QACX,OAAO,eAAe,4BAA4B,WAAW,IAC7D,OAAO,YAAY;;;AAKvB,SAAgB,+BACd,UACY;CACZ,MAAM,iBAAiB,UAAwB;AAC7C,MAAI,MAAM,QAAQ,4BAA4B;GAC5C,MAAM,SAAS,YAAY,MAAM,UAAU,KAAK,KAAK,CAAC;AACtD,OAAI,MAAM,aAAa,QAAQ,WAAW,KACxC,KAAI;AACF,iBAAa,WAAW,2BAA2B;WAC7C;AAIV,YAAS,OAAO;;;AAGpB,QAAO,iBAAiB,WAAW,cAAc;AACjD,cAAa,OAAO,oBAAoB,WAAW,cAAc"}
|