Commit Graph

54 Commits

Author SHA1 Message Date
Jordan Ritter 91dd4b13fa feat(vue): add v1 wrappers, A2UI Vue-native renderer, and
CR parity fixes

V1 CopilotKit.vue provider wrapper with backward-compatible
API, A2UI adapter/surface/catalog context/built-in tool-call
renderer for Vue-native rendering, capability and custom
message hooks, config allowlist and release config updates.
2026-05-13 15:50:13 -07:00
github-actions[bot] d54ec8b1d6 style: auto-fix formatting 2026-05-11 21:33:25 +00:00
Martha Schumann bd968fabaf fix(inspector/telemetry): fix banner_viewed race and dead opt-out check
- Defer trackBannerViewed until runtime connection is established via
  pendingBannerViewed + flushPendingBannerViewed(), preventing the race
  where the CDN response beats the /info handshake and fires the event
  before core.telemetryDisabled is known
- Remove dead isTelemetryOptedOut() short-circuit from track(); opt-out
  is enforced at call sites via core.telemetryDisabled, not localStorage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 14:31:36 -07:00
Martha Schumann aee390ab4d refactor(inspector): remove internal gap labels from code comments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
Martha Schumann fa75abf23c fix(inspector/telemetry): address code review findings
- Don't fire banner_clicked on copy-button clicks (move track call to
  the non-copy-button branch of handleAnnouncementContentClick)
- Defer ensureTelemetryDistinctId() to runtime connection so no UUID
  is written to localStorage when COPILOTKIT_TELEMETRY_DISABLED is set
- Remove setTelemetryOptOut re-export from telemetry.ts (no production
  caller; tests already import directly from persistence.ts)
- Fix docs: replace Privacy tab toggle description with env var opt-out

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
github-actions[bot] 044bb12e69 style: auto-fix formatting 2026-05-11 15:43:17 -05:00
Martha Schumann 7234906d05 fix(inspector/telemetry): send distinct ID via X-CopilotKit-Telemetry-Id header
Per Ben Taylor: the ingest lambda parses the X-CopilotKit-Telemetry-Id header
as telemetry_id for the distinct ID. Send it as a header in addition to keeping
it in the POST body properties.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
github-actions[bot] 7acf886bf6 style: auto-fix formatting 2026-05-11 15:43:17 -05:00
Martha Schumann ce35cba85e feat(inspector/telemetry): propagate telemetryDisabled from runtime env var through inspector
- Add telemetryDisabled to RuntimeInfo from COPILOTKIT_TELEMETRY_DISABLED/DO_NOT_TRACK env vars
- Mirror through AgentRegistry and expose via CopilotKitCore getter
- Guard track calls, URL param appending, and console disclosure on core.telemetryDisabled
- Move maybeShowDisclosure() to onRuntimeConnectionStatusChanged (fires after core attaches)
- Update docs to replace localStorage toggle description with env var approach
- Add telemetryDisabled test suite to get-runtime-info tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
github-actions[bot] 78e8c5013b style: auto-fix formatting 2026-05-11 15:43:17 -05:00
Martha Schumann af275506fd refactor(inspector): replace privacy tab with cog settings button (OSS-96 feedback)
- Remove "Privacy" from the nav tab row; move settings access to a cog
  button (Settings icon) in the top-right header, between dock controls
  and the close button. Clicking the cog toggles the settings panel;
  clicking again returns to the previous view.
- Settings panel replaces the privacy panel: shows the same transparency
  copy but replaces the checkbox toggle with an "I want to opt out —
  show me how →" link to the docs. Opt-out is via COPILOTKIT_TELEMETRY_DISABLED
  (env variable, documented at docs.copilotkit.ai/telemetry) rather than
  a per-browser localStorage toggle.
- Remove isTelemetryOptedOut / setTelemetryOptOut from index.ts (no longer
  used; the toggle UI is gone). Underlying persistence exports remain in
  telemetry.ts for future use.
- Fix cpk-tab-icon: add display:inline-flex + flex-shrink:0 + align-items:center
  to prevent icon containers from collapsing on the x-axis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
