Skip to content
Open
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
68ddf72
Add provider skill listing to workspace
Quicksaver Jun 12, 2026
ace7991
Address CodeRabbit review comments
Quicksaver Jun 12, 2026
5bc3d6e
Fix disabled Codex skill listing
Quicksaver Jun 12, 2026
c34dff3
Fix Codex skill listing refresh and validation
Quicksaver Jun 12, 2026
1a1547f
Fix workspace skill refresh state
Quicksaver Jun 12, 2026
b38045b
Remove test skill file
Quicksaver Jun 12, 2026
6acc264
Fix workspace-scoped Codex skill loading
Quicksaver Jun 12, 2026
5b4e534
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 18, 2026
8f06032
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
00cebad
Bound workspace skill discovery requests
juliusmarminge Jun 19, 2026
5c37b87
Preserve workspace skills during refresh
Quicksaver Jun 19, 2026
05e81b6
Harden provider workspace skill cache
Quicksaver Jun 19, 2026
307486b
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
22f37d0
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
e5496d6
Cover provider skill discovery failures
juliusmarminge Jun 19, 2026
f980381
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
be22f74
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 21, 2026
a5fb01d
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 25, 2026
1654062
Stabilize provider skills error messages
Quicksaver Jun 21, 2026
f75f6cd
Port provider skills diagnostic details
Quicksaver Jun 21, 2026
bd73e93
Show workspace skill chips in chat messages
Quicksaver Jun 25, 2026
3199949
Load workspace skills lazily in composer
Quicksaver Jun 25, 2026
3464e42
Restore provider skills failure reason contract
Quicksaver Jun 25, 2026
3e2be11
Add provider skills error cause sanitizer
Quicksaver Jun 25, 2026
973cb5c
Fix provider skills namespace imports
Quicksaver Jun 25, 2026
89984e1
Fix provider skill typecheck fallout
Quicksaver Jun 25, 2026
661a9f3
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 25, 2026
ebe1625
Normalize provider skills error cwd
Quicksaver Jun 26, 2026
8d076f1
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 26, 2026
46a1603
Refactor route-layer dependency options in ws
Quicksaver Jun 26, 2026
8f2dd72
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 27, 2026
c748279
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 27, 2026
2dc022d
Merge upstream timeline scroll updates
Quicksaver Jun 30, 2026
2bd42cd
Fix timeline live-follow cancellation
Quicksaver Jun 30, 2026
f5930d6
Retry timeline scroll listener setup
Quicksaver Jun 30, 2026
71a2a69
Fix timeline scroll listener and anchor cleanup
Quicksaver Jun 30, 2026
67a43b9
Fix timeline listener retry exhaustion
Quicksaver Jun 30, 2026
1bc887b
Fix exhausted timeline anchor state
Quicksaver Jun 30, 2026
c8c8dee
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 1, 2026
8bd26b0
Align workspace paths import in provider skills lister
Quicksaver Jul 1, 2026
5a12942
Merge upstream and preserve Codex skill fixes
Quicksaver Jul 3, 2026
34def14
Remove codex skill branch pollution
Quicksaver Jul 3, 2026
4350f99
Merge upstream mobile tasks and Vite Plus updates
Quicksaver Jul 4, 2026
e84b0fb
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 5, 2026
5e9d607
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 10, 2026
0b571ea
Hide publish-only links from Connect discovery
Quicksaver Jul 10, 2026
33581b8
Harden relay activity delivery maintenance
Quicksaver Jul 10, 2026
0b5087f
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 13, 2026
bc17d95
Share workspace-aware provider skills with mobile
Quicksaver Jul 13, 2026
3c78e6c
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 15, 2026
57fc6cf
Surface workspace skill errors with fallbacks
Quicksaver Jul 15, 2026
ba9b5fb
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 16, 2026
fa0563c
Remove remaining codex skills branch pollution
Quicksaver Jul 16, 2026
0f8bc68
Add Codex skill loading branch details
Quicksaver Jul 17, 2026
6b04a4c
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 18, 2026
aa42013
Gate timeline skill loading on sent skill references
Quicksaver Jul 18, 2026
2183032
Recognize trailing skills in timeline loading
Quicksaver Jul 18, 2026
b1af7c3
Improve timeline skill reference detection
Quicksaver Jul 18, 2026
345368c
Unify sent skill token boundaries
Quicksaver Jul 18, 2026
78833da
Update mobile markdown lockfile dependencies
Quicksaver Jul 18, 2026
edda975
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 19, 2026
bbb0343
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 19, 2026
fe0480b
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 19, 2026
823202b
Enable pnpm global virtual store
Quicksaver Jul 19, 2026
b832625
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 20, 2026
58d8eca
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 20, 2026
5798b81
Stop fallback changes from refreshing skill probes
Quicksaver Jul 20, 2026
6d09f51
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 20, 2026
55b7c23
Fix Codex skill probe and refresh state
Quicksaver Jul 20, 2026
eb0650d
Document pending workspace skill isolation
Quicksaver Jul 20, 2026
a973e27
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 21, 2026
a9b4a6a
Avoid probing skills for future worktrees
Quicksaver Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions BRANCH_DETAILS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Codex Workspace Skill Loading

