@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,28 +1,10 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
2
|
+
import { retryChatTurn } from '@/lib/server/chats/chat-session-service'
|
|
3
3
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
4
|
|
|
5
5
|
export async function POST(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
6
|
const { id } = await params
|
|
7
|
-
const
|
|
8
|
-
if (!
|
|
9
|
-
|
|
10
|
-
const msgs = session.messages
|
|
11
|
-
// Pop trailing assistant messages to find the last user message
|
|
12
|
-
while (msgs.length && msgs[msgs.length - 1].role === 'assistant') {
|
|
13
|
-
msgs.pop()
|
|
14
|
-
}
|
|
15
|
-
if (!msgs.length) {
|
|
16
|
-
return NextResponse.json({ message: '', imagePath: null }, { status: 200 })
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const lastUser = msgs[msgs.length - 1]
|
|
20
|
-
const message = lastUser.text
|
|
21
|
-
const imagePath = lastUser.imagePath || null
|
|
22
|
-
|
|
23
|
-
// Remove the last user message too — it will be re-sent by the client
|
|
24
|
-
msgs.pop()
|
|
25
|
-
upsertSession(id, session)
|
|
26
|
-
|
|
27
|
-
return NextResponse.json({ message, imagePath })
|
|
7
|
+
const result = retryChatTurn(id)
|
|
8
|
+
if (!result.ok) return notFound()
|
|
9
|
+
return NextResponse.json(result.payload)
|
|
28
10
|
}
|
|
@@ -1,158 +1,30 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import { loadAgents } from '@/lib/server/storage'
|
|
3
2
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import { stopActiveSessionProcess } from '@/lib/server/runtime/runtime-state'
|
|
10
|
-
import { getSessionQueueSnapshot, getSessionRunState } from '@/lib/server/runtime/session-run-manager'
|
|
11
|
-
import { normalizeCapabilitySelection } from '@/lib/capability-selection'
|
|
12
|
-
import { enrichSessionWithMissionSummary } from '@/lib/server/missions/mission-service'
|
|
3
|
+
import {
|
|
4
|
+
deleteChatSession,
|
|
5
|
+
getChatSessionForApi,
|
|
6
|
+
updateChatSession,
|
|
7
|
+
} from '@/lib/server/chats/chat-session-service'
|
|
13
8
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
14
9
|
|
|
15
10
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
16
11
|
const { id } = await params
|
|
17
|
-
const session =
|
|
12
|
+
const session = getChatSessionForApi(id)
|
|
18
13
|
if (!session) return notFound()
|
|
19
|
-
|
|
20
|
-
const run = getSessionRunState(id)
|
|
21
|
-
const queue = getSessionQueueSnapshot(id)
|
|
22
|
-
session.active = !!run.runningRunId
|
|
23
|
-
session.queuedCount = queue.queueLength
|
|
24
|
-
session.currentRunId = run.runningRunId || null
|
|
25
|
-
|
|
26
|
-
return NextResponse.json(enrichSessionWithMissionSummary(session))
|
|
14
|
+
return NextResponse.json(session)
|
|
27
15
|
}
|
|
28
16
|
|
|
29
17
|
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
30
18
|
const { id } = await params
|
|
31
19
|
const { data: updates, error } = await safeParseBody(req)
|
|
32
20
|
if (error) return error
|
|
33
|
-
const session =
|
|
21
|
+
const session = updateChatSession(id, updates as Record<string, unknown>)
|
|
34
22
|
if (!session) return notFound()
|
|
35
|
-
|
|
36
|
-
if (updates.resetMainLoopState === true) {
|
|
37
|
-
clearMainLoopStateForSession(id)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const agentIdUpdateProvided = updates.agentId !== undefined
|
|
41
|
-
let nextAgentId = session.agentId
|
|
42
|
-
if (agentIdUpdateProvided) {
|
|
43
|
-
session.agentId = updates.agentId
|
|
44
|
-
nextAgentId = updates.agentId
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const linkedAgent = nextAgentId ? loadAgents()[nextAgentId as string] : null
|
|
48
|
-
const routePreferredGatewayTags = updates.routePreferredGatewayTags !== undefined
|
|
49
|
-
? (Array.isArray(updates.routePreferredGatewayTags)
|
|
50
|
-
? updates.routePreferredGatewayTags.filter((tag: unknown): tag is string => typeof tag === 'string' && tag.trim().length > 0)
|
|
51
|
-
: [])
|
|
52
|
-
: ((session.routePreferredGatewayTags as string[]) || [])
|
|
53
|
-
const routePreferredGatewayUseCase = updates.routePreferredGatewayUseCase !== undefined
|
|
54
|
-
? (typeof updates.routePreferredGatewayUseCase === 'string' && updates.routePreferredGatewayUseCase.trim()
|
|
55
|
-
? updates.routePreferredGatewayUseCase.trim()
|
|
56
|
-
: null)
|
|
57
|
-
: ((session.routePreferredGatewayUseCase as string | null) || null)
|
|
58
|
-
const linkedRoute = linkedAgent ? resolvePrimaryAgentRoute(linkedAgent, undefined, {
|
|
59
|
-
preferredGatewayTags: routePreferredGatewayTags,
|
|
60
|
-
preferredGatewayUseCase: routePreferredGatewayUseCase,
|
|
61
|
-
}) : null
|
|
62
|
-
|
|
63
|
-
if (updates.name !== undefined) session.name = updates.name
|
|
64
|
-
if (updates.cwd !== undefined) session.cwd = updates.cwd
|
|
65
|
-
if (updates.provider !== undefined) session.provider = updates.provider
|
|
66
|
-
else if (agentIdUpdateProvided && linkedAgent?.provider) session.provider = linkedAgent.provider
|
|
67
|
-
|
|
68
|
-
if (updates.model !== undefined) session.model = updates.model
|
|
69
|
-
else if (agentIdUpdateProvided && linkedRoute?.model) session.model = linkedRoute.model
|
|
70
|
-
else if (agentIdUpdateProvided && linkedAgent?.model !== undefined) session.model = linkedAgent.model
|
|
71
|
-
|
|
72
|
-
if (updates.ollamaMode !== undefined) session.ollamaMode = updates.ollamaMode
|
|
73
|
-
else if (updates.provider !== undefined && updates.provider !== 'ollama') session.ollamaMode = null
|
|
74
|
-
else if (agentIdUpdateProvided && linkedRoute) session.ollamaMode = linkedRoute.ollamaMode ?? null
|
|
75
|
-
else if (agentIdUpdateProvided && linkedAgent) session.ollamaMode = linkedAgent.ollamaMode ?? null
|
|
76
|
-
|
|
77
|
-
if (updates.credentialId !== undefined) session.credentialId = updates.credentialId
|
|
78
|
-
else if (agentIdUpdateProvided && linkedRoute) session.credentialId = linkedRoute.credentialId ?? null
|
|
79
|
-
else if (agentIdUpdateProvided && linkedAgent) session.credentialId = linkedAgent.credentialId ?? null
|
|
80
|
-
|
|
81
|
-
if (updates.fallbackCredentialIds !== undefined) session.fallbackCredentialIds = updates.fallbackCredentialIds
|
|
82
|
-
else if (agentIdUpdateProvided && linkedRoute) session.fallbackCredentialIds = [...linkedRoute.fallbackCredentialIds]
|
|
83
|
-
|
|
84
|
-
if (updates.gatewayProfileId !== undefined) session.gatewayProfileId = updates.gatewayProfileId
|
|
85
|
-
else if (agentIdUpdateProvided && linkedRoute) session.gatewayProfileId = linkedRoute.gatewayProfileId ?? null
|
|
86
|
-
|
|
87
|
-
if (updates.routePreferredGatewayTags !== undefined) {
|
|
88
|
-
session.routePreferredGatewayTags = routePreferredGatewayTags
|
|
89
|
-
}
|
|
90
|
-
if (updates.routePreferredGatewayUseCase !== undefined) {
|
|
91
|
-
session.routePreferredGatewayUseCase = routePreferredGatewayUseCase
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (updates.tools !== undefined || updates.extensions !== undefined || (agentIdUpdateProvided && linkedAgent)) {
|
|
95
|
-
const nextSelection = normalizeCapabilitySelection({
|
|
96
|
-
tools: Array.isArray(updates.tools)
|
|
97
|
-
? updates.tools
|
|
98
|
-
: (agentIdUpdateProvided && linkedAgent ? linkedAgent.tools : session.tools as string[] | undefined),
|
|
99
|
-
extensions: Array.isArray(updates.extensions)
|
|
100
|
-
? updates.extensions
|
|
101
|
-
: (agentIdUpdateProvided && linkedAgent ? linkedAgent.extensions : session.extensions as string[] | undefined),
|
|
102
|
-
})
|
|
103
|
-
session.tools = nextSelection.tools
|
|
104
|
-
session.extensions = nextSelection.extensions
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (updates.apiEndpoint !== undefined) {
|
|
108
|
-
session.apiEndpoint = normalizeProviderEndpoint(
|
|
109
|
-
(updates.provider || session.provider) as string,
|
|
110
|
-
updates.apiEndpoint as string | null | undefined,
|
|
111
|
-
)
|
|
112
|
-
} else if (agentIdUpdateProvided && linkedRoute) {
|
|
113
|
-
session.apiEndpoint = linkedRoute.apiEndpoint ?? null
|
|
114
|
-
} else if (agentIdUpdateProvided && linkedAgent) {
|
|
115
|
-
session.apiEndpoint = normalizeProviderEndpoint(
|
|
116
|
-
linkedAgent.provider,
|
|
117
|
-
linkedAgent.apiEndpoint ?? null,
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
if (updates.heartbeatEnabled !== undefined) session.heartbeatEnabled = updates.heartbeatEnabled
|
|
121
|
-
if (updates.heartbeatIntervalSec !== undefined) session.heartbeatIntervalSec = updates.heartbeatIntervalSec
|
|
122
|
-
if (updates.sessionResetMode !== undefined) session.sessionResetMode = updates.sessionResetMode
|
|
123
|
-
if (updates.sessionIdleTimeoutSec !== undefined) session.sessionIdleTimeoutSec = updates.sessionIdleTimeoutSec
|
|
124
|
-
if (updates.sessionMaxAgeSec !== undefined) session.sessionMaxAgeSec = updates.sessionMaxAgeSec
|
|
125
|
-
if (updates.sessionDailyResetAt !== undefined) session.sessionDailyResetAt = updates.sessionDailyResetAt
|
|
126
|
-
if (updates.sessionResetTimezone !== undefined) session.sessionResetTimezone = updates.sessionResetTimezone
|
|
127
|
-
if (updates.thinkingLevel !== undefined) session.thinkingLevel = updates.thinkingLevel
|
|
128
|
-
if (updates.connectorThinkLevel !== undefined) session.connectorThinkLevel = updates.connectorThinkLevel
|
|
129
|
-
if (updates.connectorSessionScope !== undefined) session.connectorSessionScope = updates.connectorSessionScope
|
|
130
|
-
if (updates.connectorReplyMode !== undefined) session.connectorReplyMode = updates.connectorReplyMode
|
|
131
|
-
if (updates.connectorThreadBinding !== undefined) session.connectorThreadBinding = updates.connectorThreadBinding
|
|
132
|
-
if (updates.connectorGroupPolicy !== undefined) session.connectorGroupPolicy = updates.connectorGroupPolicy
|
|
133
|
-
if (updates.connectorIdleTimeoutSec !== undefined) session.connectorIdleTimeoutSec = updates.connectorIdleTimeoutSec
|
|
134
|
-
if (updates.connectorMaxAgeSec !== undefined) session.connectorMaxAgeSec = updates.connectorMaxAgeSec
|
|
135
|
-
if (updates.connectorContext !== undefined) session.connectorContext = updates.connectorContext
|
|
136
|
-
if (updates.identityState !== undefined) session.identityState = updates.identityState
|
|
137
|
-
if (updates.sessionArchiveState !== undefined) session.sessionArchiveState = updates.sessionArchiveState
|
|
138
|
-
if (updates.lastSessionResetAt !== undefined) session.lastSessionResetAt = updates.lastSessionResetAt
|
|
139
|
-
if (updates.lastSessionResetReason !== undefined) session.lastSessionResetReason = updates.lastSessionResetReason
|
|
140
|
-
if (updates.pinned !== undefined) session.pinned = !!updates.pinned
|
|
141
|
-
if (updates.claudeSessionId !== undefined) session.claudeSessionId = updates.claudeSessionId
|
|
142
|
-
if (updates.codexThreadId !== undefined) session.codexThreadId = updates.codexThreadId
|
|
143
|
-
if (updates.opencodeSessionId !== undefined) session.opencodeSessionId = updates.opencodeSessionId
|
|
144
|
-
if (updates.delegateResumeIds !== undefined) session.delegateResumeIds = updates.delegateResumeIds
|
|
145
|
-
if (!Array.isArray(session.messages)) session.messages = []
|
|
146
|
-
|
|
147
|
-
saveSession(id, session)
|
|
148
|
-
return NextResponse.json(enrichSessionWithMissionSummary(session as never))
|
|
23
|
+
return NextResponse.json(session)
|
|
149
24
|
}
|
|
150
25
|
|
|
151
26
|
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
152
27
|
const { id } = await params
|
|
153
|
-
if (!
|
|
154
|
-
stopActiveSessionProcess(id)
|
|
155
|
-
cleanupSessionProcesses(id)
|
|
156
|
-
deleteSession(id)
|
|
28
|
+
if (!deleteChatSession(id)) return notFound()
|
|
157
29
|
return new NextResponse('OK')
|
|
158
30
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { DEFAULT_HEARTBEAT_INTERVAL_SEC } from '@/lib/runtime/heartbeat-defaults'
|
|
3
|
-
import { disableAllSessionHeartbeats, loadSettings, saveSettings } from '@/lib/server/storage'
|
|
4
3
|
import { cancelAllHeartbeatRuns } from '@/lib/server/runtime/session-run-manager'
|
|
4
|
+
import { disableAllSessionHeartbeats } from '@/lib/server/sessions/session-repository'
|
|
5
|
+
import { loadSettings, saveSettings } from '@/lib/server/settings/settings-repository'
|
|
5
6
|
|
|
6
7
|
export async function POST(req: Request) {
|
|
7
8
|
const body = await req.json().catch(() => ({}))
|
|
@@ -1,44 +1,17 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import { genId } from '@/lib/id'
|
|
3
|
-
import os from 'os'
|
|
4
|
-
import path from 'path'
|
|
5
2
|
import { perf } from '@/lib/server/runtime/perf'
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import { normalizeProviderEndpoint } from '@/lib/openclaw/openclaw-endpoint'
|
|
13
|
-
import { applyResolvedRoute, resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
|
|
14
|
-
import { buildAgentDisabledMessage, isAgentDisabled } from '@/lib/server/agents/agent-availability'
|
|
15
|
-
import { buildSessionListSummary } from '@/lib/chat/session-summary'
|
|
16
|
-
import { normalizeCapabilitySelection } from '@/lib/capability-selection'
|
|
17
|
-
import { enrichSessionWithMissionSummary } from '@/lib/server/missions/mission-service'
|
|
3
|
+
import {
|
|
4
|
+
createChatSession,
|
|
5
|
+
deleteChats,
|
|
6
|
+
listChatsForApi,
|
|
7
|
+
} from '@/lib/server/chats/chat-session-service'
|
|
8
|
+
import { ensureDaemonProcessRunning } from '@/lib/server/daemon/controller'
|
|
18
9
|
export const dynamic = 'force-dynamic'
|
|
19
10
|
|
|
20
|
-
async function ensureDaemonIfNeeded(source: string) {
|
|
21
|
-
const { ensureDaemonStarted } = await import('@/lib/server/runtime/daemon-state')
|
|
22
|
-
ensureDaemonStarted(source)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
11
|
|
|
26
12
|
export async function GET(req: Request) {
|
|
27
13
|
const endPerf = perf.start('api', 'GET /api/chats')
|
|
28
|
-
|
|
29
|
-
// are handled by the daemon periodic health check, not on every list fetch.
|
|
30
|
-
const sessions = listSessions()
|
|
31
|
-
for (const id of Object.keys(sessions)) {
|
|
32
|
-
const run = getSessionRunState(id)
|
|
33
|
-
const queue = getSessionQueueSnapshot(id)
|
|
34
|
-
sessions[id].active = !!run.runningRunId
|
|
35
|
-
sessions[id].queuedCount = queue.queueLength
|
|
36
|
-
sessions[id].currentRunId = run.runningRunId || null
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const summarized = Object.fromEntries(
|
|
40
|
-
Object.entries(sessions).map(([id, session]) => [id, buildSessionListSummary(enrichSessionWithMissionSummary(session))]),
|
|
41
|
-
)
|
|
14
|
+
const summarized = listChatsForApi()
|
|
42
15
|
|
|
43
16
|
const { searchParams } = new URL(req.url)
|
|
44
17
|
const limitParam = searchParams.get('limit')
|
|
@@ -56,112 +29,18 @@ export async function GET(req: Request) {
|
|
|
56
29
|
}
|
|
57
30
|
|
|
58
31
|
export async function DELETE(req: Request) {
|
|
59
|
-
await
|
|
32
|
+
await ensureDaemonProcessRunning('api/chats:delete')
|
|
60
33
|
const { ids } = await req.json().catch(() => ({ ids: [] })) as { ids: string[] }
|
|
61
34
|
if (!Array.isArray(ids) || !ids.length) {
|
|
62
35
|
return new NextResponse('Missing ids', { status: 400 })
|
|
63
36
|
}
|
|
64
|
-
|
|
65
|
-
let deleted = 0
|
|
66
|
-
for (const id of ids) {
|
|
67
|
-
if (!sessions[id]) continue
|
|
68
|
-
stopActiveSessionProcess(id)
|
|
69
|
-
deleteSession(id)
|
|
70
|
-
deleted += 1
|
|
71
|
-
}
|
|
72
|
-
notify('sessions')
|
|
73
|
-
return NextResponse.json({ deleted, requested: ids.length })
|
|
37
|
+
return NextResponse.json(deleteChats(ids))
|
|
74
38
|
}
|
|
75
39
|
|
|
76
40
|
export async function POST(req: Request) {
|
|
77
|
-
await
|
|
41
|
+
await ensureDaemonProcessRunning('api/chats:post')
|
|
78
42
|
const body = await req.json().catch(() => ({}))
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
else if (!cwd) cwd = WORKSPACE_DIR
|
|
83
|
-
|
|
84
|
-
const id = body.id || genId()
|
|
85
|
-
const sessions = listSessions()
|
|
86
|
-
const agent = body.agentId ? loadAgents()[body.agentId] : null
|
|
87
|
-
if (isAgentDisabled(agent)) {
|
|
88
|
-
return NextResponse.json({ error: buildAgentDisabledMessage(agent, 'start chats') }, { status: 409 })
|
|
89
|
-
}
|
|
90
|
-
const routePreferredGatewayTags = Array.isArray(body.routePreferredGatewayTags)
|
|
91
|
-
? body.routePreferredGatewayTags.filter((tag: unknown): tag is string => typeof tag === 'string' && tag.trim().length > 0)
|
|
92
|
-
: []
|
|
93
|
-
const routePreferredGatewayUseCase = typeof body.routePreferredGatewayUseCase === 'string' && body.routePreferredGatewayUseCase.trim()
|
|
94
|
-
? body.routePreferredGatewayUseCase.trim()
|
|
95
|
-
: null
|
|
96
|
-
const resolvedRoute = agent ? resolvePrimaryAgentRoute(agent, undefined, {
|
|
97
|
-
preferredGatewayTags: routePreferredGatewayTags,
|
|
98
|
-
preferredGatewayUseCase: routePreferredGatewayUseCase,
|
|
99
|
-
}) : null
|
|
100
|
-
const resolvedCapabilities = normalizeCapabilitySelection({
|
|
101
|
-
tools: Array.isArray(body.tools) ? body.tools : agent?.tools,
|
|
102
|
-
extensions: Array.isArray(body.extensions) ? body.extensions : agent?.extensions,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
// If session with this ID already exists, return it as-is
|
|
106
|
-
if (body.id && sessions[id]) {
|
|
107
|
-
return NextResponse.json(sessions[id])
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const sessionName = body.name || 'New Chat'
|
|
111
|
-
|
|
112
|
-
const nextSession = {
|
|
113
|
-
id, name: sessionName, cwd,
|
|
114
|
-
user: body.user || 'user',
|
|
115
|
-
provider: body.provider || agent?.provider || 'claude-cli',
|
|
116
|
-
model: body.model || agent?.model || '',
|
|
117
|
-
ollamaMode: body.ollamaMode ?? agent?.ollamaMode ?? ((body.provider || agent?.provider) === 'ollama' ? 'local' : null),
|
|
118
|
-
credentialId: body.credentialId || agent?.credentialId || null,
|
|
119
|
-
fallbackCredentialIds: body.fallbackCredentialIds || agent?.fallbackCredentialIds || [],
|
|
120
|
-
apiEndpoint: normalizeProviderEndpoint(
|
|
121
|
-
body.provider || agent?.provider || 'claude-cli',
|
|
122
|
-
body.apiEndpoint || agent?.apiEndpoint || null,
|
|
123
|
-
),
|
|
124
|
-
routePreferredGatewayTags,
|
|
125
|
-
routePreferredGatewayUseCase,
|
|
126
|
-
claudeSessionId: null,
|
|
127
|
-
codexThreadId: null,
|
|
128
|
-
opencodeSessionId: null,
|
|
129
|
-
delegateResumeIds: {
|
|
130
|
-
claudeCode: null,
|
|
131
|
-
codex: null,
|
|
132
|
-
opencode: null,
|
|
133
|
-
gemini: null,
|
|
134
|
-
},
|
|
135
|
-
messages: Array.isArray(body.messages) ? body.messages : [],
|
|
136
|
-
createdAt: Date.now(), lastActiveAt: Date.now(),
|
|
137
|
-
sessionType: body.sessionType || 'human',
|
|
138
|
-
agentId: body.agentId || null,
|
|
139
|
-
parentSessionId: body.parentSessionId || null,
|
|
140
|
-
tools: resolvedCapabilities.tools,
|
|
141
|
-
extensions: resolvedCapabilities.extensions,
|
|
142
|
-
heartbeatEnabled: body.heartbeatEnabled ?? null,
|
|
143
|
-
heartbeatIntervalSec: body.heartbeatIntervalSec ?? null,
|
|
144
|
-
sessionResetMode: body.sessionResetMode ?? agent?.sessionResetMode ?? null,
|
|
145
|
-
sessionIdleTimeoutSec: body.sessionIdleTimeoutSec ?? agent?.sessionIdleTimeoutSec ?? null,
|
|
146
|
-
sessionMaxAgeSec: body.sessionMaxAgeSec ?? agent?.sessionMaxAgeSec ?? null,
|
|
147
|
-
sessionDailyResetAt: body.sessionDailyResetAt ?? agent?.sessionDailyResetAt ?? null,
|
|
148
|
-
sessionResetTimezone: body.sessionResetTimezone ?? agent?.sessionResetTimezone ?? null,
|
|
149
|
-
thinkingLevel: body.thinkingLevel ?? null,
|
|
150
|
-
connectorThinkLevel: body.connectorThinkLevel ?? null,
|
|
151
|
-
connectorSessionScope: body.connectorSessionScope ?? null,
|
|
152
|
-
connectorReplyMode: body.connectorReplyMode ?? null,
|
|
153
|
-
connectorThreadBinding: body.connectorThreadBinding ?? null,
|
|
154
|
-
connectorGroupPolicy: body.connectorGroupPolicy ?? null,
|
|
155
|
-
connectorIdleTimeoutSec: body.connectorIdleTimeoutSec ?? null,
|
|
156
|
-
connectorMaxAgeSec: body.connectorMaxAgeSec ?? null,
|
|
157
|
-
connectorContext: body.connectorContext ?? null,
|
|
158
|
-
identityState: body.identityState ?? agent?.identityState ?? null,
|
|
159
|
-
sessionArchiveState: body.sessionArchiveState ?? null,
|
|
160
|
-
}
|
|
161
|
-
sessions[id] = (body.provider || body.model || body.credentialId || body.apiEndpoint)
|
|
162
|
-
? nextSession
|
|
163
|
-
: applyResolvedRoute(nextSession, resolvedRoute)
|
|
164
|
-
replaceSessions(sessions)
|
|
165
|
-
notify('sessions')
|
|
166
|
-
return NextResponse.json(sessions[id])
|
|
43
|
+
const result = createChatSession(body as Record<string, unknown>)
|
|
44
|
+
if (!result.ok) return NextResponse.json(result.payload, { status: result.status })
|
|
45
|
+
return NextResponse.json(result.payload)
|
|
167
46
|
}
|
|
@@ -1,77 +1,15 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
3
|
-
import type { Connector, ConnectorAccessMutationAction, ConnectorAccessMutationResponse } from '@/types'
|
|
4
3
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
5
|
-
import {
|
|
6
|
-
loadConnectors,
|
|
7
|
-
logActivity,
|
|
8
|
-
upsertStoredItem,
|
|
9
|
-
} from '@/lib/server/storage'
|
|
10
|
-
import { ensureDaemonStarted } from '@/lib/server/runtime/daemon-state'
|
|
11
|
-
import { notify } from '@/lib/server/ws-hub'
|
|
12
|
-
import { errorMessage } from '@/lib/shared-utils'
|
|
13
4
|
import {
|
|
14
5
|
buildConnectorAccessSnapshot,
|
|
15
|
-
resolveConnectorOwnerSenderId,
|
|
16
6
|
} from '@/lib/server/connectors/access'
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
approvePendingSender,
|
|
21
|
-
clearSenderAddressingOverride,
|
|
22
|
-
normalizeSenderId,
|
|
23
|
-
parseAllowFromCsv,
|
|
24
|
-
parseDmAddressingMode,
|
|
25
|
-
parsePairingPolicy,
|
|
26
|
-
removeAllowedSender,
|
|
27
|
-
rejectPendingSender,
|
|
28
|
-
setSenderAddressingOverride,
|
|
29
|
-
senderMatchesAnyEntry,
|
|
30
|
-
} from '@/lib/server/connectors/pairing'
|
|
31
|
-
|
|
32
|
-
function setConnectorSenderList(connector: Connector, key: string, values: string[]): void {
|
|
33
|
-
if (!connector.config) connector.config = {}
|
|
34
|
-
if (values.length === 0) {
|
|
35
|
-
delete connector.config[key]
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
connector.config[key] = values.join(',')
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function addConnectorSenderListEntry(connector: Connector, key: string, senderId: string): boolean {
|
|
42
|
-
const normalized = normalizeSenderId(senderId)
|
|
43
|
-
if (!normalized) return false
|
|
44
|
-
const current = parseAllowFromCsv(connector.config?.[key])
|
|
45
|
-
if (senderMatchesAnyEntry(normalized, current)) return false
|
|
46
|
-
setConnectorSenderList(connector, key, [...current, normalized])
|
|
47
|
-
return true
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function removeConnectorSenderListEntry(connector: Connector, key: string, senderId: string): boolean {
|
|
51
|
-
const normalized = normalizeSenderId(senderId)
|
|
52
|
-
if (!normalized) return false
|
|
53
|
-
const current = parseAllowFromCsv(connector.config?.[key])
|
|
54
|
-
const next = current.filter((entry) => !senderMatchesAnyEntry(normalized, [entry]))
|
|
55
|
-
if (next.length === current.length) return false
|
|
56
|
-
setConnectorSenderList(connector, key, next)
|
|
57
|
-
return true
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function persistConnector(connector: Connector): void {
|
|
61
|
-
connector.updatedAt = Date.now()
|
|
62
|
-
upsertStoredItem('connectors', connector.id, connector)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function requireSenderId(body: Record<string, unknown>): string {
|
|
66
|
-
const senderId = typeof body.senderId === 'string' ? body.senderId.trim() : ''
|
|
67
|
-
if (!senderId) {
|
|
68
|
-
throw new Error('senderId is required for this action')
|
|
69
|
-
}
|
|
70
|
-
return senderId
|
|
71
|
-
}
|
|
7
|
+
import { loadConnectors } from '@/lib/server/connectors/connector-repository'
|
|
8
|
+
import { ensureDaemonProcessRunning } from '@/lib/server/daemon/controller'
|
|
9
|
+
import { updateConnectorAccess } from '@/lib/server/connectors/connector-service'
|
|
72
10
|
|
|
73
11
|
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
74
|
-
|
|
12
|
+
await ensureDaemonProcessRunning('api/connectors/[id]/access:get')
|
|
75
13
|
const { id } = await params
|
|
76
14
|
const connectors = loadConnectors()
|
|
77
15
|
const connector = connectors[id]
|
|
@@ -88,169 +26,14 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
88
26
|
}
|
|
89
27
|
|
|
90
28
|
export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
91
|
-
ensureDaemonStarted('api/connectors/[id]/access:put')
|
|
92
29
|
const { id } = await params
|
|
93
|
-
const
|
|
94
|
-
const connector = connectors[id]
|
|
30
|
+
const connector = loadConnectors()[id]
|
|
95
31
|
if (!connector) return notFound()
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let connectorChanged = false
|
|
106
|
-
let responseSenderId = typeof body.senderId === 'string' ? body.senderId.trim() : ''
|
|
107
|
-
const responseSenderIdAlt = typeof body.senderIdAlt === 'string' ? body.senderIdAlt.trim() : ''
|
|
108
|
-
let summary = `Updated access controls for "${connector.name}".`
|
|
109
|
-
|
|
110
|
-
switch (action) {
|
|
111
|
-
case 'set_policy': {
|
|
112
|
-
const rawPolicy = typeof body.dmPolicy === 'string' ? body.dmPolicy.trim() : ''
|
|
113
|
-
if (!rawPolicy) {
|
|
114
|
-
delete connector.config.dmPolicy
|
|
115
|
-
} else {
|
|
116
|
-
connector.config.dmPolicy = parsePairingPolicy(rawPolicy, 'open')
|
|
117
|
-
}
|
|
118
|
-
connectorChanged = true
|
|
119
|
-
summary = `Updated DM policy for "${connector.name}".`
|
|
120
|
-
break
|
|
121
|
-
}
|
|
122
|
-
case 'set_dm_addressing_mode': {
|
|
123
|
-
const rawMode = typeof body.dmAddressingMode === 'string' ? body.dmAddressingMode.trim() : ''
|
|
124
|
-
const nextMode = parseDmAddressingMode(rawMode || 'open', 'open')
|
|
125
|
-
if (nextMode === 'open') delete connector.config.dmAddressingMode
|
|
126
|
-
else connector.config.dmAddressingMode = nextMode
|
|
127
|
-
connectorChanged = true
|
|
128
|
-
summary = `Updated DM addressing mode for "${connector.name}" to ${nextMode}.`
|
|
129
|
-
break
|
|
130
|
-
}
|
|
131
|
-
case 'allow_sender': {
|
|
132
|
-
const senderId = requireSenderId(body)
|
|
133
|
-
addAllowedSender(connector.id, senderId)
|
|
134
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'denyFrom', senderId) || connectorChanged
|
|
135
|
-
summary = `Allowed sender ${normalizeSenderId(senderId)} on "${connector.name}".`
|
|
136
|
-
break
|
|
137
|
-
}
|
|
138
|
-
case 'remove_allowed_sender': {
|
|
139
|
-
const senderId = requireSenderId(body)
|
|
140
|
-
removeAllowedSender(connector.id, senderId)
|
|
141
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'allowFrom', senderId) || connectorChanged
|
|
142
|
-
summary = `Removed connector-managed access for ${normalizeSenderId(senderId)} on "${connector.name}".`
|
|
143
|
-
break
|
|
144
|
-
}
|
|
145
|
-
case 'block_sender': {
|
|
146
|
-
const senderId = requireSenderId(body)
|
|
147
|
-
connectorChanged = addConnectorSenderListEntry(connector, 'denyFrom', senderId) || connectorChanged
|
|
148
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'allowFrom', senderId) || connectorChanged
|
|
149
|
-
removeAllowedSender(connector.id, senderId)
|
|
150
|
-
rejectPendingSender(connector.id, senderId)
|
|
151
|
-
const ownerSenderId = resolveConnectorOwnerSenderId(connector)
|
|
152
|
-
if (ownerSenderId && senderMatchesAnyEntry(senderId, [ownerSenderId])) {
|
|
153
|
-
delete connector.config.ownerSenderId
|
|
154
|
-
connectorChanged = true
|
|
155
|
-
}
|
|
156
|
-
summary = `Blocked sender ${normalizeSenderId(senderId)} on "${connector.name}".`
|
|
157
|
-
break
|
|
158
|
-
}
|
|
159
|
-
case 'unblock_sender': {
|
|
160
|
-
const senderId = requireSenderId(body)
|
|
161
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'denyFrom', senderId) || connectorChanged
|
|
162
|
-
summary = `Removed sender ${normalizeSenderId(senderId)} from the deny list on "${connector.name}".`
|
|
163
|
-
break
|
|
164
|
-
}
|
|
165
|
-
case 'approve_pairing': {
|
|
166
|
-
if (typeof body.code === 'string' && body.code.trim()) {
|
|
167
|
-
const approved = approvePairingCode(connector.id, body.code)
|
|
168
|
-
if (!approved.ok) {
|
|
169
|
-
return NextResponse.json({ error: approved.reason || 'Pairing approval failed.' }, { status: 400 })
|
|
170
|
-
}
|
|
171
|
-
if (approved.senderId) {
|
|
172
|
-
responseSenderId = approved.senderId
|
|
173
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'denyFrom', approved.senderId) || connectorChanged
|
|
174
|
-
}
|
|
175
|
-
summary = `Approved pairing on "${connector.name}".`
|
|
176
|
-
} else {
|
|
177
|
-
const senderId = requireSenderId(body)
|
|
178
|
-
const approved = approvePendingSender(connector.id, senderId)
|
|
179
|
-
if (!approved.ok) {
|
|
180
|
-
return NextResponse.json({ error: approved.reason || 'Pairing approval failed.' }, { status: 400 })
|
|
181
|
-
}
|
|
182
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'denyFrom', senderId) || connectorChanged
|
|
183
|
-
summary = `Approved pairing for ${normalizeSenderId(senderId)} on "${connector.name}".`
|
|
184
|
-
}
|
|
185
|
-
break
|
|
186
|
-
}
|
|
187
|
-
case 'reject_pairing': {
|
|
188
|
-
const senderId = requireSenderId(body)
|
|
189
|
-
rejectPendingSender(connector.id, senderId)
|
|
190
|
-
summary = `Rejected pairing for ${normalizeSenderId(senderId)} on "${connector.name}".`
|
|
191
|
-
break
|
|
192
|
-
}
|
|
193
|
-
case 'set_owner': {
|
|
194
|
-
const senderId = requireSenderId(body)
|
|
195
|
-
const normalized = normalizeSenderId(senderId)
|
|
196
|
-
if (!normalized) {
|
|
197
|
-
return NextResponse.json({ error: 'Could not normalize owner sender ID' }, { status: 400 })
|
|
198
|
-
}
|
|
199
|
-
connector.config.ownerSenderId = normalized
|
|
200
|
-
connectorChanged = true
|
|
201
|
-
connectorChanged = removeConnectorSenderListEntry(connector, 'denyFrom', normalized) || connectorChanged
|
|
202
|
-
summary = `Set connector owner for "${connector.name}" to ${normalized}.`
|
|
203
|
-
break
|
|
204
|
-
}
|
|
205
|
-
case 'clear_owner': {
|
|
206
|
-
if (connector.config?.ownerSenderId) {
|
|
207
|
-
delete connector.config.ownerSenderId
|
|
208
|
-
connectorChanged = true
|
|
209
|
-
}
|
|
210
|
-
summary = `Cleared connector owner override for "${connector.name}".`
|
|
211
|
-
break
|
|
212
|
-
}
|
|
213
|
-
case 'set_sender_dm_addressing': {
|
|
214
|
-
const senderId = requireSenderId(body)
|
|
215
|
-
const rawMode = typeof body.dmAddressingMode === 'string' ? body.dmAddressingMode.trim() : ''
|
|
216
|
-
const nextMode = parseDmAddressingMode(rawMode || 'open', 'open')
|
|
217
|
-
setSenderAddressingOverride(connector.id, senderId, nextMode)
|
|
218
|
-
summary = `Updated DM addressing override for ${normalizeSenderId(senderId)} on "${connector.name}" to ${nextMode}.`
|
|
219
|
-
break
|
|
220
|
-
}
|
|
221
|
-
case 'clear_sender_dm_addressing': {
|
|
222
|
-
const senderId = requireSenderId(body)
|
|
223
|
-
clearSenderAddressingOverride(connector.id, senderId)
|
|
224
|
-
summary = `Cleared DM addressing override for ${normalizeSenderId(senderId)} on "${connector.name}".`
|
|
225
|
-
break
|
|
226
|
-
}
|
|
227
|
-
default:
|
|
228
|
-
return NextResponse.json({ error: `Unsupported access action: ${action}` }, { status: 400 })
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (connectorChanged) {
|
|
232
|
-
persistConnector(connector)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
logActivity({
|
|
236
|
-
entityType: 'connector',
|
|
237
|
-
entityId: connector.id,
|
|
238
|
-
action: 'access-updated',
|
|
239
|
-
actor: 'user',
|
|
240
|
-
summary,
|
|
241
|
-
detail: { action },
|
|
242
|
-
})
|
|
243
|
-
notify('connectors')
|
|
244
|
-
|
|
245
|
-
return NextResponse.json<ConnectorAccessMutationResponse>({
|
|
246
|
-
ok: true,
|
|
247
|
-
snapshot: buildConnectorAccessSnapshot({
|
|
248
|
-
connector,
|
|
249
|
-
senderId: responseSenderId || null,
|
|
250
|
-
senderIdAlt: responseSenderIdAlt || null,
|
|
251
|
-
}),
|
|
252
|
-
})
|
|
253
|
-
} catch (err: unknown) {
|
|
254
|
-
return NextResponse.json({ error: errorMessage(err) }, { status: 400 })
|
|
255
|
-
}
|
|
32
|
+
const { data: body, error } = await safeParseBody<Record<string, unknown>>(req)
|
|
33
|
+
if (error) return error
|
|
34
|
+
const result = await updateConnectorAccess(id, body)
|
|
35
|
+
if (!result.ok && result.status === 404) return notFound()
|
|
36
|
+
return result.ok
|
|
37
|
+
? NextResponse.json(result.payload)
|
|
38
|
+
: NextResponse.json(result.payload, { status: result.status })
|
|
256
39
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import { loadConnectors } from '@/lib/server/storage'
|
|
3
2
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
3
|
import { buildConnectorDoctorPreview, buildConnectorDoctorReport, type ConnectorDoctorPreviewInput } from '@/lib/server/connectors/doctor'
|
|
4
|
+
import { loadConnectors } from '@/lib/server/connectors/connector-repository'
|
|
5
5
|
|
|
6
6
|
export const dynamic = 'force-dynamic'
|
|
7
7
|
|