Martha Schumann db17476883 fix(inspector): update wire body shape + typed helpers + full test coverage (OSS-96)
- Move `package` from properties string to top-level `{ name }` object per
  Ben's confirmed IngestPayload schema (telemetry-sink-ingest/index.ts:127-134)
- Add typed per-event helpers trackBannerViewed/trackBannerClicked/trackThreadsTabClicked
  to enforce property shapes at call sites and prevent PII leakage under wrong keys
- Add trackBannerClickedOnce guard in index.ts (per-mount Set keyed by
  banner_id + cta) to prevent banner_clicked inflation on repeated clicks
- Fix handleTelemetryOptOutToggle: replace ?? true fallback with
  instanceof HTMLInputElement guard (wrong fallback was a privacy bug)
- Add threadsTabClicked re-selection guard (skip if already on threads tab)
- Replace getTelemetryDistinctIdForUrl() call on mount with ensureTelemetryDistinctId()
- Add inMemoryFallbackId in persistence.ts for funnel coherence when
  localStorage is unavailable (same UUID returned per page load)
- Add _resetTelemetryPersistenceForTesting() for test isolation
- Remove @copilotkit/shared dep from telemetry-disclosure.ts (inline
  env-var check; keeps module self-contained and testable in isolation)
- Add clearMocks: true to web-inspector vitest config (fixes spy call
  history accumulating across tests)
- Expand telemetry.test.ts to 22 tests covering wire body shape, opt-out,
  5 error-resilience paths, typed helpers, distinct ID lifecycle (SSR +
  localStorage-throws + funnel coherence), maybeShowDisclosure, and
  getTelemetryDistinctIdForUrl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
github-actions[bot] 9e08ce9ee8 style: auto-fix formatting 2026-05-11 15:43:17 -05:00
Claude 7914275c99 feat(inspector): add anonymous interaction telemetry (OSS-96)
Three V1 funnel events from the inspector — oss.inspector.banner_viewed,
oss.inspector.banner_clicked, oss.inspector.threads_tab_clicked — plus a
privacy panel for opt-out, a first-run console disclosure on inspector
mount and runtime startup, and inspector content added to the canonical
/telemetry docs page on main.

Inspector POSTs directly from the browser to telemetry.copilotkit.ai/ingest
(per ticket: URL is intentionally clearly named for transparency in DevTools).
Inline fetch POST in lib/telemetry.ts — no @copilotkit/shared dep on the
inspector, no dependency on any non-main branch.

Wire body shape (conservative; needs Ben confirmation):
  POST https://telemetry.copilotkit.ai/ingest
  { event, properties: { ...caller, distinct_id, package }, ts }
If the lambda expects a richer envelope, update the single JSON.stringify
in lib/telemetry.ts.

Privacy invariants:
- Opt-out toggle short-circuits before any network call (verified by test).
- Properties are scoped to event metadata only — no message content, agent
  state, prompts, completions, banner markdown. Negative test pins the wire.
- Anonymous distinct ID (UUID v4 in localStorage) set on inspector load and
  propagated onto banner CTA links as ?posthog_distinct_id=<uuid> so the
  destination site can posthog.alias() and close the
  banner_viewed → banner_clicked → signup_attributed funnel. URL param
  suppressed when opted out.
- Console disclosure on first inspector mount and runtime startup. Both
  link to https://docs.copilotkit.ai/telemetry.

Plan gaps addressed:
- CTA name on banner_clicked: cta:'body'|'dismiss' (click location) plus
  optional cta_label read defensively. Sam: confirm dismiss treatment.
- De-anon opt-out folded into the single toggle. Docs say so explicitly.
- banner_viewed dedup: per-instance Set<string> keyed by timestamp.
- EPIC consent / pixel review: out of scope for this PR; flagged at merge.

Deferred for V1.1:
- Wire body shape (Ben).
- Event-type allowlist for oss.inspector.* (Ben — oss-path-to-production).
- posthog_distinct_id URL-param key name (Ben/Tyler/website team).

