@swarmclawai/swarmclaw 1.2.4 → 1.2.5
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 +15 -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/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
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import os from 'node:os'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
import { genId } from '@/lib/id'
|
|
5
|
+
import { normalizeCapabilitySelection } from '@/lib/capability-selection'
|
|
6
|
+
import { buildAgentDisabledMessage, isAgentDisabled } from '@/lib/server/agents/agent-availability'
|
|
7
|
+
import { loadAgent } from '@/lib/server/agents/agent-repository'
|
|
8
|
+
import { clearMainLoopStateForSession } from '@/lib/server/agents/main-agent-loop'
|
|
9
|
+
import { applyResolvedRoute, resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
|
|
10
|
+
import { enrichSessionWithMissionSummary } from '@/lib/server/missions/mission-service'
|
|
11
|
+
import { cleanupSessionProcesses } from '@/lib/server/runtime/process-manager'
|
|
12
|
+
import { stopActiveSessionProcess } from '@/lib/server/runtime/runtime-state'
|
|
13
|
+
import {
|
|
14
|
+
cancelQueuedRunById,
|
|
15
|
+
cancelQueuedRunsForSession,
|
|
16
|
+
enqueueSessionRun,
|
|
17
|
+
getSessionQueueSnapshot,
|
|
18
|
+
getSessionRunState,
|
|
19
|
+
} from '@/lib/server/runtime/session-run-manager'
|
|
20
|
+
import { deleteSession, getSession, listSessions, saveSession } from '@/lib/server/sessions/session-repository'
|
|
21
|
+
import {
|
|
22
|
+
clearMessages,
|
|
23
|
+
deleteSessionMessages,
|
|
24
|
+
getMessages,
|
|
25
|
+
truncateAfter,
|
|
26
|
+
} from '@/lib/server/messages/message-repository'
|
|
27
|
+
import { deleteSessionWorkingState } from '@/lib/server/working-state/service'
|
|
28
|
+
import { normalizeProviderEndpoint } from '@/lib/openclaw/openclaw-endpoint'
|
|
29
|
+
import { serviceFail, serviceOk } from '@/lib/server/service-result'
|
|
30
|
+
import { WORKSPACE_DIR } from '@/lib/server/data-dir'
|
|
31
|
+
import { buildSessionListSummary } from '@/lib/chat/session-summary'
|
|
32
|
+
import type { Session } from '@/types'
|
|
33
|
+
import type { ServiceResult } from '@/lib/server/service-result'
|
|
34
|
+
import { notify } from '@/lib/server/ws-hub'
|
|
35
|
+
|
|
36
|
+
function normalizeCwd(value: unknown): string {
|
|
37
|
+
const raw = typeof value === 'string' ? value.trim() : ''
|
|
38
|
+
if (raw.startsWith('~/')) return path.join(os.homedir(), raw.slice(2))
|
|
39
|
+
if (raw === '~') return os.homedir()
|
|
40
|
+
if (!raw) return WORKSPACE_DIR
|
|
41
|
+
return raw
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function emptyDelegateResumeIds() {
|
|
45
|
+
return {
|
|
46
|
+
claudeCode: null,
|
|
47
|
+
codex: null,
|
|
48
|
+
opencode: null,
|
|
49
|
+
gemini: null,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function listChatsForApi(): Record<string, ReturnType<typeof buildSessionListSummary>> {
|
|
54
|
+
const sessions = listSessions()
|
|
55
|
+
for (const id of Object.keys(sessions)) {
|
|
56
|
+
const run = getSessionRunState(id)
|
|
57
|
+
const queue = getSessionQueueSnapshot(id)
|
|
58
|
+
sessions[id].active = !!run.runningRunId
|
|
59
|
+
sessions[id].queuedCount = queue.queueLength
|
|
60
|
+
sessions[id].currentRunId = run.runningRunId || null
|
|
61
|
+
}
|
|
62
|
+
return Object.fromEntries(
|
|
63
|
+
Object.entries(sessions).map(([id, session]) => [id, buildSessionListSummary(enrichSessionWithMissionSummary(session))]),
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getChatSessionForApi(sessionId: string): Session | null {
|
|
68
|
+
const session = getSession(sessionId)
|
|
69
|
+
if (!session) return null
|
|
70
|
+
const run = getSessionRunState(sessionId)
|
|
71
|
+
const queue = getSessionQueueSnapshot(sessionId)
|
|
72
|
+
session.active = !!run.runningRunId
|
|
73
|
+
session.queuedCount = queue.queueLength
|
|
74
|
+
session.currentRunId = run.runningRunId || null
|
|
75
|
+
return enrichSessionWithMissionSummary(session)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createChatSession(input: Record<string, unknown>): ServiceResult<Session> {
|
|
79
|
+
const id = typeof input.id === 'string' && input.id.trim() ? input.id.trim() : genId()
|
|
80
|
+
const sessions = listSessions()
|
|
81
|
+
if (typeof input.id === 'string' && sessions[id]) {
|
|
82
|
+
return serviceOk(sessions[id])
|
|
83
|
+
}
|
|
84
|
+
const agent = typeof input.agentId === 'string' ? loadAgent(input.agentId) : null
|
|
85
|
+
if (isAgentDisabled(agent)) {
|
|
86
|
+
return serviceFail(409, buildAgentDisabledMessage(agent, 'start chats'))
|
|
87
|
+
}
|
|
88
|
+
const explicitOllamaMode = input.ollamaMode === 'cloud' ? 'cloud' : input.ollamaMode === 'local' ? 'local' : null
|
|
89
|
+
const routePreferredGatewayTags = Array.isArray(input.routePreferredGatewayTags)
|
|
90
|
+
? input.routePreferredGatewayTags.filter((tag): tag is string => typeof tag === 'string' && tag.trim().length > 0)
|
|
91
|
+
: []
|
|
92
|
+
const routePreferredGatewayUseCase = typeof input.routePreferredGatewayUseCase === 'string' && input.routePreferredGatewayUseCase.trim()
|
|
93
|
+
? input.routePreferredGatewayUseCase.trim()
|
|
94
|
+
: null
|
|
95
|
+
const resolvedRoute = agent ? resolvePrimaryAgentRoute(agent, undefined, {
|
|
96
|
+
preferredGatewayTags: routePreferredGatewayTags,
|
|
97
|
+
preferredGatewayUseCase: routePreferredGatewayUseCase,
|
|
98
|
+
}) : null
|
|
99
|
+
const resolvedCapabilities = normalizeCapabilitySelection({
|
|
100
|
+
tools: Array.isArray(input.tools) ? input.tools : agent?.tools,
|
|
101
|
+
extensions: Array.isArray(input.extensions) ? input.extensions : agent?.extensions,
|
|
102
|
+
})
|
|
103
|
+
const provider = (
|
|
104
|
+
typeof input.provider === 'string' && input.provider.trim()
|
|
105
|
+
? input.provider.trim()
|
|
106
|
+
: agent?.provider || 'claude-cli'
|
|
107
|
+
) as Session['provider']
|
|
108
|
+
const now = Date.now()
|
|
109
|
+
const baseSession: Session = {
|
|
110
|
+
id,
|
|
111
|
+
name: (input.name as string) || 'New Chat',
|
|
112
|
+
cwd: normalizeCwd(input.cwd),
|
|
113
|
+
user: (input.user as string) || 'user',
|
|
114
|
+
provider,
|
|
115
|
+
model: (input.model as string) || agent?.model || '',
|
|
116
|
+
ollamaMode: explicitOllamaMode ?? agent?.ollamaMode ?? (provider === 'ollama' ? 'local' : null),
|
|
117
|
+
credentialId: (input.credentialId as string | null | undefined) || agent?.credentialId || null,
|
|
118
|
+
fallbackCredentialIds: Array.isArray(input.fallbackCredentialIds) ? input.fallbackCredentialIds : agent?.fallbackCredentialIds || [],
|
|
119
|
+
apiEndpoint: normalizeProviderEndpoint(
|
|
120
|
+
provider,
|
|
121
|
+
(input.apiEndpoint as string | null | undefined) || agent?.apiEndpoint || null,
|
|
122
|
+
),
|
|
123
|
+
routePreferredGatewayTags,
|
|
124
|
+
routePreferredGatewayUseCase,
|
|
125
|
+
claudeSessionId: null,
|
|
126
|
+
codexThreadId: null,
|
|
127
|
+
opencodeSessionId: null,
|
|
128
|
+
delegateResumeIds: emptyDelegateResumeIds(),
|
|
129
|
+
messages: Array.isArray(input.messages) ? input.messages : [],
|
|
130
|
+
createdAt: now,
|
|
131
|
+
lastActiveAt: now,
|
|
132
|
+
sessionType: (input.sessionType as Session['sessionType']) || 'human',
|
|
133
|
+
agentId: (input.agentId as string | null | undefined) || null,
|
|
134
|
+
parentSessionId: (input.parentSessionId as string | null | undefined) || null,
|
|
135
|
+
tools: resolvedCapabilities.tools,
|
|
136
|
+
extensions: resolvedCapabilities.extensions,
|
|
137
|
+
heartbeatEnabled: (input.heartbeatEnabled as boolean | null | undefined) ?? null,
|
|
138
|
+
heartbeatIntervalSec: (input.heartbeatIntervalSec as number | null | undefined) ?? null,
|
|
139
|
+
sessionResetMode: (input.sessionResetMode as Session['sessionResetMode']) ?? agent?.sessionResetMode ?? null,
|
|
140
|
+
sessionIdleTimeoutSec: (input.sessionIdleTimeoutSec as number | null | undefined) ?? agent?.sessionIdleTimeoutSec ?? null,
|
|
141
|
+
sessionMaxAgeSec: (input.sessionMaxAgeSec as number | null | undefined) ?? agent?.sessionMaxAgeSec ?? null,
|
|
142
|
+
sessionDailyResetAt: (input.sessionDailyResetAt as string | null | undefined) ?? agent?.sessionDailyResetAt ?? null,
|
|
143
|
+
sessionResetTimezone: (input.sessionResetTimezone as string | null | undefined) ?? agent?.sessionResetTimezone ?? null,
|
|
144
|
+
thinkingLevel: (input.thinkingLevel as Session['thinkingLevel']) ?? null,
|
|
145
|
+
connectorThinkLevel: (input.connectorThinkLevel as Session['connectorThinkLevel']) ?? null,
|
|
146
|
+
connectorSessionScope: (input.connectorSessionScope as Session['connectorSessionScope']) ?? null,
|
|
147
|
+
connectorReplyMode: (input.connectorReplyMode as Session['connectorReplyMode']) ?? null,
|
|
148
|
+
connectorThreadBinding: (input.connectorThreadBinding as Session['connectorThreadBinding']) ?? null,
|
|
149
|
+
connectorGroupPolicy: (input.connectorGroupPolicy as Session['connectorGroupPolicy']) ?? null,
|
|
150
|
+
connectorIdleTimeoutSec: (input.connectorIdleTimeoutSec as number | null | undefined) ?? null,
|
|
151
|
+
connectorMaxAgeSec: (input.connectorMaxAgeSec as number | null | undefined) ?? null,
|
|
152
|
+
connectorContext: input.connectorContext === null
|
|
153
|
+
? undefined
|
|
154
|
+
: (input.connectorContext as Session['connectorContext']),
|
|
155
|
+
identityState: (input.identityState as Session['identityState']) ?? agent?.identityState ?? null,
|
|
156
|
+
sessionArchiveState: (input.sessionArchiveState as Session['sessionArchiveState']) ?? null,
|
|
157
|
+
}
|
|
158
|
+
const session: Session = (input.provider || input.model || input.credentialId || input.apiEndpoint)
|
|
159
|
+
? baseSession
|
|
160
|
+
: applyResolvedRoute(baseSession, resolvedRoute)
|
|
161
|
+
saveSession(id, session)
|
|
162
|
+
notify('sessions')
|
|
163
|
+
return serviceOk(session)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function deleteChats(ids: string[]): { deleted: number; requested: number } {
|
|
167
|
+
let deleted = 0
|
|
168
|
+
const sessions = listSessions()
|
|
169
|
+
for (const id of ids) {
|
|
170
|
+
if (!sessions[id]) continue
|
|
171
|
+
stopActiveSessionProcess(id)
|
|
172
|
+
deleteSessionWorkingState(id)
|
|
173
|
+
clearMainLoopStateForSession(id)
|
|
174
|
+
deleteSessionMessages(id)
|
|
175
|
+
deleteSession(id)
|
|
176
|
+
deleted += 1
|
|
177
|
+
}
|
|
178
|
+
if (deleted > 0) notify('sessions')
|
|
179
|
+
return { deleted, requested: ids.length }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function updateChatSession(sessionId: string, updates: Record<string, unknown>): Session | null {
|
|
183
|
+
const original = getSession(sessionId)
|
|
184
|
+
if (!original) return null
|
|
185
|
+
const session = original as unknown as Record<string, unknown>
|
|
186
|
+
|
|
187
|
+
if (updates.resetMainLoopState === true) {
|
|
188
|
+
clearMainLoopStateForSession(sessionId)
|
|
189
|
+
deleteSessionWorkingState(sessionId)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const agentIdUpdateProvided = updates.agentId !== undefined
|
|
193
|
+
let nextAgentId = session.agentId
|
|
194
|
+
if (agentIdUpdateProvided) {
|
|
195
|
+
session.agentId = updates.agentId
|
|
196
|
+
nextAgentId = updates.agentId
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const linkedAgent = nextAgentId ? loadAgent(String(nextAgentId)) : null
|
|
200
|
+
const routePreferredGatewayTags = updates.routePreferredGatewayTags !== undefined
|
|
201
|
+
? (Array.isArray(updates.routePreferredGatewayTags)
|
|
202
|
+
? updates.routePreferredGatewayTags.filter((tag): tag is string => typeof tag === 'string' && tag.trim().length > 0)
|
|
203
|
+
: [])
|
|
204
|
+
: ((session.routePreferredGatewayTags as string[]) || [])
|
|
205
|
+
const routePreferredGatewayUseCase = updates.routePreferredGatewayUseCase !== undefined
|
|
206
|
+
? (typeof updates.routePreferredGatewayUseCase === 'string' && updates.routePreferredGatewayUseCase.trim()
|
|
207
|
+
? updates.routePreferredGatewayUseCase.trim()
|
|
208
|
+
: null)
|
|
209
|
+
: ((session.routePreferredGatewayUseCase as string | null) || null)
|
|
210
|
+
const linkedRoute = linkedAgent ? resolvePrimaryAgentRoute(linkedAgent, undefined, {
|
|
211
|
+
preferredGatewayTags: routePreferredGatewayTags,
|
|
212
|
+
preferredGatewayUseCase: routePreferredGatewayUseCase,
|
|
213
|
+
}) : null
|
|
214
|
+
|
|
215
|
+
if (updates.name !== undefined) session.name = updates.name
|
|
216
|
+
if (updates.cwd !== undefined) session.cwd = normalizeCwd(updates.cwd)
|
|
217
|
+
if (updates.provider !== undefined) session.provider = updates.provider
|
|
218
|
+
else if (agentIdUpdateProvided && linkedAgent?.provider) session.provider = linkedAgent.provider
|
|
219
|
+
if (updates.model !== undefined) session.model = updates.model
|
|
220
|
+
else if (agentIdUpdateProvided && linkedRoute?.model) session.model = linkedRoute.model
|
|
221
|
+
else if (agentIdUpdateProvided && linkedAgent?.model !== undefined) session.model = linkedAgent.model
|
|
222
|
+
if (updates.ollamaMode !== undefined) session.ollamaMode = updates.ollamaMode
|
|
223
|
+
else if (updates.provider !== undefined && updates.provider !== 'ollama') session.ollamaMode = null
|
|
224
|
+
else if (agentIdUpdateProvided && linkedRoute) session.ollamaMode = linkedRoute.ollamaMode ?? null
|
|
225
|
+
else if (agentIdUpdateProvided && linkedAgent) session.ollamaMode = linkedAgent.ollamaMode ?? null
|
|
226
|
+
if (updates.credentialId !== undefined) session.credentialId = updates.credentialId
|
|
227
|
+
else if (agentIdUpdateProvided && linkedRoute) session.credentialId = linkedRoute.credentialId ?? null
|
|
228
|
+
else if (agentIdUpdateProvided && linkedAgent) session.credentialId = linkedAgent.credentialId ?? null
|
|
229
|
+
if (updates.fallbackCredentialIds !== undefined) session.fallbackCredentialIds = updates.fallbackCredentialIds
|
|
230
|
+
else if (agentIdUpdateProvided && linkedRoute) session.fallbackCredentialIds = [...linkedRoute.fallbackCredentialIds]
|
|
231
|
+
if (updates.gatewayProfileId !== undefined) session.gatewayProfileId = updates.gatewayProfileId
|
|
232
|
+
else if (agentIdUpdateProvided && linkedRoute) session.gatewayProfileId = linkedRoute.gatewayProfileId ?? null
|
|
233
|
+
if (updates.routePreferredGatewayTags !== undefined) session.routePreferredGatewayTags = routePreferredGatewayTags
|
|
234
|
+
if (updates.routePreferredGatewayUseCase !== undefined) session.routePreferredGatewayUseCase = routePreferredGatewayUseCase
|
|
235
|
+
|
|
236
|
+
if (updates.tools !== undefined || updates.extensions !== undefined || (agentIdUpdateProvided && linkedAgent)) {
|
|
237
|
+
const nextSelection = normalizeCapabilitySelection({
|
|
238
|
+
tools: Array.isArray(updates.tools)
|
|
239
|
+
? updates.tools
|
|
240
|
+
: (agentIdUpdateProvided && linkedAgent ? linkedAgent.tools : session.tools as string[] | undefined),
|
|
241
|
+
extensions: Array.isArray(updates.extensions)
|
|
242
|
+
? updates.extensions
|
|
243
|
+
: (agentIdUpdateProvided && linkedAgent ? linkedAgent.extensions : session.extensions as string[] | undefined),
|
|
244
|
+
})
|
|
245
|
+
session.tools = nextSelection.tools
|
|
246
|
+
session.extensions = nextSelection.extensions
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (updates.apiEndpoint !== undefined) {
|
|
250
|
+
session.apiEndpoint = normalizeProviderEndpoint(
|
|
251
|
+
(updates.provider || session.provider) as string,
|
|
252
|
+
updates.apiEndpoint as string | null | undefined,
|
|
253
|
+
)
|
|
254
|
+
} else if (agentIdUpdateProvided && linkedRoute) {
|
|
255
|
+
session.apiEndpoint = linkedRoute.apiEndpoint ?? null
|
|
256
|
+
} else if (agentIdUpdateProvided && linkedAgent) {
|
|
257
|
+
session.apiEndpoint = normalizeProviderEndpoint(linkedAgent.provider, linkedAgent.apiEndpoint ?? null)
|
|
258
|
+
}
|
|
259
|
+
if (updates.heartbeatEnabled !== undefined) session.heartbeatEnabled = updates.heartbeatEnabled
|
|
260
|
+
if (updates.heartbeatIntervalSec !== undefined) session.heartbeatIntervalSec = updates.heartbeatIntervalSec
|
|
261
|
+
if (updates.sessionResetMode !== undefined) session.sessionResetMode = updates.sessionResetMode
|
|
262
|
+
if (updates.sessionIdleTimeoutSec !== undefined) session.sessionIdleTimeoutSec = updates.sessionIdleTimeoutSec
|
|
263
|
+
if (updates.sessionMaxAgeSec !== undefined) session.sessionMaxAgeSec = updates.sessionMaxAgeSec
|
|
264
|
+
if (updates.sessionDailyResetAt !== undefined) session.sessionDailyResetAt = updates.sessionDailyResetAt
|
|
265
|
+
if (updates.sessionResetTimezone !== undefined) session.sessionResetTimezone = updates.sessionResetTimezone
|
|
266
|
+
if (updates.thinkingLevel !== undefined) session.thinkingLevel = updates.thinkingLevel
|
|
267
|
+
if (updates.connectorThinkLevel !== undefined) session.connectorThinkLevel = updates.connectorThinkLevel
|
|
268
|
+
if (updates.connectorSessionScope !== undefined) session.connectorSessionScope = updates.connectorSessionScope
|
|
269
|
+
if (updates.connectorReplyMode !== undefined) session.connectorReplyMode = updates.connectorReplyMode
|
|
270
|
+
if (updates.connectorThreadBinding !== undefined) session.connectorThreadBinding = updates.connectorThreadBinding
|
|
271
|
+
if (updates.connectorGroupPolicy !== undefined) session.connectorGroupPolicy = updates.connectorGroupPolicy
|
|
272
|
+
if (updates.connectorIdleTimeoutSec !== undefined) session.connectorIdleTimeoutSec = updates.connectorIdleTimeoutSec
|
|
273
|
+
if (updates.connectorMaxAgeSec !== undefined) session.connectorMaxAgeSec = updates.connectorMaxAgeSec
|
|
274
|
+
if (updates.connectorContext !== undefined) session.connectorContext = updates.connectorContext
|
|
275
|
+
if (updates.identityState !== undefined) session.identityState = updates.identityState
|
|
276
|
+
if (updates.sessionArchiveState !== undefined) session.sessionArchiveState = updates.sessionArchiveState
|
|
277
|
+
if (updates.lastSessionResetAt !== undefined) session.lastSessionResetAt = updates.lastSessionResetAt
|
|
278
|
+
if (updates.lastSessionResetReason !== undefined) session.lastSessionResetReason = updates.lastSessionResetReason
|
|
279
|
+
if (updates.pinned !== undefined) session.pinned = !!updates.pinned
|
|
280
|
+
if (updates.claudeSessionId !== undefined) session.claudeSessionId = updates.claudeSessionId
|
|
281
|
+
if (updates.codexThreadId !== undefined) session.codexThreadId = updates.codexThreadId
|
|
282
|
+
if (updates.opencodeSessionId !== undefined) session.opencodeSessionId = updates.opencodeSessionId
|
|
283
|
+
if (updates.delegateResumeIds !== undefined) session.delegateResumeIds = updates.delegateResumeIds
|
|
284
|
+
if (!Array.isArray(session.messages)) session.messages = []
|
|
285
|
+
|
|
286
|
+
saveSession(sessionId, original)
|
|
287
|
+
notify('sessions')
|
|
288
|
+
return enrichSessionWithMissionSummary(original)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function deleteChatSession(sessionId: string): boolean {
|
|
292
|
+
if (!getSession(sessionId)) return false
|
|
293
|
+
stopActiveSessionProcess(sessionId)
|
|
294
|
+
cleanupSessionProcesses(sessionId)
|
|
295
|
+
deleteSessionMessages(sessionId)
|
|
296
|
+
deleteSession(sessionId)
|
|
297
|
+
notify('sessions')
|
|
298
|
+
return true
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function getQueueSnapshot(sessionId: string) {
|
|
302
|
+
const session = getSession(sessionId)
|
|
303
|
+
if (!session) return null
|
|
304
|
+
return getSessionQueueSnapshot(sessionId)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function queueChatMessage(sessionId: string, body: Record<string, unknown>): ServiceResult<Record<string, unknown>> {
|
|
308
|
+
const session = getSession(sessionId)
|
|
309
|
+
if (!session) return serviceFail(404, 'Not found')
|
|
310
|
+
const message = typeof body.message === 'string' ? body.message : ''
|
|
311
|
+
const imagePath = typeof body.imagePath === 'string' ? body.imagePath : undefined
|
|
312
|
+
const imageUrl = typeof body.imageUrl === 'string' ? body.imageUrl : undefined
|
|
313
|
+
const attachedFiles = Array.isArray(body.attachedFiles)
|
|
314
|
+
? body.attachedFiles.filter((file): file is string => typeof file === 'string' && file.trim().length > 0)
|
|
315
|
+
: undefined
|
|
316
|
+
const replyToId = typeof body.replyToId === 'string' ? body.replyToId : undefined
|
|
317
|
+
const hasFiles = !!(imagePath || imageUrl || attachedFiles?.length)
|
|
318
|
+
if (!message.trim() && !hasFiles) {
|
|
319
|
+
return serviceFail(400, 'message or file is required')
|
|
320
|
+
}
|
|
321
|
+
const queued = enqueueSessionRun({
|
|
322
|
+
sessionId,
|
|
323
|
+
missionId: session.missionId || null,
|
|
324
|
+
message,
|
|
325
|
+
imagePath,
|
|
326
|
+
imageUrl,
|
|
327
|
+
attachedFiles,
|
|
328
|
+
source: 'chat',
|
|
329
|
+
mode: 'followup',
|
|
330
|
+
replyToId,
|
|
331
|
+
})
|
|
332
|
+
return serviceOk({
|
|
333
|
+
queued: {
|
|
334
|
+
runId: queued.runId,
|
|
335
|
+
position: queued.position,
|
|
336
|
+
},
|
|
337
|
+
snapshot: getSessionQueueSnapshot(sessionId),
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function cancelQueuedChatMessages(sessionId: string, runId?: string): ServiceResult<Record<string, unknown>> | null {
|
|
342
|
+
const session = getSession(sessionId)
|
|
343
|
+
if (!session) return null
|
|
344
|
+
const normalizedRunId = typeof runId === 'string' ? runId.trim() : ''
|
|
345
|
+
if (normalizedRunId) {
|
|
346
|
+
const snapshot = getSessionQueueSnapshot(sessionId)
|
|
347
|
+
if (!snapshot.items.some((item) => item.runId === normalizedRunId)) {
|
|
348
|
+
return serviceFail(404, 'Queued run not found')
|
|
349
|
+
}
|
|
350
|
+
cancelQueuedRunById(normalizedRunId, 'Removed from queue')
|
|
351
|
+
return serviceOk({ cancelled: 1, snapshot: getSessionQueueSnapshot(sessionId) })
|
|
352
|
+
}
|
|
353
|
+
const cancelled = cancelQueuedRunsForSession(sessionId, 'Cleared queued messages')
|
|
354
|
+
return serviceOk({ cancelled, snapshot: getSessionQueueSnapshot(sessionId) })
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export function clearChatMessages(sessionId: string): boolean {
|
|
358
|
+
const session = getSession(sessionId)
|
|
359
|
+
if (!session) return false
|
|
360
|
+
clearMessages(sessionId)
|
|
361
|
+
session.messages = []
|
|
362
|
+
session.claudeSessionId = null
|
|
363
|
+
session.codexThreadId = null
|
|
364
|
+
session.opencodeSessionId = null
|
|
365
|
+
session.delegateResumeIds = emptyDelegateResumeIds()
|
|
366
|
+
saveSession(sessionId, session)
|
|
367
|
+
notify('sessions')
|
|
368
|
+
return true
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function retryChatTurn(sessionId: string): ServiceResult<{ message: string; imagePath: string | null }> {
|
|
372
|
+
const session = getSession(sessionId)
|
|
373
|
+
if (!session) return serviceFail(404, 'Session not found')
|
|
374
|
+
const msgs = getMessages(sessionId)
|
|
375
|
+
// Remove trailing assistant messages
|
|
376
|
+
while (msgs.length && msgs[msgs.length - 1].role === 'assistant') {
|
|
377
|
+
msgs.pop()
|
|
378
|
+
}
|
|
379
|
+
if (!msgs.length) {
|
|
380
|
+
clearMessages(sessionId)
|
|
381
|
+
return serviceOk({ message: '', imagePath: null })
|
|
382
|
+
}
|
|
383
|
+
const lastUser = msgs[msgs.length - 1]
|
|
384
|
+
const message = lastUser.text
|
|
385
|
+
const imagePath = lastUser.imagePath || null
|
|
386
|
+
msgs.pop()
|
|
387
|
+
// Truncate to the new length (keep seq 0..msgs.length-1)
|
|
388
|
+
if (msgs.length === 0) {
|
|
389
|
+
clearMessages(sessionId)
|
|
390
|
+
} else {
|
|
391
|
+
truncateAfter(sessionId, msgs.length - 1)
|
|
392
|
+
}
|
|
393
|
+
return serviceOk({ message, imagePath })
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function editAndResendChatTurn(sessionId: string, messageIndex: number, newText: string): ServiceResult<{ message: string }> {
|
|
397
|
+
const session = getSession(sessionId)
|
|
398
|
+
if (!session) return serviceFail(404, 'Not found')
|
|
399
|
+
const msgCount = getMessages(sessionId).length
|
|
400
|
+
if (typeof messageIndex !== 'number' || messageIndex < 0 || messageIndex >= msgCount) {
|
|
401
|
+
return serviceFail(400, 'Invalid message index')
|
|
402
|
+
}
|
|
403
|
+
// Keep messages up to but not including messageIndex
|
|
404
|
+
if (messageIndex === 0) {
|
|
405
|
+
clearMessages(sessionId)
|
|
406
|
+
} else {
|
|
407
|
+
truncateAfter(sessionId, messageIndex - 1)
|
|
408
|
+
}
|
|
409
|
+
return serviceOk({ message: newText })
|
|
410
|
+
}
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ConnectorAccessSnapshot,
|
|
6
6
|
WhatsAppApprovedContact,
|
|
7
7
|
} from '@/types'
|
|
8
|
-
import { loadSettings } from '../
|
|
8
|
+
import { loadSettings } from '../settings/settings-repository'
|
|
9
9
|
import {
|
|
10
10
|
createOrTouchPairingRequest,
|
|
11
11
|
getSenderAddressingOverride,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { getProvider } from '@/lib/providers'
|
|
2
2
|
import type { Connector } from '@/types'
|
|
3
|
-
import { loadAgents } from '
|
|
3
|
+
import { loadAgents } from '@/lib/server/agents/agent-repository'
|
|
4
4
|
import { syncSessionArchiveMemory } from '@/lib/server/memory/session-archive-memory'
|
|
5
|
+
import { getMessages, replaceAllMessages } from '@/lib/server/messages/message-repository'
|
|
5
6
|
import { getEnabledCapabilityIds } from '@/lib/capability-selection'
|
|
6
7
|
import { resolvePairingAccess } from './access'
|
|
7
8
|
import {
|
|
@@ -189,9 +190,9 @@ export async function handleConnectorCommand(params: {
|
|
|
189
190
|
|
|
190
191
|
if (command.name === 'status') {
|
|
191
192
|
const policy = resolveConnectorSessionPolicy(connector, msg, session)
|
|
192
|
-
const all =
|
|
193
|
-
const userCount = all.filter((message
|
|
194
|
-
const assistantCount = all.filter((message
|
|
193
|
+
const all = getMessages(session.id)
|
|
194
|
+
const userCount = all.filter((message) => message?.role === 'user').length
|
|
195
|
+
const assistantCount = all.filter((message) => message?.role === 'assistant').length
|
|
195
196
|
const toolsCount = getEnabledCapabilityIds(session).length
|
|
196
197
|
const statusText = [
|
|
197
198
|
`Status for ${connector.platform} / ${connector.name}:`,
|
|
@@ -232,7 +233,7 @@ export async function handleConnectorCommand(params: {
|
|
|
232
233
|
if (command.name === 'compact') {
|
|
233
234
|
const keepParsed = Number.parseInt(command.args, 10)
|
|
234
235
|
const keepLastN = Number.isFinite(keepParsed) ? Math.max(4, Math.min(50, keepParsed)) : 10
|
|
235
|
-
const history =
|
|
236
|
+
const history = getMessages(session.id)
|
|
236
237
|
if (history.length <= keepLastN) {
|
|
237
238
|
const text = `Nothing to compact. Current history has ${history.length} message(s), keepLastN=${keepLastN}.`
|
|
238
239
|
pushSessionMessage(session, 'user', inboundText)
|
|
@@ -249,7 +250,7 @@ export async function handleConnectorCommand(params: {
|
|
|
249
250
|
time: Date.now(),
|
|
250
251
|
kind: 'system' as const,
|
|
251
252
|
}
|
|
252
|
-
session.
|
|
253
|
+
replaceAllMessages(session.id, [summaryMessage, ...recentMessages])
|
|
253
254
|
session.lastActiveAt = Date.now()
|
|
254
255
|
const text = `Compacted ${oldMessages.length} message(s). Kept ${recentMessages.length} recent message(s) plus a summary.`
|
|
255
256
|
pushSessionMessage(session, 'assistant', text)
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
loadAgents, loadCredentials, decryptKey, loadSettings, loadSkills,
|
|
7
7
|
loadChatrooms, saveChatrooms,
|
|
8
8
|
} from '../storage'
|
|
9
|
+
import { getMessages } from '@/lib/server/messages/message-repository'
|
|
9
10
|
import { dedup, errorMessage, hmrSingleton } from '@/lib/shared-utils'
|
|
10
11
|
import path from 'path'
|
|
11
12
|
import { streamAgentChat } from '@/lib/server/chat-execution/stream-agent-chat'
|
|
@@ -22,7 +23,10 @@ import {
|
|
|
22
23
|
resolveApiKey as resolveApiKeyHelper,
|
|
23
24
|
} from '@/lib/server/chatrooms/chatroom-helpers'
|
|
24
25
|
import { filterHealthyChatroomAgents } from '@/lib/server/chatrooms/chatroom-health'
|
|
25
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
ensureChatroomRoutingGuidance,
|
|
28
|
+
selectChatroomRecipients,
|
|
29
|
+
} from '@/lib/server/chatrooms/chatroom-routing'
|
|
26
30
|
import { markProviderFailure, markProviderSuccess } from '../provider-health'
|
|
27
31
|
import { buildIdentityContinuityContext } from '../identity-continuity'
|
|
28
32
|
import { buildRuntimeSkillPromptBlocks, resolveRuntimeSkills } from '@/lib/server/skills/runtime-skill-resolver'
|
|
@@ -630,11 +634,14 @@ async function routeMessageToChatroom(connector: Connector, msg: InboundMessage)
|
|
|
630
634
|
const threadContextBlock = buildConnectorThreadContextBlock(msg)
|
|
631
635
|
|
|
632
636
|
// Parse mentions from the message text
|
|
637
|
+
ensureChatroomRoutingGuidance(chatroom, agents)
|
|
633
638
|
let mentions = parseMentions(msg.text || '', agents, chatroom.agentIds)
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
639
|
+
if (mentions.length === 0 && !chatroom.autoAddress) {
|
|
640
|
+
mentions = await selectChatroomRecipients({
|
|
641
|
+
text: msg.text || '',
|
|
642
|
+
chatroom,
|
|
643
|
+
agentsById: agents,
|
|
644
|
+
})
|
|
638
645
|
}
|
|
639
646
|
// Auto-address: if enabled and still no mentions, address all agents
|
|
640
647
|
if (chatroom.autoAddress && mentions.length === 0) {
|
|
@@ -1245,7 +1252,7 @@ If media sending fails, report the exact error and retry with a corrected path/t
|
|
|
1245
1252
|
}
|
|
1246
1253
|
}
|
|
1247
1254
|
},
|
|
1248
|
-
history: modelHistoryTailWithAttribution(session.
|
|
1255
|
+
history: modelHistoryTailWithAttribution(getMessages(session.id), 50, 48_000),
|
|
1249
1256
|
})
|
|
1250
1257
|
settledConnectorToolEvents = [
|
|
1251
1258
|
...pruneIncompleteToolEvents(streamedConnectorToolEvents),
|
|
@@ -1300,7 +1307,7 @@ If media sending fails, report the exact error and retry with a corrected path/t
|
|
|
1300
1307
|
}
|
|
1301
1308
|
},
|
|
1302
1309
|
active: new Map(),
|
|
1303
|
-
loadHistory: () => modelHistoryTailWithAttribution(session.
|
|
1310
|
+
loadHistory: () => modelHistoryTailWithAttribution(getMessages(session.id), 50, 48_000),
|
|
1304
1311
|
})
|
|
1305
1312
|
mediaExtractionText = fullText
|
|
1306
1313
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
loadConnectors,
|
|
4
4
|
loadSession, upsertSession,
|
|
5
5
|
} from '../storage'
|
|
6
|
+
import { getMessages, replaceMessageAt } from '@/lib/server/messages/message-repository'
|
|
6
7
|
import { errorMessage } from '@/lib/shared-utils'
|
|
7
8
|
import path from 'path'
|
|
8
9
|
import { notify } from '../ws-hub'
|
|
@@ -247,7 +248,7 @@ export async function sendConnectorMessage(params: {
|
|
|
247
248
|
lastOutboundAt: Date.now(),
|
|
248
249
|
lastOutboundMessageId: result?.messageId || session.connectorContext?.lastOutboundMessageId || null,
|
|
249
250
|
}
|
|
250
|
-
const history =
|
|
251
|
+
const history = getMessages(session.id)
|
|
251
252
|
for (let i = history.length - 1; i >= 0; i -= 1) {
|
|
252
253
|
const entry = history[i]
|
|
253
254
|
if (entry?.role !== 'assistant') continue
|
|
@@ -255,17 +256,21 @@ export async function sendConnectorMessage(params: {
|
|
|
255
256
|
if (source.connectorId !== connectorId) continue
|
|
256
257
|
if (source.channelId !== channelId) continue
|
|
257
258
|
if (!source.messageId && result?.messageId) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
259
|
+
const updatedEntry = {
|
|
260
|
+
...entry,
|
|
261
|
+
source: {
|
|
262
|
+
platform: source.platform || connector.platform,
|
|
263
|
+
connectorId: source.connectorId || connectorId,
|
|
264
|
+
connectorName: source.connectorName || connector.name,
|
|
265
|
+
channelId: source.channelId || channelId,
|
|
266
|
+
senderId: source.senderId,
|
|
267
|
+
senderName: source.senderName,
|
|
268
|
+
messageId: result.messageId,
|
|
269
|
+
threadId: source.threadId || params.threadId,
|
|
270
|
+
replyToMessageId: source.replyToMessageId || params.replyToMessageId,
|
|
271
|
+
},
|
|
268
272
|
}
|
|
273
|
+
replaceMessageAt(session.id, i, updatedEntry)
|
|
269
274
|
}
|
|
270
275
|
break
|
|
271
276
|
}
|