Fix Codex repo-local skill discovery in the composer by resolving skills for the active project/worktree cwd, instead of relying on the global provider status snapshot.

Expected behavior:

- Repo-local Codex skills for the active workspace appear in the `$` skill picker.
- The server exposes a workspace-aware `server.listProviderSkills` path and validates enabled Codex skill-listing requests against the requested cwd.
- The server routes skill listing through a bounded request lister that coalesces concurrent requests for the same provider/cwd, limits cross-workspace concurrency, and applies a short TTL so reconnects or repeated composer renders do not repeatedly spawn Codex app-server probes.
- The Codex provider requests `skills/list` with the current workspace cwd, times out hung app-server probes, and terminates the probe process when a timeout occurs.
- Provider skill-list failures preserve structured reason, operation, provider instance, normalized cwd, and bounded cause diagnostics for missing providers, invalid cwd, settings failures, Codex home preparation, probe timeouts, and probe failures while keeping stable user-facing messages. Raw thrown values are not sent directly to clients; the server keeps a small plain diagnostic shape so file paths, process output, and unexpected objects do not expand the wire payload.
- Non-Codex or disabled providers keep returning provider snapshot skills instead of failing workspace skill search.
- The client runtime keys provider-skill query state by environment, provider instance, and cwd, with a bounded stale window so reconnects refresh workspace-local skills without reusing another workspace's snapshot. Client-side fallback skill changes do not refresh the workspace query or respawn Codex skill probes.
- The composer loads workspace skills lazily: it starts workspace skill discovery when the `$` skill menu is active or the prompt already contains a complete `$skill` token, rather than probing on every empty composer mount. It preserves already loaded repo-local skills while refreshing the same workspace, falls back to provider snapshot skills when a settled workspace lookup returns no skills or errors, keeps structured lookup errors visible alongside those fallback skills on web and mobile, and clears stale repo-local skills during workspace switches or settled no-data states.
- The conversation timeline renders sent user prompts against the same workspace-aware skill list as the composer, so repo-local `$skill-name` references display with the same skill chip treatment as user-level skills. Timeline lookup stays disabled until a sent user prompt contains a complete skill token, including one at the end of the message, so an empty draft does not probe Codex merely to decorate nonexistent messages.
- The shared client-runtime policy also drives mobile thread composers and feeds. Mobile shows loading and structured error feedback, refreshes an already-open `$` menu when skills arrive, decorates complete skill references, and prevents stale successful results from surviving a failed refresh.
- New-task drafts request workspace skills lazily only after a complete `$skill` reference. Local drafts resolve the selected checkout or project root, while future-worktree drafts deliberately have no cwd and use provider snapshots until the target directory exists.

Primary files:

- `apps/server/src/ws.ts`
- `apps/server/src/provider/ProviderSkillsLister.ts`
- `apps/server/src/provider/Layers/CodexProvider.ts`
- `apps/web/src/components/ChatView.tsx`
- `apps/web/src/components/chat/ChatComposer.tsx`
- `apps/web/src/components/chat/MessagesTimeline.tsx`
- `apps/web/src/lib/providerWorkspaceSkillsState.ts`
- `apps/mobile/src/state/providerWorkspaceSkillsState.ts`
- `apps/mobile/src/features/threads/new-task-provider-skills.ts`
- `apps/mobile/src/features/threads/thread-composer-skill-items.ts`
- `packages/client-runtime/src/state/providerWorkspaceSkills.ts`
- `packages/contracts/src/server.ts`
- `packages/client-runtime/src/state/server.ts`

Relevant tests live in:

- `apps/server/src/server.test.ts`
- `apps/server/src/provider/ProviderSkillsLister.test.ts`
- `apps/server/src/provider/Layers/CodexProvider.test.ts`
- `apps/server/src/provider/Layers/CursorProvider.test.ts`
- `apps/server/src/provider/Layers/GrokProvider.test.ts`
- `apps/web/src/components/chat/MessagesTimeline.test.tsx`
- `apps/web/src/lib/providerWorkspaceSkillsState.test.ts`
- `apps/mobile/src/features/threads/new-task-provider-skills.test.ts`
- `apps/mobile/src/features/threads/thread-composer-skill-items.test.ts`
- `packages/client-runtime/src/state/providerWorkspaceSkills.test.ts`
- `packages/client-runtime/src/state/runtime.test.ts`

Useful focused commands:

```sh
(cd apps/server && pnpm exec vp test run --passWithNoTests src/provider/ProviderSkillsLister.test.ts src/provider/Layers/CodexProvider.test.ts src/provider/Layers/CursorProvider.test.ts src/provider/Layers/GrokProvider.test.ts)
(cd apps/web && pnpm exec vp test run --passWithNoTests --project unit src/lib/providerWorkspaceSkillsState.test.ts)
(cd apps/mobile && pnpm exec vp test run --passWithNoTests src/features/threads/new-task-provider-skills.test.ts src/features/threads/thread-composer-skill-items.test.ts)
(cd packages/client-runtime && pnpm exec vp test run --passWithNoTests src/state/providerWorkspaceSkills.test.ts)
```

## Development Ports

- Web: `5735`
- Server/WebSocket: `13775`
1 change: 1 addition & 0 deletions apps/mobile/modules/t3-markdown-text/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"./types": "./src/SelectableMarkdownText.types.ts"
},
"peerDependencies": {
"@t3tools/shared": "workspace:*",
"expo-asset": "*",
"expo-clipboard": "*",
"expo-haptics": "*",
Expand Down
10 changes: 4 additions & 6 deletions apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { MarkdownNode } from "react-native-nitro-markdown/headless";
import { parseInlineSkillTokens } from "@t3tools/shared/skillInlineTokens";

import type { SelectableMarkdownSkill } from "./SelectableMarkdownText.types";
import { resolveMarkdownLinkPresentation, type MarkdownFileIcon } from "./markdownLinks";
Expand Down Expand Up @@ -184,8 +185,6 @@ function appendRun(
return runs;
}

const SKILL_TOKEN_REGEX = /(^|\s)\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\s|$)/g;