Refs https://linear.app/copilotkit/issue/OSS-96
2026-05-11 15:43:17 -05:00
Markus Ecker 79fb5af452 Merge remote-tracking branch 'origin/main' into mme/register-proxied-agent
# Conflicts:
#	packages/react-core/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx
#	packages/react-core/src/v2/hooks/use-agent.tsx
#	packages/web-inspector/src/styles/generated.css
2026-05-07 14:20:55 +02:00
Tyler Slaton 102b5a9e1f feat(inspector): remove invite-code gate on Threads
Threads is no longer behind a private-beta access code — drop the gate UI
(early-access card, unlocking card, code submission, cookie persistence)
and render the threads view unconditionally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-04 14:17:34 -07:00
Tyler Slaton aa394bbc9d fix(inspector): restore production announcement URL again
The prior commit accidentally re-included a local-only flip of
ANNOUNCEMENT_URL to the draft endpoint while staging the unrelated
copy-button timeout fix. Restore the production URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:28:29 -07:00
Tyler Slaton ecc54cca9c fix(inspector): scope copy-button reset timeouts per button
The previous copyResetTimeout field was a single instance-level number,
shared across every code block in a multi-block announcement. Clicking
Copy on block A then block B cancelled block A's reset timer, leaving
block A stuck on "Copied" forever.

Switch to a WeakMap<HTMLButtonElement, number> so each button manages
its own pending reset and is naturally cleaned up when the announcement
re-renders. Also keep aria-label in sync with the visible text label so
screen-reader users hear "Code copied" while sighted users see "Copied".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:26:51 -07:00
Tyler Slaton 55b25629a4 fix(inspector): harden announcement copy-button helpers and renderer
CR-loop fixes from a 7-agent unbiased review on the announcement banner
work:

- Replace deprecated unescape/escape with TextEncoder/TextDecoder in
  encodeBase64/decodeBase64, dropping the half-decoded fallback path.
- Drop unsafe `as HTMLElement` and `as HTMLButtonElement` casts in
  handleAnnouncementContentClick; the .announcement-code__copy selector
  does not enforce HTMLButtonElement, so use instanceof guards.
- Coalesce overlapping copy-button resets via a class field timeout id
  and a constant "Copy" label; previously a rapid double-click captured
  "Copied" as the original label and pinned the button text.
- Pass async: false to marked.parse for a type-honest string return.
- Fold escapeHtmlAttr into the module-level escapeHtml helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:21:37 -07:00
Tyler Slaton d45b04b605 refactor(inspector): reuse module-level escapeHtml in announcement renderer
Replaces the duplicate escapeHtmlText method with the existing module-level
escapeHtml helper that has identical behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:15:42 -07:00
Tyler Slaton c6f0fbe5dc fix(inspector): restore production announcement URL
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 13:05:39 -07:00
Tyler Slaton cbc1aa6ab8 fix(inspector): polish announcement banner styles and move into scroll area
- Differentiate h1/h2/h3 sizes and bump body type for readability
- Add code-block styling with horizontal scroll, trailing spacer, and a
  copy button (brand lavender on success)
- Move announcement banner from the non-scrollable header into the main
  scroll container so an expanded banner no longer pushes the resize
  handle and content off-screen

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 12:52:38 -07:00
Markus Ecker 7829191350 test(react-core): intelligence-indicator renderer + MemoizedCustomMessage gating signals
Adds three new memo gating signals to MemoizedCustomMessage so custom
message renderers stay reactive across the structural events that affect
"is this slot still authoritative?" decisions:

- numberOfMessagesInRun — invalidates when peers stream into the same run,
  so renderers gating on "last message of the run" stay correct.
- isInLatestRun — invalidates when a newer run starts, so renderers gating
  on "is this the latest activity?" can drop their badges on completed runs.
- isRunning (gated on isInLatestRun) — invalidates exactly twice per run on
  the latest run's slots (start, end), preserving the perf-test guarantee
  that completed runs' messages skip re-renders during streaming.

CopilotChatMessageView computes these per slot via getRunIdForMessage and
passes them down. Helper getNumberOfMessagesInRun lives next to the call
site for clarity.

