@swarmclawai/swarmclaw 1.2.4 → 1.2.6
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/README.md +14 -0
- package/bin/daemon-cmd.js +169 -0
- package/bin/server-cmd.js +3 -0
- package/bin/swarmclaw.js +11 -0
- package/package.json +17 -16
- package/src/app/api/agents/[id]/clone/route.ts +3 -32
- package/src/app/api/agents/[id]/route.ts +6 -158
- package/src/app/api/agents/[id]/status/route.ts +2 -3
- package/src/app/api/agents/[id]/thread/route.ts +4 -17
- package/src/app/api/agents/bulk/route.ts +5 -47
- package/src/app/api/agents/route.ts +5 -119
- package/src/app/api/agents/trash/route.ts +13 -24
- package/src/app/api/auth/route.ts +3 -9
- package/src/app/api/autonomy/estop/route.ts +5 -5
- package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
- package/src/app/api/chatrooms/[id]/route.ts +23 -2
- package/src/app/api/chatrooms/route.ts +13 -2
- package/src/app/api/chats/[id]/clear/route.ts +2 -13
- package/src/app/api/chats/[id]/deploy/route.ts +2 -3
- package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
- package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
- package/src/app/api/chats/[id]/queue/route.ts +17 -64
- package/src/app/api/chats/[id]/retry/route.ts +4 -22
- package/src/app/api/chats/[id]/route.ts +10 -138
- package/src/app/api/chats/heartbeat/route.ts +2 -1
- package/src/app/api/chats/migrate-messages/route.ts +7 -0
- package/src/app/api/chats/route.ts +13 -134
- package/src/app/api/connectors/[id]/access/route.ts +12 -229
- package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
- package/src/app/api/connectors/[id]/health/route.ts +12 -39
- package/src/app/api/connectors/[id]/route.ts +14 -122
- package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
- package/src/app/api/connectors/doctor/route.ts +1 -1
- package/src/app/api/connectors/route.ts +12 -70
- package/src/app/api/credentials/[id]/route.ts +2 -4
- package/src/app/api/credentials/route.ts +10 -19
- package/src/app/api/daemon/health-check/route.ts +3 -4
- package/src/app/api/daemon/route.ts +10 -8
- package/src/app/api/documents/route.ts +11 -10
- package/src/app/api/external-agents/route.ts +3 -3
- package/src/app/api/gateways/[id]/health/route.ts +2 -3
- package/src/app/api/gateways/[id]/route.ts +7 -122
- package/src/app/api/gateways/route.ts +3 -103
- package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
- package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
- package/src/app/api/openclaw/directory/route.ts +2 -2
- package/src/app/api/openclaw/history/route.ts +3 -5
- package/src/app/api/providers/[id]/route.test.ts +49 -0
- package/src/app/api/providers/ollama/route.ts +6 -5
- package/src/app/api/schedules/[id]/route.ts +14 -108
- package/src/app/api/schedules/[id]/run/route.ts +6 -67
- package/src/app/api/schedules/route.ts +9 -51
- package/src/app/api/settings/route.ts +4 -3
- package/src/app/api/setup/check-provider/route.ts +23 -1
- package/src/app/api/setup/openclaw-device/route.ts +2 -2
- package/src/app/api/system/status/route.ts +2 -2
- package/src/app/api/tasks/[id]/route.ts +16 -202
- package/src/app/api/tasks/bulk/route.ts +5 -86
- package/src/app/api/tasks/metrics/route.ts +2 -1
- package/src/app/api/tasks/route.ts +11 -171
- package/src/app/api/upload/route.ts +1 -1
- package/src/app/api/uploads/[filename]/route.ts +1 -1
- package/src/app/api/uploads/route.ts +1 -1
- package/src/app/api/webhooks/[id]/history/route.ts +2 -2
- package/src/app/layout.tsx +9 -6
- package/src/app/protocols/page.tsx +71 -89
- package/src/app/tasks/page.tsx +32 -32
- package/src/cli/index.js +1 -0
- package/src/cli/spec.js +1 -0
- package/src/components/agents/agent-sheet.tsx +5 -5
- package/src/components/auth/setup-wizard/index.tsx +4 -4
- package/src/components/auth/setup-wizard/step-agents.tsx +1 -1
- package/src/components/auth/setup-wizard/step-connect.tsx +1 -1
- package/src/components/auth/setup-wizard/utils.ts +1 -1
- package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
- package/src/components/connectors/connector-list.tsx +26 -40
- package/src/components/connectors/connector-sheet.tsx +95 -149
- package/src/components/gateways/gateway-sheet.tsx +61 -110
- package/src/components/layout/live-query-sync.tsx +121 -0
- package/src/components/protocols/structured-session-launcher.tsx +24 -45
- package/src/components/providers/app-query-provider.tsx +17 -0
- package/src/components/providers/provider-list.tsx +60 -61
- package/src/components/providers/provider-sheet.tsx +74 -56
- package/src/components/skills/skill-list.tsx +5 -18
- package/src/components/skills/skill-sheet.tsx +21 -20
- package/src/components/skills/skills-workspace.tsx +48 -87
- package/src/components/tasks/task-card.tsx +20 -13
- package/src/components/tasks/task-column.tsx +22 -7
- package/src/components/tasks/task-list.tsx +8 -11
- package/src/components/tasks/task-sheet.tsx +111 -103
- package/src/features/agents/queries.ts +20 -0
- package/src/features/chatrooms/queries.ts +20 -0
- package/src/features/chats/queries.ts +27 -0
- package/src/features/connectors/queries.ts +145 -0
- package/src/features/credentials/queries.ts +37 -0
- package/src/features/extensions/queries.ts +26 -0
- package/src/features/external-agents/queries.ts +36 -0
- package/src/features/gateways/queries.ts +274 -0
- package/src/features/missions/queries.ts +23 -0
- package/src/features/projects/queries.ts +20 -0
- package/src/features/protocols/queries.ts +149 -0
- package/src/features/providers/queries.ts +142 -0
- package/src/features/settings/queries.ts +20 -0
- package/src/features/skills/queries.ts +182 -0
- package/src/features/tasks/queries.ts +189 -0
- package/src/hooks/use-ws.ts +3 -2
- package/src/lib/app/api-client.ts +2 -2
- package/src/lib/providers/index.test.ts +108 -0
- package/src/lib/providers/index.ts +38 -15
- package/src/lib/query/client.ts +17 -0
- package/src/lib/server/agents/agent-runtime-config.ts +1 -1
- package/src/lib/server/agents/agent-service.ts +429 -0
- package/src/lib/server/agents/agent-thread-session.ts +6 -5
- package/src/lib/server/agents/autonomy-contract.ts +1 -4
- package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
- package/src/lib/server/agents/delegation-advisory.ts +251 -0
- package/src/lib/server/agents/main-agent-loop.ts +98 -40
- package/src/lib/server/agents/subagent-runtime.ts +12 -0
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
- package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
- package/src/lib/server/build-llm.ts +7 -15
- package/src/lib/server/capability-router.test.ts +70 -1
- package/src/lib/server/capability-router.ts +24 -99
- package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
- package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
- package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
- package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
- package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
- package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
- package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
- package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
- package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
- package/src/lib/server/chat-execution/message-classifier.ts +74 -32
- package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
- package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
- package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
- package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
- package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
- package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
- package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
- package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
- package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
- package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
- package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
- package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
- package/src/lib/server/chats/chat-session-service.ts +410 -0
- package/src/lib/server/connectors/access.ts +1 -1
- package/src/lib/server/connectors/commands.ts +7 -6
- package/src/lib/server/connectors/connector-inbound.ts +14 -7
- package/src/lib/server/connectors/connector-outbound.ts +16 -11
- package/src/lib/server/connectors/connector-service.ts +453 -0
- package/src/lib/server/connectors/delivery.ts +17 -12
- package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
- package/src/lib/server/connectors/media.ts +1 -1
- package/src/lib/server/connectors/response-media.ts +1 -1
- package/src/lib/server/connectors/session-consolidation.ts +11 -7
- package/src/lib/server/connectors/session.ts +9 -7
- package/src/lib/server/connectors/voice-note.ts +2 -1
- package/src/lib/server/context-manager.ts +20 -1
- package/src/lib/server/cost.ts +2 -3
- package/src/lib/server/credentials/credential-repository.ts +43 -4
- package/src/lib/server/credentials/credential-service.ts +112 -0
- package/src/lib/server/daemon/admin-metadata.ts +64 -0
- package/src/lib/server/daemon/controller.ts +577 -0
- package/src/lib/server/daemon/daemon-runtime.ts +352 -0
- package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
- package/src/lib/server/daemon/types.ts +101 -0
- package/src/lib/server/embeddings.ts +3 -9
- package/src/lib/server/eval/agent-regression.ts +3 -2
- package/src/lib/server/eval/runner.ts +2 -2
- package/src/lib/server/execution-brief.test.ts +167 -0
- package/src/lib/server/execution-brief.ts +295 -0
- package/src/lib/server/execution-engine/chat-turn.ts +9 -0
- package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
- package/src/lib/server/execution-engine/index.ts +35 -0
- package/src/lib/server/execution-engine/task-attempt.ts +303 -0
- package/src/lib/server/execution-engine/types.ts +33 -0
- package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
- package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
- package/src/lib/server/memory/session-archive-memory.ts +12 -10
- package/src/lib/server/messages/message-repository.ts +330 -0
- package/src/lib/server/missions/mission-service/core.ts +8 -6
- package/src/lib/server/openclaw/agent-resolver.ts +2 -3
- package/src/lib/server/openclaw/doctor.ts +1 -1
- package/src/lib/server/openclaw/gateway.test.ts +10 -1
- package/src/lib/server/openclaw/gateway.ts +5 -14
- package/src/lib/server/openclaw/health.ts +3 -11
- package/src/lib/server/openclaw/sync.ts +8 -6
- package/src/lib/server/persistence/storage-context.ts +3 -0
- package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
- package/src/lib/server/protocols/protocol-normalization.ts +1 -1
- package/src/lib/server/protocols/protocol-queries.ts +13 -7
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
- package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
- package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
- package/src/lib/server/protocols/protocol-swarm.ts +8 -8
- package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
- package/src/lib/server/protocols/protocol-templates.ts +4 -2
- package/src/lib/server/protocols/protocol-types.ts +10 -7
- package/src/lib/server/provider-endpoint.ts +7 -12
- package/src/lib/server/provider-model-discovery.ts +2 -11
- package/src/lib/server/query-expansion.ts +5 -6
- package/src/lib/server/run-context.test.ts +365 -0
- package/src/lib/server/run-context.ts +367 -0
- package/src/lib/server/runtime/heartbeat-service.ts +7 -5
- package/src/lib/server/runtime/queue/core.ts +61 -190
- package/src/lib/server/runtime/run-ledger.ts +8 -0
- package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
- package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
- package/src/lib/server/schedules/schedule-route-service.ts +230 -0
- package/src/lib/server/service-result.ts +16 -0
- package/src/lib/server/session-note.ts +2 -3
- package/src/lib/server/session-reset-policy.ts +4 -3
- package/src/lib/server/session-tools/connector.ts +9 -6
- package/src/lib/server/session-tools/context-mgmt.ts +58 -9
- package/src/lib/server/session-tools/crud.ts +162 -10
- package/src/lib/server/session-tools/delegate.ts +1 -1
- package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
- package/src/lib/server/session-tools/memory.ts +6 -4
- package/src/lib/server/session-tools/session-info.test.ts +56 -0
- package/src/lib/server/session-tools/session-info.ts +119 -12
- package/src/lib/server/session-tools/skill-runtime.ts +3 -1
- package/src/lib/server/session-tools/skills.ts +15 -15
- package/src/lib/server/session-tools/subagent.test.ts +115 -1
- package/src/lib/server/session-tools/subagent.ts +125 -7
- package/src/lib/server/session-tools/team-context.ts +4 -3
- package/src/lib/server/session-tools/wallet.ts +0 -58
- package/src/lib/server/sessions/session-lineage.ts +55 -0
- package/src/lib/server/sessions/session-repository.ts +2 -2
- package/src/lib/server/skills/learned-skills.ts +24 -23
- package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
- package/src/lib/server/skills/skill-repository.ts +136 -13
- package/src/lib/server/skills/skill-suggestions.ts +25 -28
- package/src/lib/server/storage-normalization.test.ts +44 -267
- package/src/lib/server/storage-normalization.ts +75 -0
- package/src/lib/server/storage.ts +19 -0
- package/src/lib/server/structured-extract.ts +3 -14
- package/src/lib/server/tasks/task-followups.ts +16 -11
- package/src/lib/server/tasks/task-result.test.ts +25 -29
- package/src/lib/server/tasks/task-result.ts +5 -9
- package/src/lib/server/tasks/task-route-service.ts +449 -0
- package/src/lib/server/text-normalization.ts +41 -0
- package/src/lib/server/tool-planning.ts +6 -42
- package/src/lib/server/upload-path.ts +5 -0
- package/src/lib/server/working-state/extraction.ts +614 -0
- package/src/lib/server/working-state/normalization.ts +866 -0
- package/src/lib/server/working-state/prompt.ts +60 -0
- package/src/lib/server/working-state/repository.ts +38 -0
- package/src/lib/server/working-state/service.test.ts +253 -0
- package/src/lib/server/working-state/service.ts +293 -0
- package/src/lib/validation/schemas.ts +1 -0
- package/src/lib/ws-client.ts +3 -3
- package/src/stores/slices/task-slice.ts +1 -4
- package/src/stores/use-chatroom-store.ts +2 -2
- package/src/types/index.ts +277 -12
|
@@ -1,35 +1,19 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
3
|
-
import { genId } from '@/lib/id'
|
|
4
3
|
import { perf } from '@/lib/server/runtime/perf'
|
|
5
|
-
import { deleteTask, loadAgents, loadSettings, loadTasks, logActivity, upsertTask } from '@/lib/server/storage'
|
|
6
4
|
import { TaskCreateSchema, formatZodError } from '@/lib/validation/schemas'
|
|
7
5
|
import { z } from 'zod'
|
|
8
|
-
import { enqueueTask, recoverStalledRunningTasks, validateCompletedTasksQueue } from '@/lib/server/runtime/queue'
|
|
9
|
-
import { pushMainLoopEventToMainSessions } from '@/lib/server/agents/main-agent-loop'
|
|
10
|
-
import { notify } from '@/lib/server/ws-hub'
|
|
11
|
-
import { resolveTaskAgentFromDescription } from '@/lib/server/tasks/task-mention'
|
|
12
|
-
import { validateDag } from '@/lib/server/dag-validation'
|
|
13
|
-
import { getExtensionManager } from '@/lib/server/extensions'
|
|
14
|
-
import { getEnabledCapabilityIds } from '@/lib/capability-selection'
|
|
15
6
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
createTaskFromRoute,
|
|
8
|
+
deleteTasksByFilter,
|
|
9
|
+
prepareTasksForListing,
|
|
10
|
+
} from '@/lib/server/tasks/task-route-service'
|
|
20
11
|
|
|
21
12
|
export async function GET(req: Request) {
|
|
22
13
|
const endPerf = perf.start('api', 'GET /api/tasks')
|
|
23
|
-
// Keep completed queue integrity even if daemon is not running.
|
|
24
|
-
validateCompletedTasksQueue()
|
|
25
|
-
recoverStalledRunningTasks()
|
|
26
|
-
|
|
27
14
|
const { searchParams } = new URL(req.url)
|
|
28
15
|
const includeArchived = searchParams.get('includeArchived') === 'true'
|
|
29
|
-
const
|
|
30
|
-
const missionTasks = Object.fromEntries(
|
|
31
|
-
Object.entries(allTasks).map(([id, task]) => [id, enrichTaskWithMissionSummary(task)]),
|
|
32
|
-
)
|
|
16
|
+
const missionTasks = prepareTasksForListing()
|
|
33
17
|
|
|
34
18
|
if (includeArchived) {
|
|
35
19
|
endPerf({ count: Object.keys(missionTasks).length })
|
|
@@ -37,7 +21,7 @@ export async function GET(req: Request) {
|
|
|
37
21
|
}
|
|
38
22
|
|
|
39
23
|
// Exclude archived tasks by default
|
|
40
|
-
const filtered: Record<string, typeof
|
|
24
|
+
const filtered: Record<string, (typeof missionTasks)[string]> = {}
|
|
41
25
|
for (const [id, task] of Object.entries(missionTasks)) {
|
|
42
26
|
if (task.status !== 'archived') {
|
|
43
27
|
filtered[id] = task
|
|
@@ -50,23 +34,7 @@ export async function GET(req: Request) {
|
|
|
50
34
|
export async function DELETE(req: Request) {
|
|
51
35
|
const { searchParams } = new URL(req.url)
|
|
52
36
|
const filter = searchParams.get('filter') // 'all' | 'schedule' | 'done' | null
|
|
53
|
-
|
|
54
|
-
let removed = 0
|
|
55
|
-
|
|
56
|
-
const shouldRemove = (task: { status: string; sourceType?: string }) =>
|
|
57
|
-
filter === 'all' ||
|
|
58
|
-
(filter === 'schedule' && task.sourceType === 'schedule') ||
|
|
59
|
-
(filter === 'done' && (task.status === 'completed' || task.status === 'failed')) ||
|
|
60
|
-
(!filter && task.status === 'archived')
|
|
61
|
-
|
|
62
|
-
for (const [id, task] of Object.entries(tasks)) {
|
|
63
|
-
if (shouldRemove(task as { status: string; sourceType?: string })) {
|
|
64
|
-
deleteTask(id)
|
|
65
|
-
removed++
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
notify('tasks')
|
|
69
|
-
return NextResponse.json({ removed, remaining: Object.keys(tasks).length - removed })
|
|
37
|
+
return NextResponse.json(deleteTasksByFilter(filter))
|
|
70
38
|
}
|
|
71
39
|
|
|
72
40
|
export async function POST(req: Request) {
|
|
@@ -76,136 +44,8 @@ export async function POST(req: Request) {
|
|
|
76
44
|
if (!parsed.success) {
|
|
77
45
|
return NextResponse.json(formatZodError(parsed.error as z.ZodError), { status: 400 })
|
|
78
46
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const settings = loadSettings()
|
|
84
|
-
const maxAttempts = Number.isFinite(Number(body.maxAttempts))
|
|
85
|
-
? Math.max(1, Math.min(20, Math.trunc(Number(body.maxAttempts))))
|
|
86
|
-
: Math.max(1, Math.min(20, Math.trunc(Number(settings.defaultTaskMaxAttempts ?? 3))))
|
|
87
|
-
const retryBackoffSec = Number.isFinite(Number(body.retryBackoffSec))
|
|
88
|
-
? Math.max(1, Math.min(3600, Math.trunc(Number(body.retryBackoffSec))))
|
|
89
|
-
: Math.max(1, Math.min(3600, Math.trunc(Number(settings.taskRetryBackoffSec ?? 30))))
|
|
90
|
-
// DAG validation: reject if proposed blockedBy would create a cycle
|
|
91
|
-
if (Array.isArray(body.blockedBy) && body.blockedBy.length > 0) {
|
|
92
|
-
const dagResult = validateDag(tasks, id, body.blockedBy)
|
|
93
|
-
if (!dagResult.valid) {
|
|
94
|
-
return NextResponse.json(
|
|
95
|
-
{ error: 'Dependency cycle detected', cycle: dagResult.cycle },
|
|
96
|
-
{ status: 400 },
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Resolve @mentions in description to auto-assign agent
|
|
102
|
-
const resolvedAgentId = body.description
|
|
103
|
-
? resolveTaskAgentFromDescription(body.description, body.agentId || '', loadAgents())
|
|
104
|
-
: (body.agentId || '')
|
|
105
|
-
|
|
106
|
-
const prepared = prepareTaskCreation({
|
|
107
|
-
id,
|
|
108
|
-
input: {
|
|
109
|
-
...body,
|
|
110
|
-
agentId: resolvedAgentId,
|
|
111
|
-
},
|
|
112
|
-
tasks,
|
|
113
|
-
now,
|
|
114
|
-
settings,
|
|
115
|
-
seed: {
|
|
116
|
-
projectId: typeof body.projectId === 'string' && body.projectId ? body.projectId : null,
|
|
117
|
-
goalContract: body.goalContract || null,
|
|
118
|
-
cwd: typeof body.cwd === 'string' ? body.cwd : null,
|
|
119
|
-
file: typeof body.file === 'string' ? body.file : null,
|
|
120
|
-
sessionId: typeof body.sessionId === 'string' ? body.sessionId : null,
|
|
121
|
-
result: typeof body.result === 'string' ? body.result : null,
|
|
122
|
-
error: typeof body.error === 'string' ? body.error : null,
|
|
123
|
-
outputFiles: Array.isArray(body.outputFiles)
|
|
124
|
-
? body.outputFiles.filter((entry: unknown) => typeof entry === 'string').slice(0, 24)
|
|
125
|
-
: [],
|
|
126
|
-
artifacts: Array.isArray(body.artifacts)
|
|
127
|
-
? body.artifacts
|
|
128
|
-
.filter((artifact: unknown) => artifact && typeof artifact === 'object')
|
|
129
|
-
.map((artifact: unknown) => {
|
|
130
|
-
const row = artifact as {
|
|
131
|
-
url?: unknown
|
|
132
|
-
type?: unknown
|
|
133
|
-
filename?: unknown
|
|
134
|
-
}
|
|
135
|
-
const normalizedType = String(row.type || '')
|
|
136
|
-
return {
|
|
137
|
-
url: String(row.url || ''),
|
|
138
|
-
type: ['image', 'video', 'pdf', 'file'].includes(normalizedType)
|
|
139
|
-
? (normalizedType as 'image' | 'video' | 'pdf' | 'file')
|
|
140
|
-
: 'file',
|
|
141
|
-
filename: String(row.filename || ''),
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
.filter((artifact: { url: string; filename: string }) => artifact.url && artifact.filename)
|
|
145
|
-
.slice(0, 24)
|
|
146
|
-
: [],
|
|
147
|
-
archivedAt: null,
|
|
148
|
-
attempts: 0,
|
|
149
|
-
maxAttempts,
|
|
150
|
-
retryBackoffSec,
|
|
151
|
-
retryScheduledAt: null,
|
|
152
|
-
deadLetteredAt: null,
|
|
153
|
-
checkpoint: null,
|
|
154
|
-
blockedBy: Array.isArray(body.blockedBy) ? body.blockedBy.filter((s: unknown) => typeof s === 'string') : [],
|
|
155
|
-
blocks: Array.isArray(body.blocks) ? body.blocks.filter((s: unknown) => typeof s === 'string') : [],
|
|
156
|
-
tags: Array.isArray(body.tags) ? body.tags.filter((s: unknown) => typeof s === 'string') : [],
|
|
157
|
-
dueAt: typeof body.dueAt === 'number' ? body.dueAt : null,
|
|
158
|
-
customFields: body.customFields && typeof body.customFields === 'object' ? body.customFields : undefined,
|
|
159
|
-
priority: body.priority && ['low', 'medium', 'high', 'critical'].includes(body.priority) ? body.priority : undefined,
|
|
160
|
-
},
|
|
161
|
-
})
|
|
162
|
-
if (!prepared.ok) {
|
|
163
|
-
return NextResponse.json({ error: prepared.error }, { status: 400 })
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (prepared.duplicate) {
|
|
167
|
-
return NextResponse.json({ ...prepared.duplicate, deduplicated: true })
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const task = prepared.task
|
|
171
|
-
if (task.status === 'completed') {
|
|
172
|
-
const agentExtensions = resolvedAgentId ? getEnabledCapabilityIds(loadAgents()[resolvedAgentId]) : []
|
|
173
|
-
getExtensionManager().runHook(
|
|
174
|
-
'onTaskComplete',
|
|
175
|
-
{ taskId: id, result: task.result },
|
|
176
|
-
{ enabledIds: agentExtensions },
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Parent/child hierarchy
|
|
181
|
-
const parentTaskId = typeof body.parentTaskId === 'string' && body.parentTaskId.trim() ? body.parentTaskId.trim() : null
|
|
182
|
-
if (parentTaskId) {
|
|
183
|
-
task.parentTaskId = parentTaskId
|
|
184
|
-
const parentTask = tasks[parentTaskId]
|
|
185
|
-
if (parentTask) {
|
|
186
|
-
const subtaskIds = Array.isArray(parentTask.subtaskIds) ? parentTask.subtaskIds : []
|
|
187
|
-
if (!subtaskIds.includes(id)) {
|
|
188
|
-
parentTask.subtaskIds = [...subtaskIds, id]
|
|
189
|
-
parentTask.updatedAt = now
|
|
190
|
-
upsertTask(parentTaskId, parentTask)
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
upsertTask(id, task)
|
|
196
|
-
const mission = ensureMissionForTask(task, { source: 'manual' })
|
|
197
|
-
const finalTask = enrichTaskWithMissionSummary({
|
|
198
|
-
...task,
|
|
199
|
-
missionId: mission?.id || task.missionId || null,
|
|
200
|
-
})
|
|
201
|
-
logActivity({ entityType: 'task', entityId: id, action: 'created', actor: 'user', summary: `Task created: "${task.title}"` })
|
|
202
|
-
pushMainLoopEventToMainSessions({
|
|
203
|
-
type: 'task_created',
|
|
204
|
-
text: `Task created: "${task.title}" (${id}) with status ${task.status}.`,
|
|
205
|
-
})
|
|
206
|
-
if (task.status === 'queued') {
|
|
207
|
-
enqueueTask(id)
|
|
208
|
-
}
|
|
209
|
-
notify('tasks')
|
|
210
|
-
return NextResponse.json(finalTask)
|
|
47
|
+
const result = createTaskFromRoute({ ...raw, ...parsed.data } as Record<string, unknown>)
|
|
48
|
+
return result.ok
|
|
49
|
+
? NextResponse.json(result.payload)
|
|
50
|
+
: NextResponse.json(result.payload, { status: result.status })
|
|
211
51
|
}
|
|
@@ -2,8 +2,8 @@ import { NextResponse } from 'next/server'
|
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import path from 'path'
|
|
4
4
|
import { genId } from '@/lib/id'
|
|
5
|
-
import { UPLOAD_DIR } from '@/lib/server/storage'
|
|
6
5
|
import { log } from '@/lib/server/logger'
|
|
6
|
+
import { UPLOAD_DIR } from '@/lib/server/upload-path'
|
|
7
7
|
|
|
8
8
|
const TAG = 'api-upload'
|
|
9
9
|
|
|
@@ -2,8 +2,8 @@ import { NextResponse } from 'next/server'
|
|
|
2
2
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
3
|
import fs from 'fs'
|
|
4
4
|
import path from 'path'
|
|
5
|
-
import { UPLOAD_DIR } from '@/lib/server/storage'
|
|
6
5
|
import { MIME_TYPES } from '@/lib/server/mime'
|
|
6
|
+
import { UPLOAD_DIR } from '@/lib/server/upload-path'
|
|
7
7
|
|
|
8
8
|
export async function GET(_req: Request, { params }: { params: Promise<{ filename: string }> }) {
|
|
9
9
|
const { filename } = await params
|
|
@@ -2,8 +2,8 @@ import { NextResponse } from 'next/server'
|
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import path from 'path'
|
|
4
4
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
5
|
-
import { UPLOAD_DIR } from '@/lib/server/storage'
|
|
6
5
|
import { getFileCategory } from '@/lib/server/mime'
|
|
6
|
+
import { UPLOAD_DIR } from '@/lib/server/upload-path'
|
|
7
7
|
|
|
8
8
|
interface UploadFile {
|
|
9
9
|
name: string
|
|
@@ -5,8 +5,8 @@ export async function GET(_req: Request, { params }: { params: Promise<{ id: str
|
|
|
5
5
|
const { id } = await params
|
|
6
6
|
const allLogs = loadWebhookLogs()
|
|
7
7
|
const entries = Object.values(allLogs)
|
|
8
|
-
.filter((entry
|
|
9
|
-
.sort((a
|
|
8
|
+
.filter((entry) => (entry as Record<string, unknown>).webhookId === id)
|
|
9
|
+
.sort((a, b) => ((b as Record<string, unknown>).timestamp as number || 0) - ((a as Record<string, unknown>).timestamp as number || 0))
|
|
10
10
|
.slice(0, 100)
|
|
11
11
|
|
|
12
12
|
return NextResponse.json(entries)
|
package/src/app/layout.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import type { Metadata, Viewport } from "next"
|
|
|
2
2
|
import { TooltipProvider } from "@/components/ui/tooltip"
|
|
3
3
|
import { Toaster } from "@/components/ui/sonner"
|
|
4
4
|
import { DashboardShell } from "@/components/layout/dashboard-shell"
|
|
5
|
+
import { AppQueryProvider } from "@/components/providers/app-query-provider"
|
|
5
6
|
import "./globals.css"
|
|
6
7
|
|
|
7
8
|
export const metadata: Metadata = {
|
|
@@ -28,12 +29,14 @@ export default function RootLayout({
|
|
|
28
29
|
return (
|
|
29
30
|
<html lang="en" className="dark">
|
|
30
31
|
<body className="antialiased" cz-shortcut-listen="true">
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
<AppQueryProvider>
|
|
33
|
+
<TooltipProvider>
|
|
34
|
+
<DashboardShell>
|
|
35
|
+
{children}
|
|
36
|
+
</DashboardShell>
|
|
37
|
+
<Toaster />
|
|
38
|
+
</TooltipProvider>
|
|
39
|
+
</AppQueryProvider>
|
|
37
40
|
</body>
|
|
38
41
|
</html>
|
|
39
42
|
)
|
|
@@ -2,8 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
4
4
|
import { useRouter, useSearchParams } from 'next/navigation'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { useAgentsQuery } from '@/features/agents/queries'
|
|
6
|
+
import { useChatroomsQuery } from '@/features/chatrooms/queries'
|
|
7
|
+
import { useMissionsQuery } from '@/features/missions/queries'
|
|
8
|
+
import {
|
|
9
|
+
useCreateProtocolRunMutation,
|
|
10
|
+
useDeleteProtocolTemplateMutation,
|
|
11
|
+
useProtocolRunActionMutation,
|
|
12
|
+
useProtocolRunDetailQuery,
|
|
13
|
+
useProtocolRunsQuery,
|
|
14
|
+
useProtocolTemplatesQuery,
|
|
15
|
+
useUpsertProtocolTemplateMutation,
|
|
16
|
+
} from '@/features/protocols/queries'
|
|
17
|
+
import { useTasksQuery } from '@/features/tasks/queries'
|
|
7
18
|
import { MainContent } from '@/components/layout/main-content'
|
|
8
19
|
import { StructuredSessionLauncher } from '@/components/protocols/structured-session-launcher'
|
|
9
20
|
import { timeAgo } from '@/lib/time-format'
|
|
@@ -67,10 +78,6 @@ const DEFAULT_TEMPLATE_DRAFT: TemplateDraft = {
|
|
|
67
78
|
entryStepId: 'present',
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
async function postRunAction(runId: string, payload: RunActionPayload) {
|
|
71
|
-
await api('POST', `/protocols/runs/${runId}/actions`, payload)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
81
|
function toTemplateDraft(template: ProtocolTemplate | null): TemplateDraft {
|
|
75
82
|
if (!template) return DEFAULT_TEMPLATE_DRAFT
|
|
76
83
|
return {
|
|
@@ -125,16 +132,7 @@ function splitCsv(value: string): string[] {
|
|
|
125
132
|
export default function ProtocolsPage() {
|
|
126
133
|
const router = useRouter()
|
|
127
134
|
const searchParams = useSearchParams()
|
|
128
|
-
const [templates, setTemplates] = useState<ProtocolTemplate[]>([])
|
|
129
|
-
const [runs, setRuns] = useState<ProtocolRun[]>([])
|
|
130
|
-
const [detail, setDetail] = useState<ProtocolRunDetail | null>(null)
|
|
131
135
|
const [selectedRunId, setSelectedRunId] = useState<string | null>(null)
|
|
132
|
-
const [agents, setAgents] = useState<AgentList>({})
|
|
133
|
-
const [chatrooms, setChatrooms] = useState<Record<string, Chatroom>>({})
|
|
134
|
-
const [missions, setMissions] = useState<Mission[]>([])
|
|
135
|
-
const [tasks, setTasks] = useState<Record<string, BoardTask>>({})
|
|
136
|
-
const [loading, setLoading] = useState(true)
|
|
137
|
-
const [detailLoading, setDetailLoading] = useState(false)
|
|
138
136
|
const [actionPending, setActionPending] = useState<string | null>(null)
|
|
139
137
|
const [templatePending, setTemplatePending] = useState<string | null>(null)
|
|
140
138
|
const [templateEditorOpen, setTemplateEditorOpen] = useState(false)
|
|
@@ -160,66 +158,55 @@ export default function ProtocolsPage() {
|
|
|
160
158
|
autoStart: true,
|
|
161
159
|
})
|
|
162
160
|
const requestedRunId = searchParams.get('runId')
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
161
|
+
const templatesQuery = useProtocolTemplatesQuery()
|
|
162
|
+
const runsQuery = useProtocolRunsQuery({ limit: 120 })
|
|
163
|
+
const agentsQuery = useAgentsQuery()
|
|
164
|
+
const chatroomsQuery = useChatroomsQuery()
|
|
165
|
+
const missionsQuery = useMissionsQuery({ limit: 80 })
|
|
166
|
+
const tasksQuery = useTasksQuery({ includeArchived: true })
|
|
167
|
+
const detailQuery = useProtocolRunDetailQuery(selectedRunId, { enabled: Boolean(selectedRunId) })
|
|
168
|
+
const createRunMutation = useCreateProtocolRunMutation()
|
|
169
|
+
const runActionMutation = useProtocolRunActionMutation()
|
|
170
|
+
const upsertTemplateMutation = useUpsertProtocolTemplateMutation()
|
|
171
|
+
const deleteTemplateMutation = useDeleteProtocolTemplateMutation()
|
|
172
|
+
const templates = templatesQuery.data ?? []
|
|
173
|
+
const runs = runsQuery.data ?? []
|
|
174
|
+
const detail = detailQuery.data ?? null
|
|
175
|
+
const agents = agentsQuery.data ?? {}
|
|
176
|
+
const chatrooms = chatroomsQuery.data ?? {}
|
|
177
|
+
const missions = missionsQuery.data ?? []
|
|
178
|
+
const tasks = tasksQuery.data ?? {}
|
|
179
|
+
const loading = (
|
|
180
|
+
templatesQuery.isLoading
|
|
181
|
+
|| runsQuery.isLoading
|
|
182
|
+
|| agentsQuery.isLoading
|
|
183
|
+
|| chatroomsQuery.isLoading
|
|
184
|
+
|| missionsQuery.isLoading
|
|
185
|
+
|| tasksQuery.isLoading
|
|
186
|
+
)
|
|
187
|
+
const detailLoading = detailQuery.isLoading || detailQuery.isFetching
|
|
188
|
+
const queryError = [
|
|
189
|
+
templatesQuery.error,
|
|
190
|
+
runsQuery.error,
|
|
191
|
+
agentsQuery.error,
|
|
192
|
+
chatroomsQuery.error,
|
|
193
|
+
missionsQuery.error,
|
|
194
|
+
tasksQuery.error,
|
|
195
|
+
detailQuery.error,
|
|
196
|
+
].find(Boolean)
|
|
197
|
+
const resolvedError = error || (queryError instanceof Error ? queryError.message : null)
|
|
186
198
|
|
|
187
199
|
// Apply URL-requested run selection separately so WS refreshes don't snap back
|
|
188
200
|
useEffect(() => {
|
|
189
201
|
if (requestedRunId) setSelectedRunId(requestedRunId)
|
|
190
202
|
}, [requestedRunId])
|
|
191
203
|
|
|
192
|
-
const loadDetail = useCallback(async (runId: string | null) => {
|
|
193
|
-
if (!runId) {
|
|
194
|
-
setDetail(null)
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
setDetailLoading(true)
|
|
198
|
-
try {
|
|
199
|
-
const value = await api<ProtocolRunDetail>('GET', `/protocols/runs/${runId}`)
|
|
200
|
-
setDetail(value)
|
|
201
|
-
setError(null)
|
|
202
|
-
} catch (err) {
|
|
203
|
-
setError(err instanceof Error ? err.message : 'Unable to load structured session.')
|
|
204
|
-
setDetail(null)
|
|
205
|
-
} finally {
|
|
206
|
-
setDetailLoading(false)
|
|
207
|
-
}
|
|
208
|
-
}, [])
|
|
209
|
-
|
|
210
204
|
useEffect(() => {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
205
|
+
setSelectedRunId((current) => {
|
|
206
|
+
if (current && runs.some((run) => run.id === current)) return current
|
|
207
|
+
return runs[0]?.id || null
|
|
214
208
|
})
|
|
215
|
-
}, [
|
|
216
|
-
|
|
217
|
-
useEffect(() => {
|
|
218
|
-
void loadDetail(selectedRunId)
|
|
219
|
-
}, [loadDetail, selectedRunId])
|
|
220
|
-
|
|
221
|
-
useWs('protocol_runs', loadRuns, 2000)
|
|
222
|
-
useWs('protocol_templates', loadRuns, 2000)
|
|
209
|
+
}, [runs])
|
|
223
210
|
|
|
224
211
|
const selectedTemplate = useMemo(() => templates.find((template) => template.id === form.templateId) || null, [form.templateId, templates])
|
|
225
212
|
const customTemplates = useMemo(() => templates.filter((template) => !template.builtIn), [templates])
|
|
@@ -244,7 +231,7 @@ export default function ProtocolsPage() {
|
|
|
244
231
|
return
|
|
245
232
|
}
|
|
246
233
|
try {
|
|
247
|
-
const run = await
|
|
234
|
+
const run = await createRunMutation.mutateAsync({
|
|
248
235
|
title: form.title.trim(),
|
|
249
236
|
templateId: form.templateId,
|
|
250
237
|
participantAgentIds: form.participantAgentIds,
|
|
@@ -269,37 +256,34 @@ export default function ProtocolsPage() {
|
|
|
269
256
|
decisionMode: '',
|
|
270
257
|
}))
|
|
271
258
|
setSelectedRunId(run.id)
|
|
272
|
-
await loadRuns()
|
|
273
259
|
} catch (err) {
|
|
274
260
|
setError(err instanceof Error ? err.message : 'Unable to create structured session.')
|
|
275
261
|
}
|
|
276
|
-
}, [
|
|
262
|
+
}, [createRunMutation, form])
|
|
277
263
|
|
|
278
264
|
const handleAction = useCallback(async (payload: RunActionPayload) => {
|
|
279
265
|
if (!detail?.run.id) return
|
|
280
266
|
setActionPending(payload.action)
|
|
281
267
|
try {
|
|
282
|
-
await
|
|
283
|
-
await Promise.all([loadRuns(), loadDetail(detail.run.id)])
|
|
268
|
+
await runActionMutation.mutateAsync({ runId: detail.run.id, payload })
|
|
284
269
|
if (payload.action === 'inject_context') setContextDraft('')
|
|
285
270
|
} catch (err) {
|
|
286
271
|
setError(err instanceof Error ? err.message : 'Unable to update structured session.')
|
|
287
272
|
} finally {
|
|
288
273
|
setActionPending(null)
|
|
289
274
|
}
|
|
290
|
-
}, [detail,
|
|
275
|
+
}, [detail, runActionMutation])
|
|
291
276
|
|
|
292
277
|
const handleBranchAction = useCallback(async (runId: string, payload: RunActionPayload) => {
|
|
293
278
|
setActionPending(`${payload.action}:${runId}`)
|
|
294
279
|
try {
|
|
295
|
-
await
|
|
296
|
-
await Promise.all([loadRuns(), detail?.run.id ? loadDetail(detail.run.id) : Promise.resolve()])
|
|
280
|
+
await runActionMutation.mutateAsync({ runId, payload })
|
|
297
281
|
} catch (err) {
|
|
298
282
|
setError(err instanceof Error ? err.message : 'Unable to update branch run.')
|
|
299
283
|
} finally {
|
|
300
284
|
setActionPending(null)
|
|
301
285
|
}
|
|
302
|
-
}, [
|
|
286
|
+
}, [runActionMutation])
|
|
303
287
|
|
|
304
288
|
const openTemplateEditor = useCallback((template: ProtocolTemplate | null = null) => {
|
|
305
289
|
setEditingTemplateId(template?.builtIn ? null : template?.id || null)
|
|
@@ -328,27 +312,27 @@ export default function ProtocolsPage() {
|
|
|
328
312
|
return
|
|
329
313
|
}
|
|
330
314
|
setTemplatePending(editingTemplateId ? 'save-edit' : 'save-new')
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
315
|
+
const created = await upsertTemplateMutation.mutateAsync({
|
|
316
|
+
templateId: editingTemplateId,
|
|
317
|
+
payload,
|
|
318
|
+
})
|
|
319
|
+
if (!editingTemplateId) {
|
|
335
320
|
setForm((current) => ({ ...current, templateId: created.id }))
|
|
336
321
|
}
|
|
337
322
|
setTemplateEditorOpen(false)
|
|
338
323
|
setEditingTemplateId(null)
|
|
339
324
|
setTemplateDraft(DEFAULT_TEMPLATE_DRAFT)
|
|
340
|
-
await loadRuns()
|
|
341
325
|
} catch (err) {
|
|
342
326
|
setError(err instanceof Error ? err.message : 'Unable to save structured-session template.')
|
|
343
327
|
} finally {
|
|
344
328
|
setTemplatePending(null)
|
|
345
329
|
}
|
|
346
|
-
}, [editingTemplateId,
|
|
330
|
+
}, [editingTemplateId, templateDraft, upsertTemplateMutation])
|
|
347
331
|
|
|
348
332
|
const handleDeleteTemplate = useCallback(async (templateId: string) => {
|
|
349
333
|
setTemplatePending(`delete:${templateId}`)
|
|
350
334
|
try {
|
|
351
|
-
await
|
|
335
|
+
await deleteTemplateMutation.mutateAsync(templateId)
|
|
352
336
|
setTemplateEditorOpen(false)
|
|
353
337
|
setEditingTemplateId(null)
|
|
354
338
|
setTemplateDraft(DEFAULT_TEMPLATE_DRAFT)
|
|
@@ -356,13 +340,12 @@ export default function ProtocolsPage() {
|
|
|
356
340
|
...current,
|
|
357
341
|
templateId: current.templateId === templateId ? 'facilitated_discussion' : current.templateId,
|
|
358
342
|
}))
|
|
359
|
-
await loadRuns()
|
|
360
343
|
} catch (err) {
|
|
361
344
|
setError(err instanceof Error ? err.message : 'Unable to delete structured-session template.')
|
|
362
345
|
} finally {
|
|
363
346
|
setTemplatePending(null)
|
|
364
347
|
}
|
|
365
|
-
}, [
|
|
348
|
+
}, [deleteTemplateMutation])
|
|
366
349
|
|
|
367
350
|
const handleSelectRun = useCallback((runId: string) => {
|
|
368
351
|
setSelectedRunId(runId)
|
|
@@ -715,9 +698,9 @@ export default function ProtocolsPage() {
|
|
|
715
698
|
)}
|
|
716
699
|
</div>
|
|
717
700
|
</div>
|
|
718
|
-
{
|
|
701
|
+
{resolvedError && (
|
|
719
702
|
<div className="mt-4 rounded-[14px] border border-red-500/20 bg-red-500/10 px-4 py-3 text-[13px] text-red-200">
|
|
720
|
-
{
|
|
703
|
+
{resolvedError}
|
|
721
704
|
</div>
|
|
722
705
|
)}
|
|
723
706
|
</section>
|
|
@@ -1272,9 +1255,8 @@ export default function ProtocolsPage() {
|
|
|
1272
1255
|
open={launcherOpen}
|
|
1273
1256
|
onClose={() => setLauncherOpen(false)}
|
|
1274
1257
|
onCreated={(run) => {
|
|
1258
|
+
setLauncherOpen(false)
|
|
1275
1259
|
setSelectedRunId(run.id)
|
|
1276
|
-
void loadRuns()
|
|
1277
|
-
void loadDetail(run.id)
|
|
1278
1260
|
router.push(`/protocols?runId=${encodeURIComponent(run.id)}`)
|
|
1279
1261
|
}}
|
|
1280
1262
|
allowContextSelection
|