@swarmclawai/swarmclaw 1.2.3 → 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 +20 -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]/models/route.test.ts +60 -0
- package/src/app/api/providers/[id]/models/route.ts +33 -1
- package/src/app/api/providers/[id]/route.test.ts +49 -0
- package/src/app/api/providers/[id]/route.ts +30 -1
- 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 +51 -25
- package/src/components/agents/inspector-panel.tsx +15 -4
- package/src/components/auth/setup-wizard/index.tsx +27 -18
- package/src/components/auth/setup-wizard/shared.tsx +2 -2
- package/src/components/auth/setup-wizard/step-agents.tsx +51 -38
- package/src/components/auth/setup-wizard/step-connect.tsx +48 -17
- package/src/components/auth/setup-wizard/types.ts +6 -4
- package/src/components/auth/setup-wizard/utils.test.ts +38 -8
- package/src/components/auth/setup-wizard/utils.ts +14 -8
- 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 +150 -77
- package/src/components/providers/provider-sheet.tsx +102 -77
- package/src/components/shared/model-combobox.tsx +5 -4
- 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/agent-provider-options.test.ts +152 -0
- package/src/lib/agent-provider-options.ts +84 -0
- package/src/lib/app/api-client.ts +2 -2
- package/src/lib/providers/index.test.ts +78 -0
- package/src/lib/providers/index.ts +13 -10
- package/src/lib/query/client.ts +17 -0
- package/src/lib/server/agents/agent-runtime-config.ts +6 -6
- 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 +42 -215
- package/src/lib/server/storage-normalization.ts +98 -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 +288 -22
- package/src/views/settings/section-providers.tsx +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AppSettings } from '@/types'
|
|
2
2
|
import { dedup } from '@/lib/shared-utils'
|
|
3
|
-
import { getToolsForCapability,
|
|
3
|
+
import { getToolsForCapability, TOOL_CAPABILITY } from './tool-planning'
|
|
4
|
+
import type { MessageClassification } from '@/lib/server/chat-execution/message-classifier'
|
|
4
5
|
|
|
5
6
|
export type TaskIntent =
|
|
6
7
|
| 'coding'
|
|
@@ -25,38 +26,10 @@ function findFirstUrl(text: string): string | undefined {
|
|
|
25
26
|
return m?.[0]
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
function containsAny(text: string, terms: string[]): boolean {
|
|
29
|
-
return terms.some((term) => text.includes(term))
|
|
30
|
-
}
|
|
31
|
-
|
|
32
29
|
function dedupe(values: string[]): string[] {
|
|
33
30
|
return dedup(values.filter(Boolean))
|
|
34
31
|
}
|
|
35
32
|
|
|
36
|
-
function isMonitoringOrCurrentEventsRequest(text: string): boolean {
|
|
37
|
-
const normalized = text.toLowerCase()
|
|
38
|
-
if (!normalized.trim()) return false
|
|
39
|
-
return containsAny(normalized, [
|
|
40
|
-
'latest',
|
|
41
|
-
'news',
|
|
42
|
-
'headline',
|
|
43
|
-
'current event',
|
|
44
|
-
'recent update',
|
|
45
|
-
'recent updates',
|
|
46
|
-
'update me',
|
|
47
|
-
'updates',
|
|
48
|
-
'breaking',
|
|
49
|
-
'developments',
|
|
50
|
-
'keep watching',
|
|
51
|
-
'watch for',
|
|
52
|
-
'watching for',
|
|
53
|
-
'monitor',
|
|
54
|
-
'track',
|
|
55
|
-
'follow the situation',
|
|
56
|
-
'tell me if anything changes',
|
|
57
|
-
])
|
|
58
|
-
}
|
|
59
|
-
|
|
60
33
|
function preferredToolsForCapabilities(enabledExtensions: string[], capabilities: string[], fallback: string[] = []): string[] {
|
|
61
34
|
const preferred = capabilities.flatMap((capability) => getToolsForCapability(enabledExtensions, capability))
|
|
62
35
|
return dedupe(preferred.length > 0 ? preferred : fallback)
|
|
@@ -90,68 +63,36 @@ export function routeTaskIntent(
|
|
|
90
63
|
message: string,
|
|
91
64
|
enabledExtensions: string[],
|
|
92
65
|
settings?: AppSettings | null,
|
|
66
|
+
classification?: MessageClassification | null,
|
|
93
67
|
): CapabilityRoutingDecision {
|
|
94
|
-
const text = (message || '').toLowerCase()
|
|
95
68
|
const url = findFirstUrl(message || '')
|
|
96
69
|
const delegateOrder = normalizeDelegateOrder(settings?.autonomyPreferredDelegates)
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
const researchLike = matchedCapabilities.has(TOOL_CAPABILITY.researchSearch)
|
|
103
|
-
|| matchedCapabilities.has(TOOL_CAPABILITY.researchFetch)
|
|
104
|
-
|| isMonitoringOrCurrentEventsRequest(text)
|
|
105
|
-
|| !!url
|
|
70
|
+
const intent = classification?.taskIntent || 'general'
|
|
71
|
+
const confidence = classification?.confidence ?? 0
|
|
72
|
+
const wantsVoiceDelivery = classification?.wantsVoiceDelivery === true
|
|
73
|
+
const wantsScreenshots = classification?.wantsScreenshots === true
|
|
74
|
+
const wantsOutboundDelivery = classification?.wantsOutboundDelivery === true
|
|
106
75
|
|
|
107
|
-
|
|
108
|
-
'build',
|
|
109
|
-
'implement',
|
|
110
|
-
'create app',
|
|
111
|
-
'refactor',
|
|
112
|
-
'fix bug',
|
|
113
|
-
'write code',
|
|
114
|
-
'codebase',
|
|
115
|
-
'typescript',
|
|
116
|
-
'javascript',
|
|
117
|
-
'react',
|
|
118
|
-
'next.js',
|
|
119
|
-
'unit test',
|
|
120
|
-
'run tests',
|
|
121
|
-
'compile',
|
|
122
|
-
'npm ',
|
|
123
|
-
'pnpm ',
|
|
124
|
-
'yarn ',
|
|
125
|
-
])
|
|
126
|
-
if (coding) {
|
|
76
|
+
if (intent === 'coding') {
|
|
127
77
|
return {
|
|
128
78
|
intent: 'coding',
|
|
129
|
-
confidence
|
|
79
|
+
confidence,
|
|
130
80
|
preferredTools: ['claude_code', 'codex_cli', 'opencode_cli', 'shell', 'files', 'edit_file'],
|
|
131
81
|
preferredDelegates: delegateOrder,
|
|
132
82
|
primaryUrl: url,
|
|
133
83
|
}
|
|
134
84
|
}
|
|
135
85
|
|
|
136
|
-
|
|
137
|
-
'send update',
|
|
138
|
-
'message',
|
|
139
|
-
'whatsapp',
|
|
140
|
-
'telegram',
|
|
141
|
-
'slack',
|
|
142
|
-
'discord',
|
|
143
|
-
'notify',
|
|
144
|
-
'broadcast',
|
|
145
|
-
]) || (!researchLike && (wantsVoiceNote || wantsMediaDelivery || wantsChannelDelivery))
|
|
146
|
-
if (outreach) {
|
|
86
|
+
if (intent === 'outreach') {
|
|
147
87
|
return {
|
|
148
88
|
intent: 'outreach',
|
|
149
|
-
confidence
|
|
89
|
+
confidence,
|
|
150
90
|
preferredTools: preferredToolsForCapabilities(
|
|
151
91
|
enabledExtensions,
|
|
152
92
|
[
|
|
153
|
-
TOOL_CAPABILITY.deliveryVoiceNote,
|
|
154
|
-
TOOL_CAPABILITY.deliveryMedia,
|
|
93
|
+
...(wantsVoiceDelivery ? [TOOL_CAPABILITY.deliveryVoiceNote] : []),
|
|
94
|
+
...(wantsScreenshots ? [TOOL_CAPABILITY.deliveryMedia] : []),
|
|
95
|
+
...(wantsOutboundDelivery || wantsVoiceDelivery ? [TOOL_CAPABILITY.deliveryMessage] : []),
|
|
155
96
|
TOOL_CAPABILITY.deliveryMessage,
|
|
156
97
|
],
|
|
157
98
|
['connector_message_tool', 'manage_connectors', 'manage_sessions'],
|
|
@@ -161,35 +102,20 @@ export function routeTaskIntent(
|
|
|
161
102
|
}
|
|
162
103
|
}
|
|
163
104
|
|
|
164
|
-
|
|
165
|
-
'schedule',
|
|
166
|
-
'every day',
|
|
167
|
-
'every week',
|
|
168
|
-
'cron',
|
|
169
|
-
'recurring',
|
|
170
|
-
'remind',
|
|
171
|
-
'follow up tomorrow',
|
|
172
|
-
]) && !researchLike
|
|
173
|
-
if (scheduling) {
|
|
105
|
+
if (intent === 'scheduling') {
|
|
174
106
|
return {
|
|
175
107
|
intent: 'scheduling',
|
|
176
|
-
confidence
|
|
108
|
+
confidence,
|
|
177
109
|
preferredTools: ['manage_schedules', 'manage_tasks'],
|
|
178
110
|
preferredDelegates: delegateOrder,
|
|
179
111
|
primaryUrl: url,
|
|
180
112
|
}
|
|
181
113
|
}
|
|
182
114
|
|
|
183
|
-
|
|
184
|
-
matchedCapabilities.has(TOOL_CAPABILITY.browserNavigate)
|
|
185
|
-
|| matchedCapabilities.has(TOOL_CAPABILITY.browserCapture)
|
|
186
|
-
|| getToolsForCapability(enabledExtensions, TOOL_CAPABILITY.browserNavigate).length > 0
|
|
187
|
-
|| getToolsForCapability(enabledExtensions, TOOL_CAPABILITY.browserCapture).length > 0
|
|
188
|
-
)
|
|
189
|
-
if (browsing) {
|
|
115
|
+
if (intent === 'browsing') {
|
|
190
116
|
return {
|
|
191
117
|
intent: 'browsing',
|
|
192
|
-
confidence
|
|
118
|
+
confidence,
|
|
193
119
|
preferredTools: preferredToolsForCapabilities(
|
|
194
120
|
enabledExtensions,
|
|
195
121
|
[
|
|
@@ -204,22 +130,21 @@ export function routeTaskIntent(
|
|
|
204
130
|
}
|
|
205
131
|
}
|
|
206
132
|
|
|
207
|
-
|
|
208
|
-
if (research) {
|
|
133
|
+
if (intent === 'research') {
|
|
209
134
|
const preferred = preferredToolsForCapabilities(
|
|
210
135
|
enabledExtensions,
|
|
211
136
|
[
|
|
212
137
|
TOOL_CAPABILITY.researchSearch,
|
|
213
138
|
TOOL_CAPABILITY.researchFetch,
|
|
214
139
|
...(wantsScreenshots ? [TOOL_CAPABILITY.browserCapture] : []),
|
|
215
|
-
...(
|
|
216
|
-
...(
|
|
140
|
+
...(wantsVoiceDelivery ? [TOOL_CAPABILITY.deliveryVoiceNote] : []),
|
|
141
|
+
...(wantsOutboundDelivery ? [TOOL_CAPABILITY.deliveryMedia, TOOL_CAPABILITY.deliveryMessage] : []),
|
|
217
142
|
],
|
|
218
143
|
['web_search', 'web_fetch', 'browser'],
|
|
219
144
|
)
|
|
220
145
|
return {
|
|
221
146
|
intent: 'research',
|
|
222
|
-
confidence
|
|
147
|
+
confidence,
|
|
223
148
|
preferredTools: preferred,
|
|
224
149
|
preferredDelegates: delegateOrder,
|
|
225
150
|
primaryUrl: url,
|
|
@@ -228,7 +153,7 @@ export function routeTaskIntent(
|
|
|
228
153
|
|
|
229
154
|
return {
|
|
230
155
|
intent: 'general',
|
|
231
|
-
confidence
|
|
156
|
+
confidence,
|
|
232
157
|
preferredTools: [],
|
|
233
158
|
preferredDelegates: delegateOrder,
|
|
234
159
|
primaryUrl: url,
|
|
@@ -398,21 +398,6 @@ export function findFirstUrl(text: string): string | null {
|
|
|
398
398
|
return match?.[0] || null
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
export function isMemoryListIntent(message: string): boolean {
|
|
402
|
-
const text = message.toLowerCase()
|
|
403
|
-
if (!/\bmemory|memories|remember\b/.test(text)) return false
|
|
404
|
-
if (/\b(save|store|memorize|add to memory|write to memory|remember this)\b/.test(text)) return false
|
|
405
|
-
if (/\bmemory_tool\b/.test(text)) return true
|
|
406
|
-
return (
|
|
407
|
-
/\blist\b[\s\w]{0,24}\bmemories\b/.test(text)
|
|
408
|
-
|| /\bshow\b[\s\w]{0,24}\bmemories\b/.test(text)
|
|
409
|
-
|| /\bget\b[\s\w]{0,24}\bmemories\b/.test(text)
|
|
410
|
-
|| /\bwhat\b[\s\w]{0,40}\bmemories\b/.test(text)
|
|
411
|
-
|| /\bwhat do you remember\b/.test(text)
|
|
412
|
-
|| /\brecall\b[\s\w]{0,24}\bmemories?\b/.test(text)
|
|
413
|
-
)
|
|
414
|
-
}
|
|
415
|
-
|
|
416
401
|
export function extractDelegationTask(message: string, toolName: string): string | null {
|
|
417
402
|
if (!message.toLowerCase().includes(toolName.toLowerCase())) return null
|
|
418
403
|
const patterns = [
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { MessageToolEvent } from '@/types'
|
|
2
2
|
import { canonicalizeExtensionId } from '@/lib/server/tool-aliases'
|
|
3
3
|
import { extractSuggestions } from '@/lib/server/suggestions'
|
|
4
|
-
import {
|
|
5
|
-
looksLikeExternalWalletTask,
|
|
6
|
-
} from '@/lib/server/chat-execution/stream-continuation'
|
|
7
4
|
import type { MessageClassification } from '@/lib/server/chat-execution/message-classifier'
|
|
8
5
|
import {
|
|
9
6
|
buildSuccessfulMemoryMutationResponse,
|
|
@@ -82,7 +79,8 @@ export function shouldForceExternalServiceSummary(params: {
|
|
|
82
79
|
toolEventCount: number
|
|
83
80
|
classification?: MessageClassification | null
|
|
84
81
|
}): boolean {
|
|
85
|
-
const walletDetected = params.classification
|
|
82
|
+
const walletDetected = params.classification?.walletIntent !== undefined
|
|
83
|
+
&& params.classification.walletIntent !== 'none'
|
|
86
84
|
if (!walletDetected) return false
|
|
87
85
|
if (!params.hasToolCalls || params.toolEventCount === 0) return false
|
|
88
86
|
const trimmed = params.finalResponse.trim()
|
|
@@ -34,8 +34,16 @@ import { isHeartbeatSource } from '@/lib/server/runtime/heartbeat-source'
|
|
|
34
34
|
import { perf } from '@/lib/server/runtime/perf'
|
|
35
35
|
import { getAgent } from '@/lib/server/agents/agent-repository'
|
|
36
36
|
import { isDirectConnectorSession } from '@/lib/server/connectors/session-kind'
|
|
37
|
-
import { getSession,
|
|
37
|
+
import { getSession, saveSession } from '@/lib/server/sessions/session-repository'
|
|
38
|
+
import {
|
|
39
|
+
getMessages,
|
|
40
|
+
getMessageCount,
|
|
41
|
+
appendMessage,
|
|
42
|
+
replaceMessageAt,
|
|
43
|
+
replaceAllMessages,
|
|
44
|
+
} from '@/lib/server/messages/message-repository'
|
|
38
45
|
import { appendUsage } from '@/lib/server/usage/usage-repository'
|
|
46
|
+
import { synchronizeWorkingStateForTurn } from '@/lib/server/working-state/service'
|
|
39
47
|
import { notify } from '@/lib/server/ws-hub'
|
|
40
48
|
|
|
41
49
|
import type { ExecuteChatTurnInput, ExecuteChatTurnResult } from './chat-execution-types'
|
|
@@ -193,7 +201,7 @@ export async function finalizeChatTurn(params: {
|
|
|
193
201
|
const totalTokens = inputTokens + outputTokens
|
|
194
202
|
if (totalTokens > 0) {
|
|
195
203
|
const cost = estimateCost(sessionForRun.model, inputTokens, outputTokens)
|
|
196
|
-
const history =
|
|
204
|
+
const history = getMessages(sessionId)
|
|
197
205
|
const usageRecord: UsageRecord = {
|
|
198
206
|
sessionId,
|
|
199
207
|
messageIndex: history.length,
|
|
@@ -354,15 +362,17 @@ export async function finalizeChatTurn(params: {
|
|
|
354
362
|
const current = getSession(sessionId)
|
|
355
363
|
let assistantPersisted = false
|
|
356
364
|
if (current) {
|
|
357
|
-
|
|
365
|
+
// Load messages from relational table (lazy-migrates from blob on first access)
|
|
366
|
+
const messages = getMessages(sessionId)
|
|
367
|
+
let messagesPruned = false
|
|
358
368
|
if (!isDirectConnectorSession(current) && current.connectorContext) {
|
|
359
369
|
current.connectorContext = undefined
|
|
360
370
|
}
|
|
361
371
|
const currentAgent = current.agentId ? getAgent(current.agentId) : null
|
|
362
|
-
pruneStreamingAssistantArtifacts(
|
|
372
|
+
if (pruneStreamingAssistantArtifacts(messages, {
|
|
363
373
|
minIndex: runMessageStartIndex,
|
|
364
374
|
minTime: runStartedAt,
|
|
365
|
-
})
|
|
375
|
+
})) messagesPruned = true
|
|
366
376
|
const persistField = (key: string, value: unknown) => {
|
|
367
377
|
const normalized = normalizeResumeId(value)
|
|
368
378
|
if ((current as unknown as Record<string, unknown>)[key] !== normalized) {
|
|
@@ -392,6 +402,8 @@ export async function finalizeChatTurn(params: {
|
|
|
392
402
|
}
|
|
393
403
|
}
|
|
394
404
|
|
|
405
|
+
let persistedAssistantMsg: Message | null = null
|
|
406
|
+
let replacedLast = false
|
|
395
407
|
if (shouldPersistAssistant) {
|
|
396
408
|
const persistedKind = isHeartbeatRun ? 'heartbeat' : 'chat'
|
|
397
409
|
const nowTs = Date.now()
|
|
@@ -410,7 +422,7 @@ export async function finalizeChatTurn(params: {
|
|
|
410
422
|
runId: lifecycleRunId,
|
|
411
423
|
})
|
|
412
424
|
if (nextAssistantMessage) {
|
|
413
|
-
const previous =
|
|
425
|
+
const previous = messages.at(-1)
|
|
414
426
|
const nextToolEvents = nextAssistantMessage.toolEvents || []
|
|
415
427
|
const nextKind = nextAssistantMessage.kind || persistedKind
|
|
416
428
|
if (shouldSuppressRedundantConnectorDeliveryFollowup({
|
|
@@ -433,11 +445,14 @@ export async function finalizeChatTurn(params: {
|
|
|
433
445
|
nextKind,
|
|
434
446
|
now: nowTs,
|
|
435
447
|
})) {
|
|
436
|
-
|
|
448
|
+
messages[messages.length - 1] = nextAssistantMessage
|
|
437
449
|
assistantPersisted = true
|
|
450
|
+
replacedLast = true
|
|
451
|
+
persistedAssistantMsg = nextAssistantMessage
|
|
438
452
|
} else {
|
|
439
|
-
|
|
453
|
+
messages.push(nextAssistantMessage)
|
|
440
454
|
assistantPersisted = true
|
|
455
|
+
persistedAssistantMsg = nextAssistantMessage
|
|
441
456
|
}
|
|
442
457
|
persistedResponseForHooks = nextAssistantMessage.text
|
|
443
458
|
if (assistantPersisted) {
|
|
@@ -534,16 +549,28 @@ export async function finalizeChatTurn(params: {
|
|
|
534
549
|
}
|
|
535
550
|
}
|
|
536
551
|
if (isHeartbeatRun && heartbeatClassification === 'suppress') {
|
|
537
|
-
pruneSuppressedHeartbeatStreamMessage(
|
|
552
|
+
if (pruneSuppressedHeartbeatStreamMessage(messages)) messagesPruned = true
|
|
538
553
|
}
|
|
539
554
|
|
|
540
555
|
if (isHeartbeatRun) {
|
|
541
|
-
const pruned = pruneOldHeartbeatMessages(
|
|
556
|
+
const pruned = pruneOldHeartbeatMessages(messages)
|
|
542
557
|
if (pruned > 0) {
|
|
558
|
+
messagesPruned = true
|
|
543
559
|
log.info('heartbeat', `Pruned ${pruned} old heartbeat message(s) from session ${sessionId}`)
|
|
544
560
|
}
|
|
545
561
|
}
|
|
546
562
|
|
|
563
|
+
// Persist messages: use O(1) append/replace when no pruning, O(n) replaceAll when pruned
|
|
564
|
+
if (messagesPruned) {
|
|
565
|
+
replaceAllMessages(sessionId, messages)
|
|
566
|
+
} else if (assistantPersisted && persistedAssistantMsg) {
|
|
567
|
+
if (replacedLast) {
|
|
568
|
+
replaceMessageAt(sessionId, getMessageCount(sessionId) - 1, persistedAssistantMsg)
|
|
569
|
+
} else {
|
|
570
|
+
appendMessage(sessionId, persistedAssistantMsg)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
547
574
|
try {
|
|
548
575
|
await runCapabilityHook('afterChatTurn', {
|
|
549
576
|
session: current,
|
|
@@ -563,8 +590,9 @@ export async function finalizeChatTurn(params: {
|
|
|
563
590
|
|
|
564
591
|
refreshSessionIdentityState(current, currentAgent)
|
|
565
592
|
let resolvedMissionId = mission?.id || current.missionId || null
|
|
593
|
+
let updatedMission = mission || null
|
|
566
594
|
if (resolvedMissionId) {
|
|
567
|
-
|
|
595
|
+
updatedMission = await applyMissionOutcomeForTurn({
|
|
568
596
|
session: current,
|
|
569
597
|
missionId: resolvedMissionId,
|
|
570
598
|
source,
|
|
@@ -579,6 +607,43 @@ export async function finalizeChatTurn(params: {
|
|
|
579
607
|
current.missionId = updatedMission.id
|
|
580
608
|
}
|
|
581
609
|
}
|
|
610
|
+
const missionStateChanged = Boolean(
|
|
611
|
+
updatedMission
|
|
612
|
+
&& (
|
|
613
|
+
updatedMission.id !== mission?.id
|
|
614
|
+
|| updatedMission.updatedAt !== mission?.updatedAt
|
|
615
|
+
|| updatedMission.status !== mission?.status
|
|
616
|
+
|| updatedMission.phase !== mission?.phase
|
|
617
|
+
|| updatedMission.currentStep !== mission?.currentStep
|
|
618
|
+
|| updatedMission.waitState?.reason !== mission?.waitState?.reason
|
|
619
|
+
)
|
|
620
|
+
)
|
|
621
|
+
const shouldSyncWorkingState = (
|
|
622
|
+
(!isHeartbeatRun && (assistantPersisted || persistedToolEvents.length > 0 || Boolean(errorMessage)))
|
|
623
|
+
|| (isHeartbeatRun && (persistedToolEvents.length > 0 || Boolean(errorMessage) || missionStateChanged))
|
|
624
|
+
)
|
|
625
|
+
if (shouldSyncWorkingState) {
|
|
626
|
+
try {
|
|
627
|
+
await synchronizeWorkingStateForTurn({
|
|
628
|
+
sessionId,
|
|
629
|
+
agentId: current.agentId || null,
|
|
630
|
+
mission: updatedMission,
|
|
631
|
+
message,
|
|
632
|
+
assistantText: hiddenControlOnly ? '' : textForPersistence,
|
|
633
|
+
error: errorMessage || null,
|
|
634
|
+
toolEvents: persistedToolEvents,
|
|
635
|
+
runId: lifecycleRunId,
|
|
636
|
+
source,
|
|
637
|
+
})
|
|
638
|
+
} catch (workingStateError: unknown) {
|
|
639
|
+
log.warn('chat-run', `Working-state sync failed for session ${sessionId}`, {
|
|
640
|
+
runId: lifecycleRunId,
|
|
641
|
+
error: typeof workingStateError === 'object' && workingStateError !== null && 'message' in workingStateError
|
|
642
|
+
? (workingStateError as Error).message
|
|
643
|
+
: String(workingStateError),
|
|
644
|
+
})
|
|
645
|
+
}
|
|
646
|
+
}
|
|
582
647
|
try {
|
|
583
648
|
syncSessionArchiveMemory(current, { agent: currentAgent })
|
|
584
649
|
} catch {
|
|
@@ -591,7 +656,7 @@ export async function finalizeChatTurn(params: {
|
|
|
591
656
|
isHeartbeatRun,
|
|
592
657
|
agentAutoDraftSetting: currentAgent?.autoDraftSkillSuggestions === true,
|
|
593
658
|
toolEventCount: persistedToolEvents.length,
|
|
594
|
-
messageCount:
|
|
659
|
+
messageCount: messages.length,
|
|
595
660
|
})) {
|
|
596
661
|
try {
|
|
597
662
|
const { createSkillSuggestionFromSession } = await import('@/lib/server/skills/skill-suggestions')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSession,
|
|
3
|
-
saveSession,
|
|
4
3
|
} from '@/lib/server/sessions/session-repository'
|
|
4
|
+
import { getMessages, replaceAllMessages } from '@/lib/server/messages/message-repository'
|
|
5
5
|
import { notify } from '@/lib/server/ws-hub'
|
|
6
6
|
import type { MessageToolEvent, SSEEvent } from '@/types'
|
|
7
7
|
import { upsertStreamingAssistantArtifact } from '@/lib/chat/chat-streaming-state'
|
|
@@ -72,7 +72,7 @@ export function createPartialAssistantPersistence(input: {
|
|
|
72
72
|
try {
|
|
73
73
|
const current = getSession(prepared.sessionId)
|
|
74
74
|
if (!current) return
|
|
75
|
-
|
|
75
|
+
const currentMessages = getMessages(prepared.sessionId)
|
|
76
76
|
const partialMsg = await applyMessageLifecycleHooks({
|
|
77
77
|
session: current,
|
|
78
78
|
message: {
|
|
@@ -98,11 +98,11 @@ export function createPartialAssistantPersistence(input: {
|
|
|
98
98
|
if (snapshotKey === lastPartialSnapshotKey) return
|
|
99
99
|
lastPartialSnapshotKey = snapshotKey
|
|
100
100
|
lastPartialSaveAt = Date.now()
|
|
101
|
-
upsertStreamingAssistantArtifact(
|
|
101
|
+
upsertStreamingAssistantArtifact(currentMessages, partialMsg, {
|
|
102
102
|
minIndex: prepared.runMessageStartIndex,
|
|
103
103
|
minTime: prepared.runStartedAt,
|
|
104
104
|
})
|
|
105
|
-
|
|
105
|
+
replaceAllMessages(prepared.sessionId, currentMessages)
|
|
106
106
|
notify(`messages:${prepared.sessionId}`)
|
|
107
107
|
} catch {
|
|
108
108
|
// Partial persistence is best-effort.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { notify } from '@/lib/server/ws-hub'
|
|
2
2
|
import { getSession, saveSession } from '@/lib/server/sessions/session-repository'
|
|
3
|
+
import { appendMessage } from '@/lib/server/messages/message-repository'
|
|
3
4
|
import type { MessageToolEvent, SSEEvent } from '@/types'
|
|
4
5
|
import type { ExecuteChatTurnResult } from './chat-execution-types'
|
|
5
6
|
import {
|
|
@@ -47,8 +48,7 @@ async function completeSyntheticAssistantTurn(params: {
|
|
|
47
48
|
isSynthetic: true,
|
|
48
49
|
})
|
|
49
50
|
if (nextAssistantMessage) {
|
|
50
|
-
|
|
51
|
-
session.messages.push(nextAssistantMessage)
|
|
51
|
+
appendMessage(params.sessionId, nextAssistantMessage)
|
|
52
52
|
session.lastActiveAt = Date.now()
|
|
53
53
|
saveSession(params.sessionId, session)
|
|
54
54
|
if (params.notifyMessages) notify(`messages:${params.sessionId}`)
|
|
@@ -2,13 +2,14 @@ import fs from 'fs'
|
|
|
2
2
|
import os from 'os'
|
|
3
3
|
|
|
4
4
|
import { getProvider } from '@/lib/providers'
|
|
5
|
-
import type { Message, Session } from '@/types'
|
|
5
|
+
import type { ExecutionBrief, Message, Session } from '@/types'
|
|
6
6
|
import {
|
|
7
7
|
decryptKey,
|
|
8
8
|
loadCredentials,
|
|
9
9
|
} from '@/lib/server/credentials/credential-repository'
|
|
10
10
|
import { getAgent } from '@/lib/server/agents/agent-repository'
|
|
11
11
|
import { getSession, saveSession } from '@/lib/server/sessions/session-repository'
|
|
12
|
+
import { getMessages, getMessageCount, appendMessage } from '@/lib/server/messages/message-repository'
|
|
12
13
|
import { loadSettings } from '@/lib/server/settings/settings-repository'
|
|
13
14
|
import { loadSkills } from '@/lib/server/skills/skill-repository'
|
|
14
15
|
import { resolveImagePath } from '@/lib/server/resolve-image'
|
|
@@ -45,7 +46,6 @@ import {
|
|
|
45
46
|
import { normalizeProviderEndpoint, isLocalOpenClawEndpoint } from '@/lib/openclaw/openclaw-endpoint'
|
|
46
47
|
import { NON_LANGGRAPH_PROVIDER_IDS } from '@/lib/provider-sets'
|
|
47
48
|
import {
|
|
48
|
-
buildMissionContextBlock,
|
|
49
49
|
resolveMissionForTurn,
|
|
50
50
|
} from '@/lib/server/missions/mission-service'
|
|
51
51
|
import {
|
|
@@ -69,7 +69,15 @@ import {
|
|
|
69
69
|
resetSessionRuntime,
|
|
70
70
|
resolveSessionResetPolicy,
|
|
71
71
|
} from '@/lib/server/session-reset-policy'
|
|
72
|
+
import {
|
|
73
|
+
buildExecutionBrief,
|
|
74
|
+
buildExecutionBriefContextBlock,
|
|
75
|
+
} from '@/lib/server/execution-brief'
|
|
72
76
|
import { checkAgentBudgetLimits } from '@/lib/server/cost'
|
|
77
|
+
import {
|
|
78
|
+
classifyMessage,
|
|
79
|
+
toMessageSemanticsSummary,
|
|
80
|
+
} from '@/lib/server/chat-execution/message-classifier'
|
|
73
81
|
import {
|
|
74
82
|
filterRuntimeCapabilityIds,
|
|
75
83
|
getTodaySpendUsd,
|
|
@@ -408,13 +416,13 @@ function resolveApiKeyForSession(session: SessionWithCredentials, provider: Prov
|
|
|
408
416
|
if (!session.credentialId) throw new Error('No API key configured for this session')
|
|
409
417
|
const creds = loadCredentials()
|
|
410
418
|
const cred = creds[session.credentialId]
|
|
411
|
-
if (!cred) throw new Error('API key not found. Please add one in Settings.')
|
|
419
|
+
if (!cred?.encryptedKey) throw new Error('API key not found. Please add one in Settings.')
|
|
412
420
|
return decryptKey(cred.encryptedKey)
|
|
413
421
|
}
|
|
414
422
|
if (provider.optionalApiKey && session.credentialId) {
|
|
415
423
|
const creds = loadCredentials()
|
|
416
424
|
const cred = creds[session.credentialId]
|
|
417
|
-
if (cred) {
|
|
425
|
+
if (cred?.encryptedKey) {
|
|
418
426
|
try { return decryptKey(cred.encryptedKey) } catch { return null }
|
|
419
427
|
}
|
|
420
428
|
}
|
|
@@ -445,7 +453,8 @@ export interface PreparedExecutableChatTurn {
|
|
|
445
453
|
lifecycleRunId: string
|
|
446
454
|
agentForSession: ReturnType<typeof getAgent>
|
|
447
455
|
mission: Awaited<ReturnType<typeof resolveMissionForTurn>>
|
|
448
|
-
|
|
456
|
+
executionBrief: ExecutionBrief
|
|
457
|
+
executionBriefContextBlock?: string
|
|
449
458
|
extensionsForRun: string[]
|
|
450
459
|
effectiveMessage: string
|
|
451
460
|
providerType: string
|
|
@@ -492,9 +501,8 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
492
501
|
|
|
493
502
|
const session = getSession(sessionId)
|
|
494
503
|
if (!session) throw new Error(`Session not found: ${sessionId}`)
|
|
495
|
-
session.messages = Array.isArray(session.messages) ? session.messages : []
|
|
496
504
|
const runStartedAt = Date.now()
|
|
497
|
-
const runMessageStartIndex =
|
|
505
|
+
const runMessageStartIndex = getMessageCount(sessionId)
|
|
498
506
|
|
|
499
507
|
const appSettings = loadSettings()
|
|
500
508
|
const lifecycleRunId = runId || `${sessionId}:${runStartedAt}`
|
|
@@ -542,7 +550,7 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
542
550
|
{
|
|
543
551
|
sessionId: session.id,
|
|
544
552
|
session,
|
|
545
|
-
messageCount:
|
|
553
|
+
messageCount: getMessageCount(sessionId),
|
|
546
554
|
durationMs: Date.now() - (session.createdAt || runStartedAt),
|
|
547
555
|
reason: freshness.reason || 'session_reset',
|
|
548
556
|
},
|
|
@@ -615,12 +623,16 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
615
623
|
if (isHeartbeatRun && input.modelOverride) {
|
|
616
624
|
sessionForRun = { ...sessionForRun, model: input.modelOverride }
|
|
617
625
|
}
|
|
618
|
-
const
|
|
626
|
+
const executionBrief = buildExecutionBrief({
|
|
627
|
+
session: sessionForRun,
|
|
628
|
+
mission,
|
|
629
|
+
})
|
|
630
|
+
const executionBriefContextBlock = buildExecutionBriefContextBlock(executionBrief)
|
|
619
631
|
|
|
620
632
|
if (extensionsForRun.length > 0) {
|
|
621
633
|
const modelResolvePrompt = heartbeatLightContext
|
|
622
|
-
? (joinSystemPromptBlocks(buildLightHeartbeatSystemPrompt(sessionForRun),
|
|
623
|
-
: (joinSystemPromptBlocks(buildAgentSystemPrompt(sessionForRun),
|
|
634
|
+
? (joinSystemPromptBlocks(buildLightHeartbeatSystemPrompt(sessionForRun), executionBriefContextBlock) || '')
|
|
635
|
+
: (joinSystemPromptBlocks(buildAgentSystemPrompt(sessionForRun), executionBriefContextBlock) || '')
|
|
624
636
|
const modelResolve = await runCapabilityBeforeModelResolve(
|
|
625
637
|
{
|
|
626
638
|
session: sessionForRun,
|
|
@@ -710,7 +722,17 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
710
722
|
|
|
711
723
|
const shouldPersistUserMessage = shouldPersistInboundUserMessage(internal, source)
|
|
712
724
|
if (shouldPersistUserMessage) {
|
|
713
|
-
const linkAnalysis =
|
|
725
|
+
const [linkAnalysis, semantics] = await Promise.all([
|
|
726
|
+
!internal ? runLinkUnderstanding(message) : Promise.resolve([]),
|
|
727
|
+
classifyMessage({
|
|
728
|
+
sessionId,
|
|
729
|
+
agentId: session.agentId || null,
|
|
730
|
+
message,
|
|
731
|
+
history: getMessages(sessionId),
|
|
732
|
+
})
|
|
733
|
+
.then((classification) => toMessageSemanticsSummary(classification))
|
|
734
|
+
.catch(() => undefined),
|
|
735
|
+
])
|
|
714
736
|
const guardedUserText = guardUntrustedText({
|
|
715
737
|
text: message,
|
|
716
738
|
source,
|
|
@@ -727,13 +749,14 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
727
749
|
imageUrl: imageUrl || undefined,
|
|
728
750
|
attachedFiles: attachedFiles?.length ? attachedFiles : undefined,
|
|
729
751
|
replyToId: input.replyToId || undefined,
|
|
752
|
+
...(semantics ? { semantics } : {}),
|
|
730
753
|
},
|
|
731
754
|
enabledIds: extensionsForRun,
|
|
732
755
|
phase: 'user',
|
|
733
756
|
runId: lifecycleRunId,
|
|
734
757
|
})
|
|
735
758
|
if (nextUserMessage) {
|
|
736
|
-
|
|
759
|
+
appendMessage(sessionId, nextUserMessage)
|
|
737
760
|
if (linkAnalysis.length > 0) {
|
|
738
761
|
const linkAnalysisMessage = await applyMessageLifecycleHooks({
|
|
739
762
|
session,
|
|
@@ -749,7 +772,7 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
749
772
|
isSynthetic: true,
|
|
750
773
|
})
|
|
751
774
|
if (linkAnalysisMessage) {
|
|
752
|
-
|
|
775
|
+
appendMessage(sessionId, linkAnalysisMessage)
|
|
753
776
|
}
|
|
754
777
|
}
|
|
755
778
|
session.lastActiveAt = Date.now()
|
|
@@ -781,8 +804,8 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
781
804
|
&& !useLocalOpenClawNativeRuntime
|
|
782
805
|
|
|
783
806
|
const systemPrompt = heartbeatLightContext
|
|
784
|
-
? joinSystemPromptBlocks(buildLightHeartbeatSystemPrompt(sessionForRun),
|
|
785
|
-
: (hasExtensions ? undefined : joinSystemPromptBlocks(buildAgentSystemPrompt(sessionForRun),
|
|
807
|
+
? joinSystemPromptBlocks(buildLightHeartbeatSystemPrompt(sessionForRun), executionBriefContextBlock)
|
|
808
|
+
: (hasExtensions ? undefined : joinSystemPromptBlocks(buildAgentSystemPrompt(sessionForRun), executionBriefContextBlock))
|
|
786
809
|
|
|
787
810
|
return {
|
|
788
811
|
kind: 'ready',
|
|
@@ -797,7 +820,8 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
797
820
|
lifecycleRunId,
|
|
798
821
|
agentForSession,
|
|
799
822
|
mission,
|
|
800
|
-
|
|
823
|
+
executionBrief,
|
|
824
|
+
executionBriefContextBlock: executionBriefContextBlock || undefined,
|
|
801
825
|
extensionsForRun,
|
|
802
826
|
effectiveMessage,
|
|
803
827
|
providerType,
|
|
@@ -74,7 +74,8 @@ export async function executePreparedChatTurn(params: {
|
|
|
74
74
|
resolvedImagePath,
|
|
75
75
|
heartbeatLightContext,
|
|
76
76
|
isAutoRunNoHistory,
|
|
77
|
-
|
|
77
|
+
executionBrief,
|
|
78
|
+
executionBriefContextBlock,
|
|
78
79
|
} = prepared
|
|
79
80
|
|
|
80
81
|
const emit = partialPersistence.emit
|
|
@@ -144,7 +145,8 @@ export async function executePreparedChatTurn(params: {
|
|
|
144
145
|
attachedFiles,
|
|
145
146
|
apiKey,
|
|
146
147
|
systemPrompt,
|
|
147
|
-
|
|
148
|
+
executionBrief,
|
|
149
|
+
extraSystemContext: [executionBriefContextBlock].filter((value): value is string => typeof value === 'string' && value.trim().length > 0),
|
|
148
150
|
write: (raw) => parseAndEmit(raw),
|
|
149
151
|
history: heartbeatHistory ?? applyContextClearBoundary(getSessionMessages(sessionId)),
|
|
150
152
|
signal: abortController.signal,
|