New e2e test at CopilotKitProvider.intelligenceIndicator.e2e.test.tsx
exercises an "Using CopilotKit Intelligence" renderer that gates on:
position === "after", last-in-run, agent.isRunning, and run-is-latest.
The walkthrough scenario drives Run A then Run B with multiple messages
each, verifying the indicator only appears on the canonical slot at each
phase. Four condition-focused tests pin each gate individually.

Includes IsRunningAccurateMockAgent — a local subclass that makes run()
return a per-run observable terminating on RUN_FINISHED/RUN_ERROR. The
shared MockStepwiseAgent.run() returns the un-terminating subject for
backward compatibility, so emit(RUN_FINISHED) on it doesn't trigger
AbstractAgent's finalize → onRunFinalized → useAgent re-render path. The
subclass scopes the fix to this file without disturbing other tests.
2026-05-04 17:26:11 +02:00
Markus Ecker 762370a4e5 refactor: remove per-thread agent cloning, restore single registry agent per id
Reverts the cloning design from #3525 (useAgent per-thread clones, getThreadClone,
globalThreadCloneMap, cloneForThread) and #3630 (clone routing in activity renderers),
plus the inspector machinery that existed only to handle clones (onAgentRunStarted
subscriber + run-handler emissions from #3869, the connect-time emission from #3872,
and the agentRunThreadId map that read from it).

State-manager isClone composite-key path and SuggestionEngine consumerAgent param —
both added in #3525 to keep clones visible to bookkeeping — are gone too.