function formatSkillLabel(skill: SelectableMarkdownSkill): string {
const displayName = skill.displayName?.trim();
if (displayName) {
Expand Down Expand Up @@ -216,14 +215,13 @@ function decorateSkillRuns(

let cursor = 0;
let matched = false;
for (const match of run.text.matchAll(SKILL_TOKEN_REGEX)) {
const prefix = match[1] ?? "";
const name = match[2] ?? "";
for (const match of parseInlineSkillTokens(run.text)) {
const { name } = match;
const skill = skillByName.get(name);
if (!skill) {
continue;
}
const start = (match.index ?? 0) + prefix.length;
const { start } = match;
const end = start + name.length + 1;
if (start > cursor) {
decorated.push({ ...run, text: run.text.slice(cursor, start) });
Expand Down
10 changes: 9 additions & 1 deletion apps/mobile/src/features/threads/ComposerCommandPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface ComposerCommandPopoverProps {
readonly items: ReadonlyArray<ComposerCommandItem>;
readonly triggerKind: ComposerTriggerKind | null;
readonly isLoading: boolean;
readonly error: string | null;
readonly onSelect: (item: ComposerCommandItem) => void;
}

Expand Down Expand Up @@ -181,6 +182,13 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(
</Text>
</View>
) : null}
{props.error ? (
<View className="px-3.5 py-2.5">
<Text className="text-xs text-danger-foreground" numberOfLines={3}>
{props.error}
</Text>
</View>
) : null}
{props.items.length > 0 ? (
<ScrollView
className="max-h-[180px]"
Expand All @@ -196,7 +204,7 @@ export const ComposerCommandPopover = memo(function ComposerCommandPopover(
/>
))}
</ScrollView>
) : (
) : props.error ? null : (
<View className="px-3.5 py-2.5">
<Text className="text-xs text-foreground-tertiary">
{emptyText(props.triggerKind, props.isLoading)}
Expand Down
104 changes: 15 additions & 89 deletions apps/mobile/src/features/threads/ThreadComposer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
ProviderInteractionMode,
RuntimeMode,
ServerConfig as T3ServerConfig,
ServerProviderSkill,
} from "@t3tools/contracts";
import {
detectComposerTrigger,
Expand Down Expand Up @@ -50,11 +51,6 @@ import type { DraftComposerImageAttachment } from "../../lib/composerImages";
import { buildModelOptions, groupByProvider } from "../../lib/modelOptions";
import { useScaledTextRole } from "../settings/appearance/useScaledTextRole";
import type { RemoteClientConnectionState } from "../../lib/connection";
import {
insertRankedSearchResult,
normalizeSearchQuery,
scoreQueryMatch,
} from "@t3tools/shared/searchRanking";
import {
applyProviderOptionMenuEvent,
buildProviderOptionMenuActions,
Expand All @@ -63,6 +59,7 @@ import {
} from "../../lib/providerOptions";
import { useComposerPathSearch } from "../../state/use-composer-path-search";
import { ComposerCommandPopover, type ComposerCommandItem } from "./ComposerCommandPopover";
import { buildComposerSkillItems } from "./thread-composer-skill-items";

/**
* Height of the collapsed composer (pill + vertical padding, excluding safe-area inset).
Expand Down Expand Up @@ -93,6 +90,9 @@ export interface ThreadComposerProps {
readonly threadSyncPhase?: "loading" | "syncing" | null;
readonly selectedThread: OrchestrationThreadShell;
readonly serverConfig: T3ServerConfig | null;
readonly workspaceSkills: ReadonlyArray<ServerProviderSkill>;
readonly workspaceSkillsIsPending: boolean;
readonly workspaceSkillsError: string | null;
readonly queueCount: number;
readonly activeThreadBusy: boolean;
readonly environmentId: EnvironmentId;
Expand Down Expand Up @@ -401,86 +401,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
}

if (composerTrigger.kind === "skill") {
const enabledSkills = (selectedProviderStatus?.skills ?? []).filter((s) => s.enabled);
const normalizedQuery = normalizeSearchQuery(composerTrigger.query, {
trimLeadingPattern: /^\$+/,
});

if (!normalizedQuery) {
return enabledSkills.slice(0, 20).map((skill) => ({
id: `skill:${skill.name}`,
type: "skill" as const,
skill,
label: skill.displayName ?? skill.name,
description: skill.shortDescription ?? skill.description ?? "",
}));
}

const ranked: Array<{
item: (typeof enabledSkills)[number];
score: number;
tieBreaker: string;
}> = [];
for (const skill of enabledSkills) {
const displayLabel = (skill.displayName ?? skill.name).toLowerCase();
const scores = [
scoreQueryMatch({
value: skill.name.toLowerCase(),
query: normalizedQuery,
exactBase: 0,
prefixBase: 2,
boundaryBase: 4,
includesBase: 6,
fuzzyBase: 100,
boundaryMarkers: ["-", "_", "/"],
}),
scoreQueryMatch({
value: displayLabel,
query: normalizedQuery,
exactBase: 1,
prefixBase: 3,
boundaryBase: 5,
includesBase: 7,
fuzzyBase: 110,
}),
scoreQueryMatch({
value: skill.shortDescription?.toLowerCase() ?? "",
query: normalizedQuery,
exactBase: 20,
prefixBase: 22,
boundaryBase: 24,
includesBase: 26,
}),
scoreQueryMatch({
value: skill.description?.toLowerCase() ?? "",
query: normalizedQuery,
exactBase: 30,
prefixBase: 32,
boundaryBase: 34,
includesBase: 36,
}),
].filter((s): s is number => s !== null);

if (scores.length > 0) {
insertRankedSearchResult(
ranked,
{
item: skill,
score: Math.min(...scores),
tieBreaker: `${displayLabel}\u0000${skill.name}`,
},
20,
);
}
}

return ranked.map(({ item: skill }) => ({
id: `skill:${skill.name}`,
type: "skill" as const,
skill,
label: skill.displayName ?? skill.name,
description: skill.shortDescription ?? skill.description ?? "",
}));
return buildComposerSkillItems(props.workspaceSkills, composerTrigger.query);
}

if (composerTrigger.kind === "path") {
Expand All @@ -498,7 +419,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
}

return [];
}, [composerTrigger, pathSearch.entries, selectedProviderStatus]);
}, [composerTrigger, pathSearch.entries, props.workspaceSkills, selectedProviderStatus]);

// ── Handle command selection ──────────────────────────────
const { onChangeDraftMessage, onUpdateInteractionMode, draftMessage, onSendMessage } = props;
Expand Down Expand Up @@ -710,12 +631,17 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
layout={COMPOSER_LAYOUT_TRANSITION}
style={{ maxWidth: props.contentMaxWidth }}
>
{composerTrigger && composerMenuItems.length > 0 ? (
{composerTrigger && (composerMenuItems.length > 0 || composerTrigger.kind === "skill") ? (
<View className="absolute inset-x-0 bottom-full z-10 mb-2">
<ComposerCommandPopover
items={composerMenuItems}
triggerKind={composerTrigger.kind}
isLoading={pathSearch.isPending}
isLoading={
composerTrigger.kind === "skill"
? props.workspaceSkillsIsPending
: pathSearch.isPending
}
error={composerTrigger.kind === "skill" ? props.workspaceSkillsError : null}
onSelect={handleCommandSelect}
/>
</View>
Expand Down Expand Up @@ -769,7 +695,7 @@ export const ThreadComposer = memo(function ThreadComposer(props: ThreadComposer
ref={inputRef}
multiline
value={props.draftMessage}
skills={selectedProviderStatus?.skills ?? []}
skills={props.workspaceSkills}
selection={composerSelection}
onChangeText={props.onChangeDraftMessage}
onSelectionChange={handleSelectionChange}
Expand Down
16 changes: 14 additions & 2 deletions apps/mobile/src/features/threads/ThreadDetailScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
ProviderInteractionMode,
RuntimeMode,
ServerConfig as T3ServerConfig,
ServerProviderSkill,
ThreadId,
} from "@t3tools/contracts";
import { formatElapsed } from "@t3tools/shared/orchestrationTiming";
Expand Down Expand Up @@ -44,6 +45,7 @@ import {
} from "./ThreadComposer";
import { ThreadFeed } from "./ThreadFeed";
import type { ThreadContentPresentation } from "./threadContentPresentation";
import { useProviderWorkspaceSkills } from "../../state/providerWorkspaceSkillsState";

export interface ThreadDetailScreenProps {
readonly selectedThread: OrchestrationThreadShell;
Expand Down Expand Up @@ -277,12 +279,19 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
const contentMaxWidth = isSplitLayout ? CHAT_CONTENT_MAX_WIDTH : undefined;
const selectedInstanceId = props.selectedThread.modelSelection.instanceId;
useStreamingHaptics(props.selectedThread.id, props.selectedThreadFeed);
const selectedProviderSkills = useMemo(
const selectedProviderFallbackSkills = useMemo<ReadonlyArray<ServerProviderSkill>>(
() =>
props.serverConfig?.providers.find((provider) => provider.instanceId === selectedInstanceId)
?.skills ?? [],
[props.serverConfig, selectedInstanceId],
);
const selectedProviderWorkspaceSkills = useProviderWorkspaceSkills({
environmentId: props.environmentId,
instanceId: selectedInstanceId,
cwd: props.threadCwd ?? props.projectWorkspaceRoot,
enabled: true,
fallbackSkills: selectedProviderFallbackSkills,
});

useLayoutEffect(() => {
selectedThreadKeyRef.current = selectedThreadKey;
Expand Down Expand Up @@ -421,7 +430,7 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
layoutVariant={layoutVariant}
usesAutomaticContentInsets={props.usesAutomaticContentInsets}
onHeaderMaterialVisibilityChange={props.onHeaderMaterialVisibilityChange}
skills={selectedProviderSkills}
skills={selectedProviderWorkspaceSkills.skills}
/>
</View>
) : (
Expand Down Expand Up @@ -487,6 +496,9 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
threadSyncPhase={threadSyncPhase}
selectedThread={props.selectedThread}
serverConfig={props.serverConfig}
workspaceSkills={selectedProviderWorkspaceSkills.skills}
workspaceSkillsIsPending={selectedProviderWorkspaceSkills.isPending}
workspaceSkillsError={selectedProviderWorkspaceSkills.error}
queueCount={props.selectedThreadQueueCount}
activeThreadBusy={props.activeThreadBusy}
environmentId={props.environmentId}
Expand Down
Loading
Loading