@agent-relay/dashboard 2.0.82 → 2.0.84
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/out/404.html +1 -1
- package/out/_next/static/chunks/1028-da5d75e35d1420f1.js +1 -0
- package/out/_next/static/chunks/1528-78b17000a7e10bc6.js +2 -0
- package/out/_next/static/chunks/1695-4a5d33ba715e09b4.js +1 -0
- package/out/_next/static/chunks/1705-36c2180d00a4a569.js +1 -0
- package/out/_next/static/chunks/1dd3208c-e1f87c7b3dc1a820.js +1 -0
- package/out/_next/static/chunks/3663-47290254b8f6f5dd.js +1 -0
- package/out/_next/static/chunks/3677-4b225baf4801d9b9.js +73 -0
- package/out/_next/static/chunks/5118-7e8ada2df38eef07.js +1 -0
- package/out/_next/static/chunks/5888-15cbe97c90ed5fae.js +1 -0
- package/out/_next/static/chunks/6773-a45343a98df3abb5.js +1 -0
- package/out/_next/static/chunks/6940-b824612b605e79b3.js +9 -0
- package/out/_next/static/chunks/7894-f4a15249082a680d.js +1 -0
- package/out/_next/static/chunks/9175-b3617c1e5cbfed0e.js +1 -0
- package/out/_next/static/chunks/9372-1a804b8d08c7a236.js +1 -0
- package/out/_next/static/chunks/{ab6c8a12-0a58072fbb505134.js → ab6c8a12-91438a812d94ecf0.js} +1 -1
- package/out/_next/static/chunks/app/_not-found/page-8e8842f82d204726.js +1 -0
- package/out/_next/static/chunks/app/about/page-b78577a7da8fa459.js +1 -0
- package/out/_next/static/chunks/app/app/[[...slug]]/page-3dffd65b6344f53e.js +1 -0
- package/out/_next/static/chunks/app/app/onboarding/page-b89be9aa6264a5e1.js +1 -0
- package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-fbd00893ef69e499.js +1 -0
- package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-de2ea13649d0b6d3.js +1 -0
- package/out/_next/static/chunks/app/blog/page-a08e263c57a156fa.js +1 -0
- package/out/_next/static/chunks/app/careers/page-02228e1d6969b232.js +1 -0
- package/out/_next/static/chunks/app/changelog/page-1b5c1d79efc6e53a.js +1 -0
- package/out/_next/static/chunks/app/cloud/link/page-99654edffffb3af2.js +1 -0
- package/out/_next/static/chunks/app/complete-profile/page-59d146e5ddeafc5c.js +1 -0
- package/out/_next/static/chunks/app/connect-repos/page-995e16a976a6632c.js +1 -0
- package/out/_next/static/chunks/app/contact/page-273396a5ad57bcee.js +1 -0
- package/out/_next/static/chunks/app/dev/cli-tools/page-a71b80dcb2d5fc8d.js +1 -0
- package/out/_next/static/chunks/app/dev/log-viewer/page-46a6151ae1be0796.js +1 -0
- package/out/_next/static/chunks/app/docs/page-7c7cb603b24b7c40.js +1 -0
- package/out/_next/static/chunks/app/history/page-0c5cab1dab4e8886.js +1 -0
- package/out/_next/static/chunks/app/layout-96d72ba8ef8a43a0.js +1 -0
- package/out/_next/static/chunks/app/login/page-0ccbab34213df842.js +1 -0
- package/out/_next/static/chunks/app/metrics/page-8616272aeab9c8b0.js +1 -0
- package/out/_next/static/chunks/app/page-09ce10603ad9a251.js +1 -0
- package/out/_next/static/chunks/app/pricing/page-91c975079120c941.js +1 -0
- package/out/_next/static/chunks/app/privacy/{page-c21d51ac2dee3a88.js → page-a49ab271cc686644.js} +1 -1
- package/out/_next/static/chunks/app/providers/{page-59114505f4353512.js → page-d775d6eb5bc29e96.js} +1 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-ec4ef3cd80de807e.js +1 -0
- package/out/_next/static/chunks/app/security/page-d9da9bd9191e8f95.js +1 -0
- package/out/_next/static/chunks/app/signup/page-930eca0bf5fd299d.js +1 -0
- package/out/_next/static/chunks/app/terms/page-3e4827620b98613c.js +1 -0
- package/out/_next/static/chunks/framework-648e1ae7da590300.js +1 -0
- package/out/_next/static/chunks/{main-acb1b24265295d6a.js → main-2b1990080c292d92.js} +1 -1
- package/out/_next/static/chunks/main-app-9f6b7ff9e754a8f5.js +1 -0
- package/out/_next/static/chunks/pages/_app-a077b72e02273ab1.js +1 -0
- package/out/_next/static/chunks/pages/_error-84001666436a04e4.js +1 -0
- package/out/_next/static/chunks/{webpack-dd93b81e2659669c.js → webpack-7586035f1585f2db.js} +1 -1
- package/out/_next/static/css/eb9fc69d1e3d2bed.css +1 -0
- package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_buildManifest.js +1 -1
- package/out/about.html +2 -2
- package/out/about.txt +2 -2
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +2 -2
- package/out/app.html +1 -1
- package/out/app.txt +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +3 -3
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
- package/out/blog.html +2 -2
- package/out/blog.txt +1 -1
- package/out/careers.html +2 -2
- package/out/careers.txt +2 -2
- package/out/changelog.html +2 -2
- package/out/changelog.txt +2 -2
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +2 -2
- package/out/complete-profile.html +2 -2
- package/out/complete-profile.txt +2 -2
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +2 -2
- package/out/contact.html +2 -2
- package/out/contact.txt +2 -2
- package/out/dev/cli-tools.html +1 -0
- package/out/dev/cli-tools.txt +7 -0
- package/out/dev/log-viewer.html +23 -0
- package/out/dev/log-viewer.txt +7 -0
- package/out/docs.html +2 -2
- package/out/docs.txt +2 -2
- package/out/history.html +1 -1
- package/out/history.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +2 -2
- package/out/login.html +2 -2
- package/out/login.txt +2 -2
- package/out/metrics.html +1 -1
- package/out/metrics.txt +2 -2
- package/out/pricing.html +2 -2
- package/out/pricing.txt +2 -2
- package/out/privacy.html +2 -2
- package/out/privacy.txt +2 -2
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +2 -2
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +2 -2
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +2 -2
- package/out/providers.html +1 -1
- package/out/providers.txt +2 -2
- package/out/security.html +2 -2
- package/out/security.txt +2 -2
- package/out/signup.html +2 -2
- package/out/signup.txt +2 -2
- package/out/terms.html +2 -2
- package/out/terms.txt +2 -2
- package/package.json +5 -1
- package/src/adapters/DashboardConfigProvider.tsx +56 -0
- package/src/adapters/cloudFetchAdapter.ts +278 -0
- package/src/adapters/index.ts +3 -0
- package/src/adapters/types.ts +508 -0
- package/src/app/app/[[...slug]]/DashboardPageClient.tsx +67 -18
- package/src/app/app/onboarding/page.tsx +870 -170
- package/src/app/cloud/link/page.tsx +14 -6
- package/src/app/connect-repos/page.tsx +9 -3
- package/src/app/dev/cli-tools/page.tsx +130 -0
- package/src/app/dev/log-viewer/MockLogViewer.tsx +132 -0
- package/src/app/dev/log-viewer/fixtures.ts +110 -0
- package/src/app/dev/log-viewer/page.tsx +288 -0
- package/src/app/history/page.tsx +28 -12
- package/src/app/page.tsx +1 -1
- package/src/app/providers/setup/[provider]/ProviderSetupClient.tsx +209 -59
- package/src/components/AgentCard.tsx +4 -4
- package/src/components/AgentLogPreview.tsx +2 -38
- package/src/components/App.tsx +441 -2624
- package/src/components/CliToolHarness.test.tsx +83 -0
- package/src/components/CliToolHarness.tsx +292 -0
- package/src/components/CoordinatorPanel.tsx +13 -6
- package/src/components/LogViewer.tsx +2 -42
- package/src/components/ProviderAuthFlow.tsx +201 -81
- package/src/components/ProvisioningProgress.tsx +1 -1
- package/src/components/ReactionChips.tsx +2 -1
- package/src/components/SpawnModal.test.tsx +51 -18
- package/src/components/SpawnModal.tsx +175 -207
- package/src/components/TerminalProviderSetup.tsx +1 -1
- package/src/components/ThreadPanel.tsx +2 -0
- package/src/components/WorkspaceContext.tsx +7 -19
- package/src/components/XTermLogViewer.tsx +190 -27
- package/src/components/channels/ChannelMessageList.tsx +94 -4
- package/src/components/channels/ChannelViewV1.tsx +35 -11
- package/src/components/channels/api.ts +21 -20
- package/src/components/channels/types.ts +16 -0
- package/src/components/hooks/index.ts +0 -19
- package/src/components/hooks/useMessages.test.ts +80 -0
- package/src/components/hooks/useMessages.ts +13 -4
- package/src/components/hooks/useOrchestrator.ts +1 -1
- package/src/components/hooks/usePresence.ts +45 -6
- package/src/components/hooks/useThread.ts +83 -46
- package/src/components/hooks/useTrajectory.ts +62 -5
- package/src/components/hooks/useWebSocket.test.ts +358 -0
- package/src/components/hooks/useWebSocket.ts +243 -5
- package/src/components/index.ts +2 -14
- package/src/components/layout/Header.tsx +9 -15
- package/src/components/layout/Sidebar.tsx +1 -8
- package/src/components/settings/SettingsPage.tsx +108 -47
- package/src/components/settings/index.ts +0 -3
- package/src/landing/blogData.ts +1 -1
- package/src/lib/agent-merge.test.ts +2 -2
- package/src/lib/api.ts +8 -38
- package/src/lib/identity.test.ts +139 -0
- package/src/lib/identity.ts +48 -0
- package/src/lib/relaycastMessageAdapters.test.ts +182 -0
- package/src/lib/relaycastMessageAdapters.ts +105 -0
- package/src/lib/sanitize-logs.test.ts +227 -0
- package/src/lib/sanitize-logs.ts +202 -0
- package/src/providers/AgentProvider.tsx +799 -0
- package/src/providers/ChannelProvider.tsx +528 -0
- package/src/providers/CloudWorkspaceProvider.tsx +402 -0
- package/src/providers/MessageProvider.tsx +875 -0
- package/src/providers/RelayConfigProvider.tsx +94 -0
- package/src/providers/SendProvider.tsx +497 -0
- package/src/providers/SettingsProvider.tsx +247 -0
- package/src/providers/index.ts +26 -0
- package/src/types/index.ts +10 -10
- package/out/_next/static/chunks/11-9a2993a37266dcb3.js +0 -9
- package/out/_next/static/chunks/118-ae2b650136a5a5fc.js +0 -1
- package/out/_next/static/chunks/1dd3208c-40ab0fc0f60392b8.js +0 -1
- package/out/_next/static/chunks/202-fc0763dd7488e58f.js +0 -1
- package/out/_next/static/chunks/259-83b77fa1b91ba5aa.js +0 -1
- package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +0 -1
- package/out/_next/static/chunks/528-f5f676996d613c25.js +0 -2
- package/out/_next/static/chunks/663-ddb04081febc3678.js +0 -1
- package/out/_next/static/chunks/687-88b6b139a6bb0e2e.js +0 -1
- package/out/_next/static/chunks/695-51d25b1988644374.js +0 -1
- package/out/_next/static/chunks/773-54a2641043c81e55.js +0 -1
- package/out/_next/static/chunks/app/_not-found/page-6da9b72091e5b511.js +0 -1
- package/out/_next/static/chunks/app/about/page-fff7c6457683f243.js +0 -1
- package/out/_next/static/chunks/app/app/[[...slug]]/page-f7eca1b66fb4249b.js +0 -1
- package/out/_next/static/chunks/app/app/onboarding/page-129abc5da2e67971.js +0 -1
- package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-5d5f28fd126b692f.js +0 -1
- package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-b194f207fbd91862.js +0 -1
- package/out/_next/static/chunks/app/blog/page-b9bd9d8703fca76a.js +0 -1
- package/out/_next/static/chunks/app/careers/page-a4bd8d5f4de8f4eb.js +0 -1
- package/out/_next/static/chunks/app/changelog/page-9a1f6ad1743d63c5.js +0 -1
- package/out/_next/static/chunks/app/cloud/link/page-0844c5699b027c3b.js +0 -1
- package/out/_next/static/chunks/app/complete-profile/page-39ed5a67916beb87.js +0 -1
- package/out/_next/static/chunks/app/connect-repos/page-297eddee0c39f2a3.js +0 -1
- package/out/_next/static/chunks/app/contact/page-3c1dd8690217fade.js +0 -1
- package/out/_next/static/chunks/app/docs/page-1875e981f2c3fd13.js +0 -1
- package/out/_next/static/chunks/app/history/page-2d5c5695c9e8b40c.js +0 -1
- package/out/_next/static/chunks/app/layout-0a4b99656da25511.js +0 -1
- package/out/_next/static/chunks/app/login/page-f69c076f5a6fc520.js +0 -1
- package/out/_next/static/chunks/app/metrics/page-bebbee055669a17e.js +0 -1
- package/out/_next/static/chunks/app/page-0ee604f7070d14c0.js +0 -1
- package/out/_next/static/chunks/app/pricing/page-eeae7d594af333b6.js +0 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-daf9b3e05e77ae19.js +0 -1
- package/out/_next/static/chunks/app/security/page-cd562730fe84a0a2.js +0 -1
- package/out/_next/static/chunks/app/signup/page-c242ca08101a84ff.js +0 -1
- package/out/_next/static/chunks/app/terms/page-c7001720e7941dc6.js +0 -1
- package/out/_next/static/chunks/framework-3664cab31236a9fa.js +0 -1
- package/out/_next/static/chunks/main-app-7f73a939a312a228.js +0 -1
- package/out/_next/static/chunks/pages/_app-10a93ab5b7c32eb3.js +0 -1
- package/out/_next/static/chunks/pages/_error-2d792b2a41857be4.js +0 -1
- package/out/_next/static/css/8968d98ed4c4d33f.css +0 -1
- package/src/components/BillingResult.tsx +0 -447
- package/src/components/CloudSessionProvider.tsx +0 -130
- package/src/components/SessionExpiredModal.tsx +0 -128
- package/src/components/WorkspaceStatusIndicator.tsx +0 -396
- package/src/components/hooks/useSession.ts +0 -209
- package/src/components/hooks/useWorkspaceMembers.ts +0 -132
- package/src/components/hooks/useWorkspaceStatus.ts +0 -237
- package/src/components/settings/BillingSettingsPanel.tsx +0 -564
- package/src/components/settings/TeamSettingsPanel.tsx +0 -560
- package/src/components/settings/WorkspaceSettingsPanel.tsx +0 -1368
- package/src/lib/cloudApi.ts +0 -893
- /package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_ssgManifest.js +0 -0
|
@@ -6,8 +6,57 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
9
|
+
import { useDashboardConfig } from '../adapters';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Model options inlined from @agent-relay/config (cli-registry.yaml).
|
|
13
|
+
* Inlined to avoid importing Node.js dependencies into the browser bundle.
|
|
14
|
+
*/
|
|
15
|
+
const RegistryModelOptions = {
|
|
16
|
+
Claude: [
|
|
17
|
+
{ value: 'sonnet', label: 'Sonnet' },
|
|
18
|
+
{ value: 'opus', label: 'Opus' },
|
|
19
|
+
{ value: 'haiku', label: 'Haiku' },
|
|
20
|
+
],
|
|
21
|
+
Codex: [
|
|
22
|
+
{ value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex — Frontier agentic coding model' },
|
|
23
|
+
{ value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex — Latest frontier agentic coding model' },
|
|
24
|
+
{ value: 'gpt-5.3-codex-spark', label: 'GPT-5.3 Codex Spark — Ultra-fast coding model' },
|
|
25
|
+
{ value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max — Deep and fast reasoning' },
|
|
26
|
+
{ value: 'gpt-5.2', label: 'GPT-5.2 — Frontier model, knowledge & reasoning' },
|
|
27
|
+
{ value: 'gpt-5.1-codex-mini', label: 'GPT-5.1 Codex Mini — Cheaper, faster' },
|
|
28
|
+
],
|
|
29
|
+
Gemini: [
|
|
30
|
+
{ value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro Preview' },
|
|
31
|
+
{ value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro' },
|
|
32
|
+
{ value: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash' },
|
|
33
|
+
{ value: 'gemini-2.5-flash-lite', label: 'Gemini 2.5 Flash Lite' },
|
|
34
|
+
],
|
|
35
|
+
Cursor: [
|
|
36
|
+
{ value: 'opus-4.5-thinking', label: 'Claude 4.5 Opus (Thinking)' },
|
|
37
|
+
{ value: 'opus-4.5', label: 'Claude 4.5 Opus' },
|
|
38
|
+
{ value: 'sonnet-4.5', label: 'Claude 4.5 Sonnet' },
|
|
39
|
+
{ value: 'sonnet-4.5-thinking', label: 'Claude 4.5 Sonnet (Thinking)' },
|
|
40
|
+
{ value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex' },
|
|
41
|
+
{ value: 'gpt-5.2-codex-high', label: 'GPT-5.2 Codex High' },
|
|
42
|
+
{ value: 'gpt-5.2-codex-low', label: 'GPT-5.2 Codex Low' },
|
|
43
|
+
{ value: 'gpt-5.2-codex-xhigh', label: 'GPT-5.2 Codex Extra High' },
|
|
44
|
+
{ value: 'gpt-5.2-codex-fast', label: 'GPT-5.2 Codex Fast' },
|
|
45
|
+
{ value: 'gpt-5.2-codex-high-fast', label: 'GPT-5.2 Codex High Fast' },
|
|
46
|
+
{ value: 'gpt-5.2-codex-low-fast', label: 'GPT-5.2 Codex Low Fast' },
|
|
47
|
+
{ value: 'gpt-5.2-codex-xhigh-fast', label: 'GPT-5.2 Codex Extra High Fast' },
|
|
48
|
+
{ value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max' },
|
|
49
|
+
{ value: 'gpt-5.1-codex-max-high', label: 'GPT-5.1 Codex Max High' },
|
|
50
|
+
{ value: 'gpt-5.2', label: 'GPT-5.2' },
|
|
51
|
+
{ value: 'gpt-5.2-high', label: 'GPT-5.2 High' },
|
|
52
|
+
{ value: 'gpt-5.1-high', label: 'GPT-5.1 High' },
|
|
53
|
+
{ value: 'gemini-3-pro', label: 'Gemini 3 Pro' },
|
|
54
|
+
{ value: 'gemini-3-flash', label: 'Gemini 3 Flash' },
|
|
55
|
+
{ value: 'composer-1', label: 'Composer 1' },
|
|
56
|
+
{ value: 'grok', label: 'Grok' },
|
|
57
|
+
],
|
|
58
|
+
};
|
|
9
59
|
import { getAgentColor, getAgentInitials } from '../lib/colors';
|
|
10
|
-
import { cloudApi } from '../lib/cloudApi';
|
|
11
60
|
|
|
12
61
|
export type SpeakOnTrigger = 'SESSION_END' | 'CODE_WRITTEN' | 'REVIEW_REQUEST' | 'EXPLICIT_ASK' | 'ALL_MESSAGES';
|
|
13
62
|
|
|
@@ -21,6 +70,7 @@ export interface SpawnConfig {
|
|
|
21
70
|
shadowAgent?: string;
|
|
22
71
|
shadowTriggers?: SpeakOnTrigger[];
|
|
23
72
|
shadowSpeakOn?: SpeakOnTrigger[];
|
|
73
|
+
continueFrom?: string;
|
|
24
74
|
}
|
|
25
75
|
|
|
26
76
|
function deriveShadowMode(command: string): 'subagent' | 'process' {
|
|
@@ -36,8 +86,6 @@ export interface SpawnModalProps {
|
|
|
36
86
|
existingAgents: string[];
|
|
37
87
|
isSpawning?: boolean;
|
|
38
88
|
error?: string | null;
|
|
39
|
-
/** Whether running in cloud mode (enables credentials check) */
|
|
40
|
-
isCloudMode?: boolean;
|
|
41
89
|
/** Active workspace ID for provider setup redirect */
|
|
42
90
|
workspaceId?: string;
|
|
43
91
|
/** Agent defaults from settings */
|
|
@@ -54,64 +102,31 @@ export interface SpawnModalProps {
|
|
|
54
102
|
repos?: Array<{ id: string; githubFullName: string }>;
|
|
55
103
|
/** Currently active repo ID (cloud mode) */
|
|
56
104
|
activeRepoId?: string;
|
|
105
|
+
/** Connected provider IDs (cloud mode) - used to disable unconnected providers */
|
|
106
|
+
connectedProviders?: string[];
|
|
107
|
+
/** Model options per agent type — provided by the host app */
|
|
108
|
+
modelOptions?: {
|
|
109
|
+
claude?: ModelOption[];
|
|
110
|
+
cursor?: ModelOption[];
|
|
111
|
+
codex?: ModelOption[];
|
|
112
|
+
gemini?: ModelOption[];
|
|
113
|
+
};
|
|
57
114
|
}
|
|
58
115
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
{ value: 'haiku', label: 'Haiku' },
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
type ClaudeModel = string;
|
|
67
|
-
|
|
68
|
-
/** Model options for Cursor agents */
|
|
69
|
-
export const CURSOR_MODEL_OPTIONS: { value: string; label: string }[] = [
|
|
70
|
-
{ value: 'opus-4.5-thinking', label: 'Claude 4.5 Opus (Thinking)' },
|
|
71
|
-
{ value: 'opus-4.5', label: 'Claude 4.5 Opus' },
|
|
72
|
-
{ value: 'sonnet-4.5', label: 'Claude 4.5 Sonnet' },
|
|
73
|
-
{ value: 'sonnet-4.5-thinking', label: 'Claude 4.5 Sonnet (Thinking)' },
|
|
74
|
-
{ value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex' },
|
|
75
|
-
{ value: 'gpt-5.2-codex-high', label: 'GPT-5.2 Codex High' },
|
|
76
|
-
{ value: 'gpt-5.2-codex-low', label: 'GPT-5.2 Codex Low' },
|
|
77
|
-
{ value: 'gpt-5.2-codex-xhigh', label: 'GPT-5.2 Codex Extra High' },
|
|
78
|
-
{ value: 'gpt-5.2-codex-fast', label: 'GPT-5.2 Codex Fast' },
|
|
79
|
-
{ value: 'gpt-5.2-codex-high-fast', label: 'GPT-5.2 Codex High Fast' },
|
|
80
|
-
{ value: 'gpt-5.2-codex-low-fast', label: 'GPT-5.2 Codex Low Fast' },
|
|
81
|
-
{ value: 'gpt-5.2-codex-xhigh-fast', label: 'GPT-5.2 Codex Extra High Fast' },
|
|
82
|
-
{ value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max' },
|
|
83
|
-
{ value: 'gpt-5.1-codex-max-high', label: 'GPT-5.1 Codex Max High' },
|
|
84
|
-
{ value: 'gpt-5.2', label: 'GPT-5.2' },
|
|
85
|
-
{ value: 'gpt-5.2-high', label: 'GPT-5.2 High' },
|
|
86
|
-
{ value: 'gpt-5.1-high', label: 'GPT-5.1 High' },
|
|
87
|
-
{ value: 'gemini-3-pro', label: 'Gemini 3 Pro' },
|
|
88
|
-
{ value: 'gemini-3-flash', label: 'Gemini 3 Flash' },
|
|
89
|
-
{ value: 'composer-1', label: 'Composer 1' },
|
|
90
|
-
{ value: 'grok', label: 'Grok' },
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
type CursorModel = string;
|
|
94
|
-
|
|
95
|
-
/** Model options for Codex agents */
|
|
96
|
-
export const CODEX_MODEL_OPTIONS: { value: string; label: string }[] = [
|
|
97
|
-
{ value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex — Frontier agentic coding model' },
|
|
98
|
-
{ value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex — Latest frontier agentic coding model' },
|
|
99
|
-
{ value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max — Deep and fast reasoning' },
|
|
100
|
-
{ value: 'gpt-5.2', label: 'GPT-5.2 — Frontier model, knowledge & reasoning' },
|
|
101
|
-
{ value: 'gpt-5.1-codex-mini', label: 'GPT-5.1 Codex Mini — Cheaper, faster' },
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
type CodexModel = string;
|
|
116
|
+
export interface ModelOption {
|
|
117
|
+
value: string;
|
|
118
|
+
label: string;
|
|
119
|
+
}
|
|
105
120
|
|
|
106
|
-
|
|
107
|
-
export const GEMINI_MODEL_OPTIONS: { value: string; label: string }[] = [
|
|
108
|
-
{ value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro Preview' },
|
|
109
|
-
{ value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro' },
|
|
110
|
-
{ value: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash' },
|
|
111
|
-
{ value: 'gemini-2.5-flash-lite', label: 'Gemini 2.5 Flash Lite' },
|
|
112
|
-
];
|
|
121
|
+
const EMPTY_MODEL_OPTIONS: ModelOption[] = [];
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
/** Built-in model options sourced from @agent-relay/config (cli-registry.yaml) */
|
|
124
|
+
export const DEFAULT_MODEL_OPTIONS: Record<string, ModelOption[]> = {
|
|
125
|
+
claude: RegistryModelOptions.Claude,
|
|
126
|
+
cursor: RegistryModelOptions.Cursor,
|
|
127
|
+
codex: RegistryModelOptions.Codex,
|
|
128
|
+
gemini: RegistryModelOptions.Gemini,
|
|
129
|
+
};
|
|
115
130
|
|
|
116
131
|
const AGENT_TEMPLATES = [
|
|
117
132
|
{
|
|
@@ -185,22 +200,33 @@ export function SpawnModal({
|
|
|
185
200
|
existingAgents,
|
|
186
201
|
isSpawning = false,
|
|
187
202
|
error,
|
|
188
|
-
isCloudMode = false,
|
|
189
203
|
workspaceId,
|
|
190
204
|
agentDefaults,
|
|
191
205
|
repos,
|
|
192
206
|
activeRepoId,
|
|
207
|
+
connectedProviders,
|
|
208
|
+
modelOptions,
|
|
193
209
|
}: SpawnModalProps) {
|
|
210
|
+
const { features } = useDashboardConfig();
|
|
211
|
+
const hasWorkspaceFeature = features.workspaces;
|
|
212
|
+
const canUseWorkspaceRepoSelection = hasWorkspaceFeature && !!repos?.length;
|
|
213
|
+
|
|
214
|
+
const claudeModels = modelOptions?.claude ?? DEFAULT_MODEL_OPTIONS.claude ?? EMPTY_MODEL_OPTIONS;
|
|
215
|
+
const cursorModels = modelOptions?.cursor ?? DEFAULT_MODEL_OPTIONS.cursor ?? EMPTY_MODEL_OPTIONS;
|
|
216
|
+
const codexModels = modelOptions?.codex ?? DEFAULT_MODEL_OPTIONS.codex ?? EMPTY_MODEL_OPTIONS;
|
|
217
|
+
const geminiModels = modelOptions?.gemini ?? DEFAULT_MODEL_OPTIONS.gemini ?? EMPTY_MODEL_OPTIONS;
|
|
218
|
+
|
|
194
219
|
const [selectedTemplate, setSelectedTemplate] = useState(AGENT_TEMPLATES[0]);
|
|
195
220
|
const [name, setName] = useState('');
|
|
196
221
|
const [customCommand, setCustomCommand] = useState('');
|
|
197
|
-
const [selectedModel, setSelectedModel] = useState
|
|
198
|
-
const [selectedCursorModel, setSelectedCursorModel] = useState
|
|
199
|
-
const [selectedCodexModel, setSelectedCodexModel] = useState
|
|
200
|
-
const [selectedGeminiModel, setSelectedGeminiModel] = useState
|
|
222
|
+
const [selectedModel, setSelectedModel] = useState(agentDefaults?.defaultModels?.claude ?? claudeModels[0]?.value ?? '');
|
|
223
|
+
const [selectedCursorModel, setSelectedCursorModel] = useState(agentDefaults?.defaultModels?.cursor ?? cursorModels[0]?.value ?? '');
|
|
224
|
+
const [selectedCodexModel, setSelectedCodexModel] = useState(agentDefaults?.defaultModels?.codex ?? codexModels[0]?.value ?? '');
|
|
225
|
+
const [selectedGeminiModel, setSelectedGeminiModel] = useState(agentDefaults?.defaultModels?.gemini ?? geminiModels[0]?.value ?? '');
|
|
201
226
|
const [cwd, setCwd] = useState('');
|
|
202
227
|
const [selectedRepoId, setSelectedRepoId] = useState<string | undefined>(activeRepoId);
|
|
203
228
|
const [team, setTeam] = useState('');
|
|
229
|
+
const [continueFromPrevious, setContinueFromPrevious] = useState(false);
|
|
204
230
|
const [isShadow, setIsShadow] = useState(false);
|
|
205
231
|
const [shadowOf, setShadowOf] = useState('');
|
|
206
232
|
const [shadowAgent, setShadowAgent] = useState('');
|
|
@@ -234,69 +260,6 @@ export function SpawnModal({
|
|
|
234
260
|
|
|
235
261
|
const shadowMode = useMemo(() => deriveShadowMode(effectiveCommand), [effectiveCommand]);
|
|
236
262
|
|
|
237
|
-
// Provider credentials state (for cloud mode)
|
|
238
|
-
const [connectedProviders, setConnectedProviders] = useState<Set<string>>(new Set());
|
|
239
|
-
const [isLoadingCredentials, setIsLoadingCredentials] = useState(false);
|
|
240
|
-
|
|
241
|
-
// Check if selected provider has active credentials
|
|
242
|
-
const hasActiveCredentials = useMemo(() => {
|
|
243
|
-
// Non-cloud mode or custom template: no credentials check needed
|
|
244
|
-
if (!isCloudMode || !selectedTemplate.providerId) {
|
|
245
|
-
return true;
|
|
246
|
-
}
|
|
247
|
-
// Check if provider is connected (handle both 'openai' and 'codex' for OpenAI)
|
|
248
|
-
if (selectedTemplate.providerId === 'codex') {
|
|
249
|
-
return connectedProviders.has('codex') || connectedProviders.has('openai');
|
|
250
|
-
}
|
|
251
|
-
return connectedProviders.has(selectedTemplate.providerId);
|
|
252
|
-
}, [isCloudMode, selectedTemplate.providerId, connectedProviders]);
|
|
253
|
-
|
|
254
|
-
// Provider setup URL for CTA
|
|
255
|
-
// Note: /providers/setup/ only supports 'claude' and 'codex'
|
|
256
|
-
// Other providers should go to /providers page
|
|
257
|
-
const providerSetupUrl = useMemo(() => {
|
|
258
|
-
if (!selectedTemplate.providerId) return null;
|
|
259
|
-
const command = selectedTemplate.command;
|
|
260
|
-
const supportedSetupPages = ['claude', 'codex'];
|
|
261
|
-
|
|
262
|
-
if (supportedSetupPages.includes(command)) {
|
|
263
|
-
const base = `/providers/setup/${command}`;
|
|
264
|
-
return workspaceId ? `${base}?workspace=${workspaceId}` : base;
|
|
265
|
-
} else {
|
|
266
|
-
// For other providers, go to main providers page
|
|
267
|
-
return workspaceId ? `/providers?workspace=${workspaceId}` : '/providers';
|
|
268
|
-
}
|
|
269
|
-
}, [selectedTemplate, workspaceId]);
|
|
270
|
-
|
|
271
|
-
// Fetch connected providers when modal opens in cloud mode
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
if (!isOpen || !isCloudMode || !workspaceId) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const fetchProviders = async () => {
|
|
278
|
-
setIsLoadingCredentials(true);
|
|
279
|
-
try {
|
|
280
|
-
// Get workspace-specific provider connection status
|
|
281
|
-
const result = await cloudApi.getProviders(workspaceId);
|
|
282
|
-
if (result.success && result.data.providers) {
|
|
283
|
-
const providers = new Set(
|
|
284
|
-
result.data.providers
|
|
285
|
-
.filter(p => p.isConnected)
|
|
286
|
-
.map(p => p.id)
|
|
287
|
-
);
|
|
288
|
-
setConnectedProviders(providers);
|
|
289
|
-
}
|
|
290
|
-
} catch (err) {
|
|
291
|
-
console.error('Failed to fetch provider credentials:', err);
|
|
292
|
-
} finally {
|
|
293
|
-
setIsLoadingCredentials(false);
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
fetchProviders();
|
|
298
|
-
}, [isOpen, isCloudMode, workspaceId]);
|
|
299
|
-
|
|
300
263
|
const SPEAK_ON_OPTIONS: { value: SpeakOnTrigger; label: string; description: string }[] = [
|
|
301
264
|
{ value: 'EXPLICIT_ASK', label: 'Explicit Ask', description: 'When directly asked' },
|
|
302
265
|
{ value: 'SESSION_END', label: 'Session End', description: 'When session ends' },
|
|
@@ -317,22 +280,30 @@ export function SpawnModal({
|
|
|
317
280
|
useEffect(() => {
|
|
318
281
|
if (isOpen) {
|
|
319
282
|
// Determine default template based on settings
|
|
283
|
+
// In cloud mode, also skip templates whose provider isn't connected
|
|
284
|
+
const isTemplateAvailable = (t: typeof AGENT_TEMPLATES[number]) => {
|
|
285
|
+
if (t.comingSoon && hasWorkspaceFeature) return false;
|
|
286
|
+
if (connectedProviders && t.providerId && !connectedProviders.includes(t.providerId)) return false;
|
|
287
|
+
return true;
|
|
288
|
+
};
|
|
320
289
|
const defaultTemplateId = agentDefaults?.defaultCliType;
|
|
321
290
|
const defaultTemplate = defaultTemplateId
|
|
322
|
-
? AGENT_TEMPLATES.find(t => t.id === defaultTemplateId &&
|
|
323
|
-
|
|
291
|
+
? AGENT_TEMPLATES.find(t => t.id === defaultTemplateId && isTemplateAvailable(t))
|
|
292
|
+
?? AGENT_TEMPLATES.find(t => isTemplateAvailable(t))
|
|
293
|
+
?? AGENT_TEMPLATES[0]
|
|
294
|
+
: AGENT_TEMPLATES.find(t => isTemplateAvailable(t)) ?? AGENT_TEMPLATES[0];
|
|
324
295
|
|
|
325
296
|
setSelectedTemplate(defaultTemplate);
|
|
326
297
|
setName('');
|
|
327
298
|
setCustomCommand('');
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
setSelectedGeminiModel(agentDefaults?.defaultModels?.gemini ?? 'gemini-2.5-pro');
|
|
299
|
+
setSelectedModel(agentDefaults?.defaultModels?.claude ?? claudeModels[0]?.value ?? '');
|
|
300
|
+
setSelectedCursorModel(agentDefaults?.defaultModels?.cursor ?? cursorModels[0]?.value ?? '');
|
|
301
|
+
setSelectedCodexModel(agentDefaults?.defaultModels?.codex ?? codexModels[0]?.value ?? '');
|
|
302
|
+
setSelectedGeminiModel(agentDefaults?.defaultModels?.gemini ?? geminiModels[0]?.value ?? '');
|
|
333
303
|
setCwd('');
|
|
334
304
|
setSelectedRepoId(activeRepoId);
|
|
335
305
|
setTeam('');
|
|
306
|
+
setContinueFromPrevious(false);
|
|
336
307
|
setIsShadow(false);
|
|
337
308
|
setShadowOf('');
|
|
338
309
|
setShadowAgent('');
|
|
@@ -340,7 +311,7 @@ export function SpawnModal({
|
|
|
340
311
|
setLocalError(null);
|
|
341
312
|
setTimeout(() => nameInputRef.current?.focus(), 100);
|
|
342
313
|
}
|
|
343
|
-
}, [isOpen, agentDefaults, activeRepoId, repos]);
|
|
314
|
+
}, [isOpen, agentDefaults, activeRepoId, repos, connectedProviders, hasWorkspaceFeature, claudeModels, cursorModels, codexModels, geminiModels]);
|
|
344
315
|
|
|
345
316
|
const validateName = useCallback(
|
|
346
317
|
(value: string): string | null => {
|
|
@@ -383,7 +354,7 @@ export function SpawnModal({
|
|
|
383
354
|
|
|
384
355
|
// Derive cwd: in cloud mode with repos, use selected repo name; otherwise use text input
|
|
385
356
|
let effectiveCwd: string | undefined;
|
|
386
|
-
if (
|
|
357
|
+
if (canUseWorkspaceRepoSelection && selectedRepoId) {
|
|
387
358
|
if (selectedRepoId === '__all__') {
|
|
388
359
|
// Coordinator mode: no cwd, agent starts at workspace root with access to all repos
|
|
389
360
|
effectiveCwd = undefined;
|
|
@@ -407,6 +378,7 @@ export function SpawnModal({
|
|
|
407
378
|
shadowAgent: shadowAgent.trim() || undefined,
|
|
408
379
|
shadowTriggers: isShadow ? shadowSpeakOn : undefined,
|
|
409
380
|
shadowSpeakOn: isShadow ? shadowSpeakOn : undefined,
|
|
381
|
+
continueFrom: continueFromPrevious ? finalName : undefined,
|
|
410
382
|
});
|
|
411
383
|
|
|
412
384
|
if (success) {
|
|
@@ -454,13 +426,34 @@ export function SpawnModal({
|
|
|
454
426
|
</div>
|
|
455
427
|
|
|
456
428
|
<form onSubmit={handleSubmit} className="p-6">
|
|
429
|
+
{/* No providers connected warning */}
|
|
430
|
+
{connectedProviders && connectedProviders.length === 0 && (
|
|
431
|
+
<div className="mb-5 p-4 rounded-lg border border-red-400/30 bg-red-400/10">
|
|
432
|
+
<p className="text-sm text-red-400 font-medium mb-1">No AI providers connected</p>
|
|
433
|
+
<p className="text-xs text-text-muted">
|
|
434
|
+
Connect an AI provider in your{' '}
|
|
435
|
+
<a
|
|
436
|
+
href={workspaceId ? `/app?workspace=${workspaceId}&tab=providers` : '/providers'}
|
|
437
|
+
className="text-accent underline"
|
|
438
|
+
>
|
|
439
|
+
workspace settings
|
|
440
|
+
</a>
|
|
441
|
+
{' '}to spawn agents.
|
|
442
|
+
</p>
|
|
443
|
+
</div>
|
|
444
|
+
)}
|
|
457
445
|
{/* Agent Type Selection */}
|
|
458
446
|
<div className="mb-5">
|
|
459
447
|
<label className="block text-sm font-semibold text-text-primary mb-2">Agent Type</label>
|
|
460
448
|
<div className="grid grid-cols-3 gap-2">
|
|
461
449
|
{AGENT_TEMPLATES.map((template) => {
|
|
462
450
|
// Only disable "coming soon" providers in cloud mode - locally they might be available
|
|
463
|
-
const
|
|
451
|
+
const isComingSoon = template.comingSoon && hasWorkspaceFeature;
|
|
452
|
+
// In cloud mode, disable providers that aren't connected (skip for custom/null providerId)
|
|
453
|
+
const isProviderMissing = connectedProviders && template.providerId
|
|
454
|
+
? !connectedProviders.includes(template.providerId)
|
|
455
|
+
: false;
|
|
456
|
+
const isDisabled = isComingSoon || isProviderMissing;
|
|
464
457
|
return (
|
|
465
458
|
<button
|
|
466
459
|
key={template.id}
|
|
@@ -477,11 +470,16 @@ export function SpawnModal({
|
|
|
477
470
|
`}
|
|
478
471
|
onClick={() => !isDisabled && setSelectedTemplate(template)}
|
|
479
472
|
>
|
|
480
|
-
{
|
|
473
|
+
{isComingSoon && (
|
|
481
474
|
<span className="absolute top-1 right-1 px-1.5 py-0.5 bg-amber-400/20 text-amber-400 text-[10px] font-medium rounded">
|
|
482
475
|
Soon
|
|
483
476
|
</span>
|
|
484
477
|
)}
|
|
478
|
+
{isProviderMissing && !isComingSoon && (
|
|
479
|
+
<span className="absolute top-1 right-1 px-1.5 py-0.5 bg-red-400/20 text-red-400 text-[10px] font-medium rounded">
|
|
480
|
+
Not Connected
|
|
481
|
+
</span>
|
|
482
|
+
)}
|
|
485
483
|
<span className={`text-2xl ${isDisabled ? 'grayscale' : ''}`}>{template.icon}</span>
|
|
486
484
|
<span className="text-sm font-semibold text-text-primary">{template.name}</span>
|
|
487
485
|
<span className="text-xs text-text-muted text-center">{template.description}</span>
|
|
@@ -501,10 +499,10 @@ export function SpawnModal({
|
|
|
501
499
|
id="claude-model"
|
|
502
500
|
className="w-full py-2.5 px-3.5 border border-border rounded-md text-sm font-sans outline-none bg-bg-primary text-text-primary transition-colors duration-150 focus:border-accent disabled:bg-bg-hover disabled:text-text-muted"
|
|
503
501
|
value={selectedModel}
|
|
504
|
-
onChange={(e) => setSelectedModel(e.target.value
|
|
502
|
+
onChange={(e) => setSelectedModel(e.target.value)}
|
|
505
503
|
disabled={isSpawning}
|
|
506
504
|
>
|
|
507
|
-
{
|
|
505
|
+
{claudeModels.map((model) => (
|
|
508
506
|
<option key={model.value} value={model.value}>
|
|
509
507
|
{model.label}
|
|
510
508
|
</option>
|
|
@@ -523,10 +521,10 @@ export function SpawnModal({
|
|
|
523
521
|
id="cursor-model"
|
|
524
522
|
className="w-full py-2.5 px-3.5 border border-border rounded-md text-sm font-sans outline-none bg-bg-primary text-text-primary transition-colors duration-150 focus:border-accent disabled:bg-bg-hover disabled:text-text-muted"
|
|
525
523
|
value={selectedCursorModel}
|
|
526
|
-
onChange={(e) => setSelectedCursorModel(e.target.value
|
|
524
|
+
onChange={(e) => setSelectedCursorModel(e.target.value)}
|
|
527
525
|
disabled={isSpawning}
|
|
528
526
|
>
|
|
529
|
-
{
|
|
527
|
+
{cursorModels.map((model) => (
|
|
530
528
|
<option key={model.value} value={model.value}>
|
|
531
529
|
{model.label}
|
|
532
530
|
</option>
|
|
@@ -545,10 +543,10 @@ export function SpawnModal({
|
|
|
545
543
|
id="codex-model"
|
|
546
544
|
className="w-full py-2.5 px-3.5 border border-border rounded-md text-sm font-sans outline-none bg-bg-primary text-text-primary transition-colors duration-150 focus:border-accent disabled:bg-bg-hover disabled:text-text-muted"
|
|
547
545
|
value={selectedCodexModel}
|
|
548
|
-
onChange={(e) => setSelectedCodexModel(e.target.value
|
|
546
|
+
onChange={(e) => setSelectedCodexModel(e.target.value)}
|
|
549
547
|
disabled={isSpawning}
|
|
550
548
|
>
|
|
551
|
-
{
|
|
549
|
+
{codexModels.map((model) => (
|
|
552
550
|
<option key={model.value} value={model.value}>
|
|
553
551
|
{model.label}
|
|
554
552
|
</option>
|
|
@@ -567,10 +565,10 @@ export function SpawnModal({
|
|
|
567
565
|
id="gemini-model"
|
|
568
566
|
className="w-full py-2.5 px-3.5 border border-border rounded-md text-sm font-sans outline-none bg-bg-primary text-text-primary transition-colors duration-150 focus:border-accent disabled:bg-bg-hover disabled:text-text-muted"
|
|
569
567
|
value={selectedGeminiModel}
|
|
570
|
-
onChange={(e) => setSelectedGeminiModel(e.target.value
|
|
568
|
+
onChange={(e) => setSelectedGeminiModel(e.target.value)}
|
|
571
569
|
disabled={isSpawning}
|
|
572
570
|
>
|
|
573
|
-
{
|
|
571
|
+
{geminiModels.map((model) => (
|
|
574
572
|
<option key={model.value} value={model.value}>
|
|
575
573
|
{model.label}
|
|
576
574
|
</option>
|
|
@@ -642,7 +640,7 @@ export function SpawnModal({
|
|
|
642
640
|
)}
|
|
643
641
|
|
|
644
642
|
{/* Repository (cloud) / Working Directory (local) */}
|
|
645
|
-
{
|
|
643
|
+
{canUseWorkspaceRepoSelection ? (
|
|
646
644
|
<div className="mb-5">
|
|
647
645
|
<label className="block text-sm font-semibold text-text-primary mb-2" htmlFor="agent-repo">
|
|
648
646
|
Repository
|
|
@@ -686,6 +684,37 @@ export function SpawnModal({
|
|
|
686
684
|
</div>
|
|
687
685
|
)}
|
|
688
686
|
|
|
687
|
+
{/* Resume from Previous Session */}
|
|
688
|
+
<div className="mb-5 p-4 border border-border rounded-lg bg-bg-hover/50">
|
|
689
|
+
<div className="flex items-center justify-between">
|
|
690
|
+
<div>
|
|
691
|
+
<label className="block text-sm font-semibold text-text-primary">
|
|
692
|
+
Resume Previous Session
|
|
693
|
+
</label>
|
|
694
|
+
<span className="text-xs text-text-muted">
|
|
695
|
+
Inject context from this agent's last session
|
|
696
|
+
</span>
|
|
697
|
+
</div>
|
|
698
|
+
<button
|
|
699
|
+
type="button"
|
|
700
|
+
className={`
|
|
701
|
+
relative w-11 h-6 rounded-full transition-colors duration-200
|
|
702
|
+
${continueFromPrevious ? 'bg-accent' : 'bg-bg-active'}
|
|
703
|
+
`}
|
|
704
|
+
onClick={() => setContinueFromPrevious(!continueFromPrevious)}
|
|
705
|
+
disabled={isSpawning}
|
|
706
|
+
aria-pressed={continueFromPrevious}
|
|
707
|
+
>
|
|
708
|
+
<span
|
|
709
|
+
className={`
|
|
710
|
+
absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full transition-transform duration-200 shadow-sm
|
|
711
|
+
${continueFromPrevious ? 'translate-x-5' : 'translate-x-0'}
|
|
712
|
+
`}
|
|
713
|
+
/>
|
|
714
|
+
</button>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
|
|
689
718
|
{/* Shadow Agent Configuration */}
|
|
690
719
|
<div className="mb-5 p-4 border border-border rounded-lg bg-bg-hover/50">
|
|
691
720
|
<div className="flex items-center justify-between mb-3">
|
|
@@ -791,40 +820,6 @@ export function SpawnModal({
|
|
|
791
820
|
)}
|
|
792
821
|
</div>
|
|
793
822
|
|
|
794
|
-
{/* Credentials CTA - shown when provider is not connected */}
|
|
795
|
-
{isCloudMode && !hasActiveCredentials && !isLoadingCredentials && selectedTemplate.providerId && (
|
|
796
|
-
<div className="p-4 bg-amber-400/10 border border-amber-400/30 rounded-lg mb-5">
|
|
797
|
-
<div className="flex items-start gap-3">
|
|
798
|
-
<div className="shrink-0 w-8 h-8 rounded-lg bg-amber-400/20 flex items-center justify-center">
|
|
799
|
-
<LockIcon />
|
|
800
|
-
</div>
|
|
801
|
-
<div className="flex-1">
|
|
802
|
-
<h4 className="text-sm font-semibold text-amber-400 mb-1">
|
|
803
|
-
{selectedTemplate.name} credentials required
|
|
804
|
-
</h4>
|
|
805
|
-
<p className="text-xs text-text-secondary mb-3">
|
|
806
|
-
Connect your {selectedTemplate.name} account to spawn {selectedTemplate.name} agents.
|
|
807
|
-
This enables secure access to the AI provider's API.
|
|
808
|
-
</p>
|
|
809
|
-
<a
|
|
810
|
-
href={providerSetupUrl || '#'}
|
|
811
|
-
className="inline-flex items-center gap-2 py-2 px-4 bg-amber-400 text-bg-deep font-semibold rounded-md text-sm hover:bg-amber-500 transition-colors"
|
|
812
|
-
>
|
|
813
|
-
<LockIcon />
|
|
814
|
-
Connect {selectedTemplate.name}
|
|
815
|
-
</a>
|
|
816
|
-
</div>
|
|
817
|
-
</div>
|
|
818
|
-
</div>
|
|
819
|
-
)}
|
|
820
|
-
|
|
821
|
-
{/* Loading credentials indicator */}
|
|
822
|
-
{isCloudMode && isLoadingCredentials && (
|
|
823
|
-
<div className="flex items-center gap-2 p-3 bg-bg-hover rounded-md text-text-muted text-sm mb-5">
|
|
824
|
-
<Spinner />
|
|
825
|
-
<span>Checking provider credentials...</span>
|
|
826
|
-
</div>
|
|
827
|
-
)}
|
|
828
823
|
|
|
829
824
|
{/* Error Display */}
|
|
830
825
|
{displayError && (
|
|
@@ -847,8 +842,7 @@ export function SpawnModal({
|
|
|
847
842
|
<button
|
|
848
843
|
type="submit"
|
|
849
844
|
className="flex items-center gap-1.5 py-2.5 px-4 border-none rounded-md text-sm font-medium cursor-pointer font-sans transition-all duration-150 bg-accent text-white hover:bg-accent-hover disabled:opacity-50 disabled:cursor-not-allowed"
|
|
850
|
-
disabled={isSpawning
|
|
851
|
-
title={!hasActiveCredentials && isCloudMode ? `Connect ${selectedTemplate.name} credentials first` : undefined}
|
|
845
|
+
disabled={isSpawning}
|
|
852
846
|
>
|
|
853
847
|
<RocketIcon />
|
|
854
848
|
Spawn Agent
|
|
@@ -890,23 +884,6 @@ function RocketIcon() {
|
|
|
890
884
|
);
|
|
891
885
|
}
|
|
892
886
|
|
|
893
|
-
function Spinner() {
|
|
894
|
-
return (
|
|
895
|
-
<svg className="animate-spin" width="16" height="16" viewBox="0 0 24 24">
|
|
896
|
-
<circle
|
|
897
|
-
cx="12"
|
|
898
|
-
cy="12"
|
|
899
|
-
r="10"
|
|
900
|
-
stroke="currentColor"
|
|
901
|
-
strokeWidth="2"
|
|
902
|
-
fill="none"
|
|
903
|
-
strokeDasharray="32"
|
|
904
|
-
strokeLinecap="round"
|
|
905
|
-
/>
|
|
906
|
-
</svg>
|
|
907
|
-
);
|
|
908
|
-
}
|
|
909
|
-
|
|
910
887
|
const SPAWNING_MESSAGES = [
|
|
911
888
|
'Initializing agent environment...',
|
|
912
889
|
'Loading model configuration...',
|
|
@@ -990,12 +967,3 @@ function SpawningOverlay({ agentName, colors }: { agentName: string; colors: { p
|
|
|
990
967
|
</div>
|
|
991
968
|
);
|
|
992
969
|
}
|
|
993
|
-
|
|
994
|
-
function LockIcon() {
|
|
995
|
-
return (
|
|
996
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
997
|
-
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
|
|
998
|
-
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
999
|
-
</svg>
|
|
1000
|
-
);
|
|
1001
|
-
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Used in:
|
|
9
9
|
* - /providers/setup/[provider] page (full-page setup)
|
|
10
|
-
* -
|
|
10
|
+
* - Settings workspace slot implementations (embedded setup)
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import React, { useRef, useEffect, useCallback, useState } from 'react';
|
|
@@ -371,7 +371,9 @@ function ThreadAttachments({ attachments }: ThreadAttachmentsProps) {
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
function formatTimestamp(timestamp: string | number): string {
|
|
374
|
+
if (!timestamp) return '';
|
|
374
375
|
const date = new Date(timestamp);
|
|
376
|
+
if (isNaN(date.getTime())) return '';
|
|
375
377
|
const now = new Date();
|
|
376
378
|
const isToday = date.toDateString() === now.toDateString();
|
|
377
379
|
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides the current workspace's base URL for WebSocket connections.
|
|
5
5
|
* Used by LogViewer and other components that need to connect to workspace-specific endpoints.
|
|
6
|
+
* Cloud mode is sourced from DashboardConfig instead of runtime hostname/env detection.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import React, { createContext, useContext, useMemo } from 'react';
|
|
10
|
+
import { useDashboardConfig } from '../adapters';
|
|
9
11
|
import { getWebSocketUrl } from '../lib/config';
|
|
10
12
|
|
|
11
13
|
interface WorkspaceContextValue {
|
|
12
14
|
/** Base WebSocket URL for the workspace (e.g., wss://workspace-abc.agentrelay.dev) */
|
|
13
15
|
wsBaseUrl: string | null;
|
|
14
|
-
/** Whether
|
|
16
|
+
/** Whether cloud mode is enabled in dashboard configuration */
|
|
15
17
|
isCloudMode: boolean;
|
|
16
18
|
}
|
|
17
19
|
|
|
@@ -40,26 +42,12 @@ function getBaseUrl(wsUrl: string): string {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
export function WorkspaceProvider({ children, wsUrl }: WorkspaceProviderProps) {
|
|
43
|
-
const
|
|
44
|
-
if (!wsUrl) {
|
|
45
|
-
return { wsBaseUrl: null, isCloudMode: false };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const wsBaseUrl = getBaseUrl(wsUrl);
|
|
49
|
-
|
|
50
|
-
// Check if we're in cloud mode by comparing the workspace URL host with the current page host
|
|
51
|
-
let isCloudMode = false;
|
|
52
|
-
if (typeof window !== 'undefined') {
|
|
53
|
-
try {
|
|
54
|
-
const wsHost = new URL(wsUrl).host;
|
|
55
|
-
isCloudMode = wsHost !== window.location.host;
|
|
56
|
-
} catch {
|
|
57
|
-
// Ignore parse errors
|
|
58
|
-
}
|
|
59
|
-
}
|
|
45
|
+
const { isCloudMode } = useDashboardConfig();
|
|
60
46
|
|
|
47
|
+
const value = useMemo(() => {
|
|
48
|
+
const wsBaseUrl = wsUrl ? getBaseUrl(wsUrl) : null;
|
|
61
49
|
return { wsBaseUrl, isCloudMode };
|
|
62
|
-
}, [wsUrl]);
|
|
50
|
+
}, [wsUrl, isCloudMode]);
|
|
63
51
|
|
|
64
52
|
return (
|
|
65
53
|
<WorkspaceContext.Provider value={value}>
|