Restores agent.threadId = resolvedThreadId in CopilotChat (pre-#3525 behavior) and
swaps the inspector's agentRunThreadId map for a direct agent.threadId read.

Removes the DemoButtonAgent and /a2ui-demo page from the demo (added by #3630 as a
clone-fix repro).

Re-opens the original issue #2957 (CPK-7155): two CopilotChat instances with the same
agentId and different threadIds will share message state again. The follow-up is a
public registerProxiedAgent API so callers can opt into multiple frontend agents
proxying to the same runtime agent, without implicit per-thread cloning.
2026-05-04 13:27:04 +02:00
github-actions[bot] be5bb0070c style: auto-fix formatting 2026-05-01 03:08:26 +00:00
Martha Schumann 62b5252963 refactor(inspector): consolidate per-tab plumbing and template caches
Mechanical cleanup of the perf commit's three repeated patterns. No
behavioral change.

- Three `_xxxTplCache` fields collapse into a single
  `_panelTplCache: Map<ThreadDetailsTab, { key, tpl }>` with a shared
  `cachedPanelTpl(slot, key, build)` helper. Cache key is now a tuple
  compared element-wise by reference, so each panel passes everything
  the template depends on (conversation passes
  `[_conversation, _expandedTools, _expandedMessages]`) without
  duplicating the cache-check shape three times.
- Three sibling tab-content `<div>` blocks in render() collapse into one
  `TAB_LIST.map(...)` driven by a new `renderTabContent(id)` dispatcher.
- Tab-button click handler extracts to `activateTab(id)` plus
  `maybeFetchTabData(id)`, keeping the rAF-and-spinner dance and the
  lazy-fetch decision off the inline lambda.
- Two-rAF first-activation collapses to a single rAF: Lit batches the
  `_activatedTabs` add and the `_panelInitializing = false` clear into
  one update, so the second rAF was redundant.
- `highlightedJsonImpl` was a pass-through layer split out only to host
  the WeakMap memo; inline it back into `highlightedJson`.
- `ReturnType<typeof html>` swaps to the canonical `TemplateResult`
  type imported from lit.
- Class renames `CpkThreadDetails` → `ɵCpkThreadDetails` (already
  exported for tests; the prefix keeps the internal-API hint).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:52:36 -07:00
Martha Schumann 3328ae45f2 fix(inspector): widen conversation cache key, add panel spacing, cover cache invariants
Three follow-ups to the perf commit:

1. The conversation TemplateResult cache was keyed only on `_conversation`,
   so toggling a tool-call expand or "Show more" on a long message — both
   of which mutate `_expandedTools` / `_expandedMessages` without touching
   the conversation array — returned the pre-toggle template and the
   disclosure appeared broken. Widen the cache key to include both expand
   sets; production toggles already replace the Set instance, so reference
   equality flips correctly.

2. Wrapping each tab in a panel <div> for the keep-mounted approach broke
   the `gap` flow that previously cascaded from `.cpk-td__content > *`.
   Add a `.cpk-td__panel` class with `display:flex; flex-direction:column;
   gap:12px` so conversation items and event rows have breathing room.

3. Export the `ɵCpkThreadDetails` class so unit tests can pin down the
   per-panel cache-invalidation contract. Add four tests in
   web-inspector.spec.ts covering: threadId change drops all three caches;
   conversation cache invalidates on `_conversation` reassignment;
   conversation cache invalidates on expand-state change (regression
   guard); state and events caches invalidate on their fetched data
   reassignment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:44:49 -07:00
Martha Schumann e05c5ef1b7 perf(inspector): keep tab DOM mounted, cache panel templates, defer off-screen events
Three layered fixes for the tab-switch jank on threads with many AG-UI
events. Symptoms: clicking back to a previously-opened tab took roughly
a second per switch on a thread with several hundred recorded events,
even though the underlying data was already cached.

1. Keep activated tab panels mounted. The render conditional swapped
   between renderConversation/renderState/renderEvents based on `_tab`,
   so Lit tore down the previous panel's DOM and rebuilt the next one
   from scratch on every switch. Now once a tab is activated, its panel
   stays mounted and inactive panels are hidden via `display:none`.
   Activated set resets on threadId change.

2. Memoize per-panel TemplateResults by data reference. Even with the
   panel mounted, render() still re-evaluated the template on every
   parent update, allocating fresh nested TemplateResults for every
   event row. Each render now returns the cached TemplateResult when
   `_conversation` / `_fetchedState` / events array references haven't
   changed; Lit then short-circuits the entire diff.

3. Defer layout for off-screen events with `content-visibility: auto`
   plus a `contain-intrinsic-size` hint. The cached-data switch back to
   the events panel still triggered a full layout pass over every
   recorded event, which on a 600-event thread shows up as a seconds-
   long freeze when the panel becomes visible. The browser now skips
   layout/paint for off-screen rows entirely.

Also adds a WeakMap memo around `highlightedJson` so identical event
payloads don't re-run JSON.stringify + the syntax-highlight regex pass
on every render.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:29:47 -07:00
Martha Schumann ce00492070 fix(inspector): treat tool calls with parsed args as DONE
Frontend-rendered generative-UI tools (charts, custom UI) never produce
a `role: tool` result message because they execute client-side, so the
prior `item.result ? DONE : PENDING` rule rendered them as PENDING
forever even after the run finished and the chart was on screen.

The args block being populated is itself the resolution signal for these
tools, so flip the condition: any tool call with parsed arguments shows
DONE. The badge stays PENDING only for the brief window where args have
not yet streamed in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:29:47 -07:00
Martha Schumann 762eb79d74 fix(inspector): lazy-load events/state + spinner so tab clicks feel instant
The threads-detail sub-tabs (Conversation, Agent State, AG-UI Events)
all fetched eagerly on threadId change. Against an Intelligence-backed
runtime, the AG-UI events response can be many MB; the JSON.parse alone
blocks the main thread for several seconds while the user is still on
the conversation tab. Any sub-tab click queued during that window
couldn't fire until the parse finished, so the tab itself appeared
unresponsive — the user perceived 15s of frozen UI before the panel
swapped, and the active-tab highlight didn't paint either.

Two fixes:

1. Defer the events / state fetches to first sub-tab click. Conversation
   stays eager because it's the default tab and visible immediately.
   When the user clicks an Agent State or AG-UI Events sub-tab the fetch
   kicks off then — so the heavy JSON.parse blocks AFTER the click has
   registered, not before.

2. Add a `_panelInitializing` flag set on tab change and cleared in the
   next animation frame. The render switches to a generic "Loading…"
   placeholder while the flag is true, so the active-tab highlight and
   spinner paint before the heavy per-tab render runs.

Total wait for events to display is unchanged; perceived responsiveness
of the click is now immediate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 15:43:29 -07:00
Martha Schumann 099700721c fix(inspector): silent re-fetch for live conversation updates
The first reactivity fix triggered a `_loadingMessages` flicker between
streaming chunks because every live re-fetch toggled the loading state
and replaced the conversation array wholesale. The silent flag suppresses
both: live re-fetches keep the loading indicator off and preserve the
last-good conversation on transient fetch errors. Initial threadId-change
fetches still show a real loading state.

Adds the same staleness guard the other tab fetches use (skip applying
results if `threadId` changed mid-flight) so a quick thread switch can't
leave the wrong thread's data on screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 14:27:57 -07:00
Martha Schumann 94305c0927 fix(inspector): re-fetch conversation when active agent emits new messages
The conversation view in cpk-thread-details only re-fetched on threadId
change, so live agent output during streaming wasn't visible until the
user switched threads (or unmounted/remounted the element by clicking
out and back in). Restoring the original conversationOverride channel
isn't viable because the parent's agentMessages map is keyed by agentId
(not threadId) and ConversationItem mapping lives in the child — passing
mapped messages would either leak across threads or duplicate the
runtime's AG-UI → ConversationItem conversion in the parent.

Instead, the parent now tracks each agent's currently-running threadId
(from `onAgentRunStarted`) and ticks a per-thread liveMessageVersion
counter every time `syncAgentMessages` fires for that agent. The counter
is passed to cpk-thread-details, which watches it in `updated()` and
re-fetches `/threads/:id/messages` when it changes for the same threadId.
The runtime endpoint is the single source of truth for conversation
shape, so streaming output flows in without any client-side mapping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 13:51:27 -07:00
Martha Schumann 3d6166611e refactor(runtime,inspector): tighten types and align JSDoc with reality
Type quality:
- intelligence/threads.ts handleGetThreadMessages: switch on the Message
  discriminant (role) and read narrowed fields directly. Removes
  `as Record<string, unknown>` laundering and chained `as` casts on
  toolCalls/function/arguments. AssistantMessage's toolCalls always have
  `function: { name, arguments }`, so the prior fallbacks (`tc.name`,
  `tc.args`) were dead branches.
- in-memory.ts getThreadState: import StateSnapshotEvent and use it
  instead of `(event as { snapshot?: unknown }).snapshot`.

Comment / API alignment:
- intelligence/threads.ts handleClearThreads JSDoc no longer claims the
  inspector calls this; the actual caller is the demo button.
- in-memory.ts clearThreads JSDoc updated to match.
- in-memory.ts getThreadEvents JSDoc no longer references a SQLite
  runner that does not exist; just describes the compaction logic.
- web-inspector lint fix: rename unused `changed` parameter to
  `_changed` per oxc no-unused-vars.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:45:07 -07:00
Martha Schumann daf52a2068 fix(inspector): plug data-staleness, error-swallowing, and parse silent-fail
Five behavioural fixes on cpk-thread-details / WebInspectorElement:

- fetchEvents/fetchState: mirror the AbortController pattern fetchMessages
  already uses. Without this, switching threads quickly (A→B) can leave
  the user looking at thread B with thread A's events/state when A's
  request resolves last.
- mapMessages: when JSON.parse fails on tool-call args or tool result
  content, log via console.error and attach __parseError + __raw on the
  parsed object instead of silently substituting `{}`. The inspector is a
  debugging surface; hiding malformed payloads defeats its purpose.
- fetchAnnouncement: keep the captured error and console.warn it. The
  prior `catch {}` swallowed Malformed-payload throws, JSON parse
  failures, and convertMarkdownToHtml exceptions silently.
- subscribeToThreadStore: also subscribe to ɵselectThreadsError, store
  per-agent in `_threadsErrorByAgent`, and surface in renderThreadsView /
  cpk-thread-list as an error state branch alongside empty/no-results.
  Previously a thread-store load failure (REST list rejection, Phoenix
  subscribe failure, retry exhaustion) left the user with stale data and
  no indication of failure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:43:50 -07:00
Martha Schumann 91986238fe feat(inspector): redesign threads early-access modal
Replaces the locked-card UI inside the threads gate with the new
private-beta modal: kicker pill, gradient "Threads" title with body
copy, three checkmark bullets, dark MonoPillButton CTA that opens the
HubSpot waitlist form in a new tab, and a dashed divider over the
invite-code row.

Adds an "unlocking" confirmation card (gradient circle, "Welcome to
Threads", "Loading your conversations…") shown for ~2s after a valid
code before the real Threads UI is revealed.

Invalid-code state now flashes a red input border + "That code isn't
valid. Double-check your invite email." copy that auto-clears after
1600ms, matching the design.

Backdrop (gradient + blurred ellipses) is intentionally preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:37:39 -07:00
Martha Schumann 2465d1f1b1 fix(inspector): pin panel toggle flush to drawer + slide drawer open/close
Drawer-toggle button used to get pushed off-screen when the drawer was
open because the tab list shared flex space with it. Toggle now stays
visible at all times, anchored at the right edge of the tabs row, and
visually distinct from the tabs (vertical separator, lavender filled
state when active — no bottom-border indicator that would mistake it
for "another tab").

The drawer slides open/closed via a width transition (always rendered)
instead of popping in/out, and the resize divider floats over the
drawer's left edge so the toggle and drawer touch directly with no
flex-gap between them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:37:38 -07:00
github-actions[bot] b3339c7c29 style: auto-fix formatting 2026-04-23 01:59:07 +00:00
Martha Schumann 68e247a78d refactor(inspector): port thread UI from Angular to Lit + add per-thread events/state endpoints
Replaces the Angular-backed cpk-thread-list / cpk-thread-details custom
elements with native Lit implementations inside @copilotkit/web-inspector,
so React, Vanilla, and any other non-Angular consumer of the inspector
gets full functionality without pulling the Angular runtime. The
@copilotkit/web-inspector-angular package is deleted entirely, and the
Angular demo no longer calls defineInspectorElements.

Backend: adds GET /threads/:id/events and GET /threads/:id/state to the
runtime (in-memory runner path). The Intelligence path returns 501 with
a clear "not yet supported on this runtime" empty state — coordination
with the Intelligence team is tracked separately (CPK-7453).

Also guards attachToCore's getThreadStores call so consumers on an older
@copilotkit/core don't throw when assigning inspector.core, and drops
two unrelated showcase-whitelist lines that landed in
scripts/hooks/check-binaries.sh during a prior merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:54:10 -07:00
Martha Schumann 32ba7a145a fix(inspector): revert access code back to earlyaccess
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 13:16:28 -07:00
Martha Schumann 9483d683d8 fix(inspector): update threads gate password and link to HubSpot form
- Change access code from "earlyaccess" to "easyaccess"
- Point "Request early access" button to HubSpot form
- Open HubSpot form in new window on successful code entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 13:16:01 -07:00
Martha Schumann 0c287c65f3 chore: merge origin/main
Excludes showcase/shell-docs and showcase/shell-dojo demo-content.json from
the size check in lefthook.yml — these data files were added by main but
weren't in the exemption list, causing the pre-commit hook to reject them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 15:17:06 -07:00
Martha Schumann a47abf2c7f fix(web-inspector): remove demo mode code and fix TS issues
Remove all demo/scripted animation code (demoMode, demoThreads,
demoConversation, startDemoAnimation, etc.) from the clean PR branch.
Also fix duplicate onAgentRunStarted handler, remove unused
announcementMarkdown field, and remove dead getSelectedMenu method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 14:56:42 -07:00
Martha Schumann cdffd8409b fix(react-core): remove redundant copilotkit.headers from useEffect deps
copilotkit.headers is already captured by headersKey (a stable memoized
string). Keeping the raw headers object in the dep array causes the context
effect to re-run on every render because mock (and real) copilotkit objects
return new header object references, leading to an unhandled
"threads is not iterable" error in tests when the spurious re-run consumed
the wrong fetchMock slot.

Also adds getThreadStore (singular) to MockCore in web-inspector.spec.ts so
ensureOwnedThreadStore can call core.getThreadStore() without throwing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 10:38:10 -07:00
Maxim 5058d195cc refactor: test hygiene for web-inspector spec
Extract shared helpers to reduce duplication and centralize unavoidable
casts. Add simulateSetState to mock controller to eliminate double-casts
in the new onStateChanged test. Promote mockClipboard to describe scope
to remove navigator clipboard cast in assertion. Add try/catch error
handling to syncAgentMessages and syncAgentState.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 00:43:49 +02:00
Maxim df199123da fix: inspector syncs state on direct agent.setState()
When using selfManagedAgents, calling agent.setState() directly only
fires onStateChanged — the inspector subscribed to onStateSnapshotEvent
(pipeline-only) but not onStateChanged, leaving the "Current State"
panel permanently stale. Add onStateChanged handler mirroring the
existing onMessagesChanged pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 00:08:53 +02:00
Martha Schumann 0ee11987e3 feat(web-inspector): add Threads tab with early-access gate and thread store integration
Wires the new Angular Custom Elements into the web inspector's Threads tab.
The tab is hidden behind an early-access gate (isEarlyAccessUser check);
_demoMode defaults to false. The inspector registers its own per-agentId
thread store unless one is already registered by useThreads(), preventing
accidental overwrites for apps that use both.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 15:43:28 -07:00
Martha Schumann 14ae28cfd1 feat(inspector): add thread store registry, runtime handlers, and useThreads hook
- CopilotKitCore gains a ThreadStoreRegistry (register/unregister by agentId)
  and a new onAgentRunStarted subscriber event so the inspector can subscribe
  before agent.runAgent() snapshots the subscriber list
- Runtime gains handleListThreads, handleUpdateThread, handleArchiveThread,
  handleDeleteThread, handleSubscribeToThreads, and handleGetThreadMessages
  handlers; all mutations are authenticated via identifyUser (request body
  userId is ignored)
- InMemoryAgentRunner now stores thread history for the local-dev fallback
  path; debug console.log removed; InMemoryThread uses literal types for
  constant-value fields (organizationId: "", createdById: "", archived: false)
- useThreads hook registers its store with CopilotKitCore on mount and
  unregisters on unmount so the inspector can read thread state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 15:43:27 -07:00
Nathan 🔶 Tarbert 8a651db6d9 fix: inspector not receiving AG-UI events from per-thread agent clones
useAgent() returns per-thread clones that are not in the agent registry.
The inspector only subscribed to registry agents via onAgentsChanged, so
it never received events from clones — resulting in an empty event panel.

Add onAgentRunStarted subscriber event that fires before connectAgent()
and runAgent(), passing the actual agent instance (which may be a clone).
The inspector subscribes to that agent, matching the existing StateManager
pattern (subscribeAgentToStateManager).
2026-04-13 17:58:10 -04:00
Alem Tuzlak ff2093102c chore(lint): add new oxlint rules and auto-fix violations
Enable stricter oxlint rules for better code health:
- typescript/consistent-type-imports: enforce `import type` for type-only imports
- typescript/no-import-type-side-effects: prefer top-level type imports
- import/consistent-type-specifier-style: consistent type specifier placement
- typescript/no-unnecessary-type-assertion: bump to error
- react/self-closing-comp: enforce self-closing JSX components
- unicorn/prefer-optional-catch-binding: drop unused catch params
- eslint/no-useless-computed-key: simplify object keys
- unicorn/prefer-string-slice: prefer .slice() over .substring()
- unicorn/prefer-array-flat-map: prefer .flatMap() over .map().flat()

All existing violations auto-fixed via oxlint --fix.
2026-04-10 19:29:32 +02:00
Markus Ecker a5c1137465 chore: update ag-ui deps and web-inspector styles 2026-04-08 12:51:07 -07:00