Add workspace and runtime analytics events#411
Conversation
📝 WalkthroughWalkthroughAdds a new backend AnalyticsService with polling, persisted dedupe/send-state and Amplitude integration; exposes Amplitude keys and analyticsStatePath in controller env; starts/stops an analytics background loop in container lifecycle; and instruments many frontend components/pages with tracking events and helpers. Changes
Sequence DiagramsequenceDiagram
participant SessionsRuntime as SessionsRuntime
participant FileSystem as File System
participant AnalyticsService as AnalyticsService
participant Amplitude as Amplitude API
loop Polling Loop (every runtimeSyncIntervalMs)
AnalyticsService->>SessionsRuntime: listSessions()
SessionsRuntime-->>AnalyticsService: sessions list
AnalyticsService->>FileSystem: read sessions.json, transcripts, skill ledger
FileSystem-->>AnalyticsService: transcripts & metadata
AnalyticsService->>AnalyticsService: parse entries, infer provider/skill candidates, dedupe
AnalyticsService->>Amplitude: POST analytics events (user_message_sent, skill_use, session_start)
Amplitude-->>AnalyticsService: response / errors
AnalyticsService->>FileSystem: persist send-state (analyticsStatePath)
FileSystem-->>AnalyticsService: state saved
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ace-and-runtime-events # Conflicts: # apps/web/src/pages/skills.tsx
Deploying nexu-docs with
|
| Latest commit: |
3f8b410
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d179bbda.nexu-docs.pages.dev |
| Branch Preview URL: | https://feat-analytics-workspace-and.nexu-docs.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/web/src/components/channel-setup/feishu-setup-view.tsx (1)
137-166:⚠️ Potential issue | 🟡 MinorThrown connect errors are not reported as failed submissions.
If
postApiV1ChannelsFeishuConnectthrows, thecatchpath does not emitworkspace_channel_config_submitwithsuccess: false.Suggested fix
- } catch { + } catch { + track("workspace_channel_config_submit", { + channel: "feishu", + success: false, + }); toast.error(t("feishuSetup.connectFailed")); } finally {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/channel-setup/feishu-setup-view.tsx` around lines 137 - 166, The catch block in handleConnect doesn't report a failed submission when postApiV1ChannelsFeishuConnect throws; update the catch to call track("workspace_channel_config_submit", { channel: "feishu", success: false }) before showing the toast (and optionally include any error message), so failures thrown by postApiV1ChannelsFeishuConnect are recorded the same way as error responses.apps/web/src/components/channel-setup/slack-oauth-view.tsx (1)
206-237:⚠️ Potential issue | 🟡 MinorManual-connect exception path is not tracked as failed submit.
When
postApiV1ChannelsSlackConnectthrows, Line 233 only shows a toast, soworkspace_channel_config_submitmisses failure telemetry.Suggested fix
- } catch { + } catch { + track("workspace_channel_config_submit", { + channel: "slack", + success: false, + }); toast.error(t("slackSetup.connectFailed")); } finally {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/channel-setup/slack-oauth-view.tsx` around lines 206 - 237, In handleManualConnect, the catch block for postApiV1ChannelsSlackConnect does not emit the failure telemetry, so add a track("workspace_channel_config_submit", { channel: "slack", success: false }) inside the catch before showing the toast (and optionally include error info if available); reference the existing track calls in the success and error branches to ensure symmetry with the success path and keep setConnecting(false) in the finally as-is.apps/web/src/components/channel-setup/discord-setup-view.tsx (1)
64-95:⚠️ Potential issue | 🟡 MinorException path is missing
success: falsetracking.If
postApiV1ChannelsDiscordConnectthrows, Line 91 only toasts and the submit-failure event is never emitted.Suggested fix
- } catch { + } catch { + track("workspace_channel_config_submit", { + channel: "discord", + success: false, + }); toast.error(t("discordSetup.connectFailed")); } finally {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/channel-setup/discord-setup-view.tsx` around lines 64 - 95, The catch block in handleConnect (which calls postApiV1ChannelsDiscordConnect) fails to emit the submit-failure analytics; add a track(...) call there mirroring the error path (e.g., track("workspace_channel_config_submit", { channel: "discord", success: false })) before showing the toast so failures from thrown exceptions are tracked; place it at the start of the catch block in discord-setup-view.tsx so existing toast.error and finally setConnecting(false) behavior remain unchanged.
🧹 Nitpick comments (2)
apps/controller/src/runtime/loops.ts (1)
111-118: Make the analytics loop stoppable without waiting for the next interval.
stopAnalyticsLoop()only flipsstopped; it does not cancel the pendingsleep(). Cleanup can therefore lag by up toruntimeSyncIntervalMs, and that timer can keep the process alive longer than expected.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/controller/src/runtime/loops.ts` around lines 111 - 118, The loop currently sets stopped = true in the returned cleanup but leaves a pending sleep(params.env.runtimeSyncIntervalMs) unresolved, so cleanup can wait the full interval; change the loop to use a cancellable wait (e.g., race sleep(...) with a stop promise or use an AbortController) inside run so the sleep resolves immediately when stopping. Concretely: inside the scope that defines run and stopped, create a stopResolve function or AbortController and use Promise.race([sleep(...), stopPromise]) (or an abortableSleep that listens to the controller) instead of awaiting sleep() directly; then call stopResolve() (or controller.abort()) in the returned cleanup closure so the pending wait is cancelled and run exits without waiting for the interval. Ensure references to run, stopped, and sleep are updated accordingly.apps/controller/src/services/analytics-service.ts (1)
160-175: Avoid reparsing full transcript history on every poll.Each pass re-reads every
.jsonltranscript plus the siblingsessions.jsonfor every session, so controller cost grows with total retained history instead of new activity. Persist a per-session file offset/mtime and cachesessions.jsonper directory to keep the loop bounded.Also applies to: 305-375
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/controller/src/services/analytics-service.ts` around lines 160 - 175, The loop in analytics-service (using sessionsRuntime.listSessions(), readTranscript(), readResolvedSkills(), and readSkillLedgerSources()) re-reads full transcript and sessions.json for every session on each poll; fix by persisting and checking per-session metadata (file offset and mtime) and caching directory-level sessions.json to avoid re-parsing unchanged files: update the session processing to load a small per-session state store (lastReadOffset, lastMtime, lastResolvedSkillsHash) and only call readTranscript/readResolvedSkills for files that changed since last poll, and add a cache keyed by session directory for the sessions.json content read by readSkillLedgerSources/readResolvedSkills so repeated lookups in the same dir reuse the parsed value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/controller/src/app/env.ts`:
- Line 136: The current amplitudeApiKey assignment uses nullish coalescing
(parsed.AMPLITUDE_API_KEY ?? parsed.VITE_AMPLITUDE_API_KEY) which treats an
empty string as set; change it so an empty/whitespace AMPLITUDE_API_KEY is
considered unset and falls back to VITE_AMPLITUDE_API_KEY. Locate the
amplitudeApiKey assignment and replace the nullish-coalescing logic with a check
that treats parsed.AMPLITUDE_API_KEY as unset when it's undefined, null, or only
whitespace (e.g., use a trimmed truthiness check or explicit empty-string test)
so parsed.VITE_AMPLITUDE_API_KEY is used as the fallback.
In `@apps/controller/src/services/analytics-service.ts`:
- Around line 143-144: The dedupe sets sentUserMessageIds and sentSkillUseIds
are global but analyzeSession() constructs fallback ids like
assistant:${tool}:${index} or uses bare entry.id that can collide across
sessions; update analyzeSession() to prefix all generated/stored event ids with
the session.id (e.g., use `${session.id}:${entry.id}` or
`${session.id}:assistant:${tool}:${index}`) before checking/inserting into
sentUserMessageIds and sentSkillUseIds so deduping is session-scoped; apply the
same session-prefixed id logic wherever those sets are accessed/updated
(including the code paths around lines noted: 165-181, 442-447, 493-496).
- Around line 13-17: The AnalyticsState type uses a single boolean
sessionStartSent which prevents emitting session_start more than once globally;
change AnalyticsState to track session-scoped sent flags (e.g. replace
sessionStartSent with sentSessionStartIds: Record<string, boolean> or
Set<string>) and update all code paths that check/set sessionStartSent (and any
logic that deduplicates by that flag near the handlers referenced) to use a
session identifier (session id or first user-message id) as the key when
deciding to emit session_start; also update any persisted state reads/writes and
the related arrays sentUserMessageIds and sentSkillUseIds to follow the same
session-scoped approach so each new session can send its own session_start
without being blocked by a global flag.
- Around line 377-405: readSkillLedgerSources currently only returns installed
skills from the live ledger which causes resolveSkillSource to fall back to
"builtin" for skills that existed in a session snapshot; update the logic so the
per-session snapshot is authoritative by checking the resolved snapshot first
(use readResolvedSkills() data/its returned map) when resolving a skill source
(in resolveSkillSource or wherever skill_source is determined), and only fall
back to the ledger produced by readSkillLedgerSources() or to "builtin" if
neither snapshot nor ledger contains the slug; ensure you reference the existing
functions readResolvedSkills(), readSkillLedgerSources(), and resolveSkillSource
when implementing this fallback ordering.
- Around line 551-567: The Amplitude POST fetch in analytics-service.ts
currently has no explicit deadline; wrap the call with
AbortSignal.timeout(30000) (or 60000 for 60s) and pass the resulting signal in
the fetch options (add signal) so the poll loop can't be blocked by a slow
Amplitude response; update the fetch invocation that constructs the body with
this.env.amplitudeApiKey to include the signal and handle the abort/timeout
error (e.g., catch the AbortError and treat it as a non-fatal timeout) so the
poll iteration can continue.
In `@apps/web/src/components/channel-connect-modal.tsx`:
- Around line 155-162: The cancel tracking fires while a submit is still in
flight; update handleClose to only call track("workspace_channel_config_cancel",
...) when not submittedSuccessfully AND not loading (e.g., if
(!submittedSuccessfully && !loading) { track(...) }), and add loading to the
useCallback dependency array so the callback uses the current in-flight state;
keep the existing onClose() call unchanged.
In `@apps/web/src/pages/auth.tsx`:
- Around line 209-218: The legacy dual-sent tracking calls are using the raw
authSourceParam instead of the normalized value; update the track calls that
currently pass authSourceParam (e.g., the first track call that sends
"login_email_success"/"signup_email_success" and the provider-based
"*_${provider}_success" calls) to pass normalizedSource ?? "Landing" (or similar
default) so both the legacy and new events use
normalizeAuthSource(authSourceParam); locate usages around the blocks
referencing normalizeAuthSource, normalizedSource, isLogin, and track (also
apply the same change in the other duplicated blocks noted) and replace the raw
authSourceParam with normalizedSource for consistency.
In `@apps/web/src/pages/home.tsx`:
- Around line 867-870: Create a shared connect handler (e.g.,
handleChannelConnect) that receives the channel id/object, calls
normalizeChannel and emits track("workspace_channel_connect_click", { channel })
when normalizeChannel returns a value, and then performs the existing setup/open
flow; replace the two inline usages (the secondary grid block that currently
calls normalizeChannel + track and the primary onboarding cards that open the
same setup flow) to both call handleChannelConnect so the primary first-run
cards are tracked through the same funnel.
In `@apps/web/src/pages/models.tsx`:
- Around line 85-95: getProviderIdFromModelId currently falls back to using the
first path segment (or whole modelId) as a provider, causing bogus provider
values; change the fallback so that if no matching entry is found in models you
only extract and return a provider when modelId contains an explicit separator
(e.g., contains "/"), otherwise return null. Update the function
getProviderIdFromModelId (parameters models and modelId) to check for a slash
before splitting and returning the provider_name, and ensure it returns null for
bare model IDs that aren't present in models.
---
Outside diff comments:
In `@apps/web/src/components/channel-setup/discord-setup-view.tsx`:
- Around line 64-95: The catch block in handleConnect (which calls
postApiV1ChannelsDiscordConnect) fails to emit the submit-failure analytics; add
a track(...) call there mirroring the error path (e.g.,
track("workspace_channel_config_submit", { channel: "discord", success: false
})) before showing the toast so failures from thrown exceptions are tracked;
place it at the start of the catch block in discord-setup-view.tsx so existing
toast.error and finally setConnecting(false) behavior remain unchanged.
In `@apps/web/src/components/channel-setup/feishu-setup-view.tsx`:
- Around line 137-166: The catch block in handleConnect doesn't report a failed
submission when postApiV1ChannelsFeishuConnect throws; update the catch to call
track("workspace_channel_config_submit", { channel: "feishu", success: false })
before showing the toast (and optionally include any error message), so failures
thrown by postApiV1ChannelsFeishuConnect are recorded the same way as error
responses.
In `@apps/web/src/components/channel-setup/slack-oauth-view.tsx`:
- Around line 206-237: In handleManualConnect, the catch block for
postApiV1ChannelsSlackConnect does not emit the failure telemetry, so add a
track("workspace_channel_config_submit", { channel: "slack", success: false })
inside the catch before showing the toast (and optionally include error info if
available); reference the existing track calls in the success and error branches
to ensure symmetry with the success path and keep setConnecting(false) in the
finally as-is.
---
Nitpick comments:
In `@apps/controller/src/runtime/loops.ts`:
- Around line 111-118: The loop currently sets stopped = true in the returned
cleanup but leaves a pending sleep(params.env.runtimeSyncIntervalMs) unresolved,
so cleanup can wait the full interval; change the loop to use a cancellable wait
(e.g., race sleep(...) with a stop promise or use an AbortController) inside run
so the sleep resolves immediately when stopping. Concretely: inside the scope
that defines run and stopped, create a stopResolve function or AbortController
and use Promise.race([sleep(...), stopPromise]) (or an abortableSleep that
listens to the controller) instead of awaiting sleep() directly; then call
stopResolve() (or controller.abort()) in the returned cleanup closure so the
pending wait is cancelled and run exits without waiting for the interval. Ensure
references to run, stopped, and sleep are updated accordingly.
In `@apps/controller/src/services/analytics-service.ts`:
- Around line 160-175: The loop in analytics-service (using
sessionsRuntime.listSessions(), readTranscript(), readResolvedSkills(), and
readSkillLedgerSources()) re-reads full transcript and sessions.json for every
session on each poll; fix by persisting and checking per-session metadata (file
offset and mtime) and caching directory-level sessions.json to avoid re-parsing
unchanged files: update the session processing to load a small per-session state
store (lastReadOffset, lastMtime, lastResolvedSkillsHash) and only call
readTranscript/readResolvedSkills for files that changed since last poll, and
add a cache keyed by session directory for the sessions.json content read by
readSkillLedgerSources/readResolvedSkills so repeated lookups in the same dir
reuse the parsed value.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 21eb1306-b931-4890-b54c-1cef483f1878
📒 Files selected for processing (20)
apps/controller/src/app/container.tsapps/controller/src/app/env.tsapps/controller/src/runtime/loops.tsapps/controller/src/services/analytics-service.tsapps/web/src/components/brand-rail.tsxapps/web/src/components/channel-connect-modal.tsxapps/web/src/components/channel-setup/discord-setup-view.tsxapps/web/src/components/channel-setup/feishu-setup-view.tsxapps/web/src/components/channel-setup/slack-oauth-view.tsxapps/web/src/components/inline-model-selector.tsxapps/web/src/components/model-picker-dropdown.tsxapps/web/src/layouts/workspace-layout.tsxapps/web/src/lib/tracking.tsapps/web/src/pages/auth.tsxapps/web/src/pages/channels.tsxapps/web/src/pages/home.tsxapps/web/src/pages/models.tsxapps/web/src/pages/sessions.tsxapps/web/src/pages/skills.tsxapps/web/src/pages/welcome.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/skills/import-skill-modal.tsx`:
- Around line 86-88: The analytics call inside import-skill-modal.tsx is sending
a raw local filename via selectedFile.name as a fallback; update the
track("workspace_skill_enable", ...) invocation to avoid any client filenames by
removing the selectedFile.name fallback and instead send only the
server-provided result.slug (or a fixed safe constant like "unknown_skill" or
"local_skill" when result.slug is falsy). Locate the track call and replace the
name payload to use result.slug ?? "unknown_skill" (or just result.slug) so no
local filenames are included in analytics.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f1b4b030-2a9e-46aa-9626-32d238a076b8
📒 Files selected for processing (2)
apps/web/src/components/skills/import-skill-modal.tsxapps/web/src/pages/skills.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/src/pages/skills.tsx
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/src/components/channel-setup/feishu-setup-view.tsx (1)
151-166:⚠️ Potential issue | 🟠 MajorDon't let post-success UI errors emit a failed submit event.
onConnected()still runs inside the sametry. If it throws after the success track at Line 151, the catch at Line 163 emitsworkspace_channel_config_submitagain withsuccess: falseand shows a failure toast after the success toast. Keep the analytics try/catch scoped topostApiV1ChannelsFeishuConnect, or move the post-success UI work outside it.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/channel-setup/feishu-setup-view.tsx` around lines 151 - 166, The try/catch currently wraps both the API call and the post-success UI/analytics, so if onConnected() or UI code throws after a successful API call it incorrectly records a failed submit; refactor by limiting the try/catch to the API call (postApiV1ChannelsFeishuConnect) and any analytics tracking (track calls), then run toast.success, identify, and onConnected() outside that try block (or add a separate try around analytics only) so that a post-success UI error cannot trigger the failure branch that emits workspace_channel_config_submit with success: false.
♻️ Duplicate comments (1)
apps/controller/src/services/analytics-service.ts (1)
13-17:⚠️ Potential issue | 🟠 MajorTrack
session_startper session, not globally.This is still a single boolean, so after the first successful
session_start, every later transcript is skipped. Persist a session-scoped sent set keyed bysession.id(or the first user-message id) instead.Also applies to: 163-164, 184-193, 240-251
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/controller/src/services/analytics-service.ts` around lines 13 - 17, AnalyticsState currently uses a single boolean sessionStartSent which causes a single global session_start to block all later sessions; change AnalyticsState to track session-scoped state (e.g., sessionStartSentBySession: Record<string, boolean> and sentUserMessageIdsBySession: Record<string, string[]> and sentSkillUseIdsBySession: Record<string, string[]>), key entries by session.id (or first user-message id) and update the logic that checks/sets sessionStartSent, sentUserMessageIds, and sentSkillUseIds to read/write the per-session maps (ensure removal/cleanup when sessions end or expire); update any functions referencing sessionStartSent, sentUserMessageIds, or sentSkillUseIds to use the session-keyed maps instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/controller/src/app/env.ts`:
- Around line 136-137: The amplitudeApiKey assignment currently only trims
parsed.AMPLITUDE_API_KEY but leaves parsed.VITE_AMPLITUDE_API_KEY untrimmed;
update the amplitudeApiKey expression in env.ts (the amplitudeApiKey
export/field) to apply .trim() and emptiness handling to both sources (e.g., use
parsed.AMPLITUDE_API_KEY?.trim() || parsed.VITE_AMPLITUDE_API_KEY?.trim()) so a
whitespace-only VITE_AMPLITUDE_API_KEY doesn't produce a truthy invalid key.
In `@apps/controller/src/services/analytics-service.ts`:
- Around line 203-213: The poll() flow is adding dedupe state (calls like
this.sentUserMessageIds.add(...), this.sentSkillUseIds.add(...), and setting
this.state.sessionStartSent = true) immediately after calling sendEvent(), but
sendEvent() can fail and returns/logs on errors; only mark events as sent when
sendEvent actually succeeded. Update sendEvent callers in analytics-service (the
spots around the user_message_sent, skill_use, and session_start flows) to check
the boolean/result returned by sendEvent() and only execute
this.sentUserMessageIds.add(...), this.sentSkillUseIds.add(...), or set
this.state.sessionStartSent = true when sendEvent() indicates success; keep the
rest of the logic unchanged so transient Amplitude failures do not permanently
drop events.
- Around line 324-375: readResolvedSkills currently iterates
Object.values(parsed) and merges resolvedSkills from all sessions; change its
signature (readResolvedSkills) to accept the current sessionId and only read the
snapshot for that key from the parsed sessions JSON (use parsed[sessionId]
instead of Object.values(parsed)), then validate that entry's skillsSnapshot and
resolvedSkills (resolvedSkills, name, filePath, source) exactly as before;
update callers to pass the session.id; reference sessionsJsonPath, parsed,
snapshot, and resolvedSkills when making this selective lookup and preserving
existing type/validation checks.
In `@apps/web/src/components/channel-connect-modal.tsx`:
- Around line 215-229: The catch/rejection path of the Channel connect flow
isn't reporting failures to analytics — update the error-handling so that
whenever a postApiV1Channels*Connect call rejects you call
track("workspace_channel_config_submit", { channel: channelType, success: false
}) before showing the toast (i.e., add the same track call used in the 409/error
branch into the catch/rejection branch where the toast is currently shown),
ensuring the channelType value used matches the existing variable and keep the
existing toast behavior.
In `@apps/web/src/components/skills/import-skill-modal.tsx`:
- Around line 85-89: After successfully calling
importMutation.mutateAsync(selectedFile) (the const result = await
importMutation.mutateAsync(selectedFile) block), guard the analytics call
track(...) so it cannot throw and block the success UX: wrap the
track("workspace_skill_enable", { name: result.slug ?? "unknown_skill",
skill_source: "custom" }) call in its own try/catch (or Promise.catch if async)
and swallow/log analytics errors, ensuring the subsequent success handling
(closing the modal/updating state) always runs regardless of track failures.
---
Outside diff comments:
In `@apps/web/src/components/channel-setup/feishu-setup-view.tsx`:
- Around line 151-166: The try/catch currently wraps both the API call and the
post-success UI/analytics, so if onConnected() or UI code throws after a
successful API call it incorrectly records a failed submit; refactor by limiting
the try/catch to the API call (postApiV1ChannelsFeishuConnect) and any analytics
tracking (track calls), then run toast.success, identify, and onConnected()
outside that try block (or add a separate try around analytics only) so that a
post-success UI error cannot trigger the failure branch that emits
workspace_channel_config_submit with success: false.
---
Duplicate comments:
In `@apps/controller/src/services/analytics-service.ts`:
- Around line 13-17: AnalyticsState currently uses a single boolean
sessionStartSent which causes a single global session_start to block all later
sessions; change AnalyticsState to track session-scoped state (e.g.,
sessionStartSentBySession: Record<string, boolean> and
sentUserMessageIdsBySession: Record<string, string[]> and
sentSkillUseIdsBySession: Record<string, string[]>), key entries by session.id
(or first user-message id) and update the logic that checks/sets
sessionStartSent, sentUserMessageIds, and sentSkillUseIds to read/write the
per-session maps (ensure removal/cleanup when sessions end or expire); update
any functions referencing sessionStartSent, sentUserMessageIds, or
sentSkillUseIds to use the session-keyed maps instead.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ea140632-ffc0-425c-b486-358c0a1a2742
📒 Files selected for processing (10)
apps/controller/src/app/env.tsapps/controller/src/services/analytics-service.tsapps/web/src/components/channel-connect-modal.tsxapps/web/src/components/channel-setup/discord-setup-view.tsxapps/web/src/components/channel-setup/feishu-setup-view.tsxapps/web/src/components/channel-setup/slack-oauth-view.tsxapps/web/src/components/skills/import-skill-modal.tsxapps/web/src/pages/auth.tsxapps/web/src/pages/home.tsxapps/web/src/pages/models.tsx
✅ Files skipped from review due to trivial changes (2)
- apps/web/src/components/channel-setup/discord-setup-view.tsx
- apps/web/src/pages/home.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/src/components/channel-setup/slack-oauth-view.tsx
- apps/web/src/pages/models.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/.vitepress/theme/ThemeToggle.vue`:
- Around line 7-9: The injected toggle handler is named _toggleAppearance but
the template calls toggleAppearance, causing an undefined click handler; fix by
making the names consistent—either rename the injected constant
_toggleAppearance to toggleAppearance (update the inject call that currently
uses _toggleAppearance) or change the template to call _toggleAppearance—ensure
the inject("toggle-appearance", ...) result and the template click handler
reference the same identifier.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 702878ca-d3bf-4407-ba4d-85456cdc4155
📒 Files selected for processing (6)
docs/.vitepress/config.tsdocs/.vitepress/theme/GitHubStars.vuedocs/.vitepress/theme/LanguageSwitcher.vuedocs/.vitepress/theme/ThemeToggle.vuedocs/.vitepress/theme/custom.cssdocs/.vitepress/theme/index.ts
✅ Files skipped from review due to trivial changes (5)
- docs/.vitepress/theme/index.ts
- docs/.vitepress/config.ts
- docs/.vitepress/theme/GitHubStars.vue
- docs/.vitepress/theme/custom.css
- docs/.vitepress/theme/LanguageSwitcher.vue
5de0a9a to
8bb4e70
Compare
…ace-and-runtime-events
Summary
Validation
Notes
Summary by CodeRabbit
New Features
Chores