@swarmclawai/swarmclaw 1.2.5 → 1.2.8
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 +24 -17
- package/next.config.ts +1 -0
- package/package.json +3 -2
- package/scripts/easy-setup.mjs +1 -1
- package/scripts/postinstall.mjs +1 -1
- package/skills/swarmclaw.md +115 -0
- package/skills/tools/browser.md +131 -0
- package/skills/tools/execute.md +98 -0
- package/skills/tools/files.md +98 -0
- package/skills/tools/memory.md +104 -0
- package/skills/tools/platform.md +144 -0
- package/skills/tools/skills.md +83 -0
- package/src/app/api/chats/[id]/messages/route.ts +23 -19
- package/src/app/api/chats/messages-route.test.ts +105 -51
- package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
- package/src/app/api/openclaw/deploy/route.ts +2 -0
- package/src/app/api/setup/check-provider/route.ts +10 -2
- package/src/app/api/setup/doctor/route.ts +4 -4
- package/src/components/agents/agent-chat-list.tsx +23 -1
- package/src/components/agents/inspector-panel.tsx +165 -48
- package/src/components/chat/chat-area.tsx +38 -9
- package/src/components/chat/message-list.tsx +33 -19
- package/src/components/gateways/gateway-sheet.tsx +5 -2
- package/src/lib/agent-execute-defaults.test.ts +24 -0
- package/src/lib/agent-execute-defaults.ts +62 -0
- package/src/lib/chat/queued-message-queue.test.ts +134 -1
- package/src/lib/chat/queued-message-queue.ts +77 -2
- package/src/lib/providers/index.test.ts +108 -0
- package/src/lib/providers/index.ts +38 -15
- package/src/lib/server/agents/agent-service.ts +5 -0
- package/src/lib/server/builtin-extensions.ts +1 -0
- package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +1 -0
- package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -2
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +79 -42
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
- package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
- package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
- package/src/lib/server/chat-execution/message-classifier.ts +11 -1
- package/src/lib/server/chat-execution/prompt-builder.test.ts +28 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +14 -1
- package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
- package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
- package/src/lib/server/chat-execution/stream-agent-chat.test.ts +6 -4
- package/src/lib/server/chat-execution/stream-agent-chat.ts +45 -16
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
- package/src/lib/server/connectors/discord.ts +2 -2
- package/src/lib/server/connectors/matrix.ts +3 -2
- package/src/lib/server/connectors/signal.ts +5 -4
- package/src/lib/server/connectors/slack.ts +10 -9
- package/src/lib/server/connectors/teams.ts +3 -2
- package/src/lib/server/connectors/telegram.ts +4 -4
- package/src/lib/server/connectors/whatsapp.ts +2 -2
- package/src/lib/server/daemon/controller.ts +7 -0
- package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
- package/src/lib/server/messages/message-repository.test.ts +70 -0
- package/src/lib/server/messages/message-repository.ts +11 -6
- package/src/lib/server/openclaw/deploy.ts +32 -2
- package/src/lib/server/plugins-advanced.test.ts +1 -2
- package/src/lib/server/provider-health.ts +1 -1
- package/src/lib/server/runtime/process-manager.ts +13 -9
- package/src/lib/server/runtime/session-run-manager/queries.ts +15 -0
- package/src/lib/server/runtime/session-run-manager.test.ts +58 -0
- package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
- package/src/lib/server/sandbox/session-runtime.ts +40 -28
- package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
- package/src/lib/server/session-tools/context.ts +1 -1
- package/src/lib/server/session-tools/credential-env.ts +109 -0
- package/src/lib/server/session-tools/crud.ts +3 -3
- package/src/lib/server/session-tools/edit_file.ts +3 -2
- package/src/lib/server/session-tools/execute.test.ts +58 -0
- package/src/lib/server/session-tools/execute.ts +334 -0
- package/src/lib/server/session-tools/files-tool.ts +635 -0
- package/src/lib/server/session-tools/index.ts +14 -4
- package/src/lib/server/session-tools/memory-tool.ts +242 -0
- package/src/lib/server/session-tools/memory.ts +1 -1
- package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
- package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
- package/src/lib/server/session-tools/platform-tool.ts +617 -0
- package/src/lib/server/session-tools/session-info.ts +3 -2
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
- package/src/lib/server/session-tools/shell.ts +7 -122
- package/src/lib/server/session-tools/skills-tool.ts +396 -0
- package/src/lib/server/session-tools/web.ts +2 -2
- package/src/lib/server/storage-normalization.ts +2 -0
- package/src/lib/server/tool-aliases.ts +2 -1
- package/src/lib/server/tool-capability-policy-advanced.test.ts +9 -2
- package/src/lib/server/tool-capability-policy.test.ts +2 -1
- package/src/lib/server/tool-capability-policy.ts +60 -33
- package/src/lib/server/tool-planning.ts +11 -0
- package/src/lib/setup-defaults.ts +5 -0
- package/src/lib/tool-definitions.ts +1 -0
- package/src/lib/validation/schemas.test.ts +16 -0
- package/src/lib/validation/schemas.ts +16 -0
- package/src/stores/use-chat-store.test.ts +231 -0
- package/src/stores/use-chat-store.ts +62 -13
- package/src/types/agent.ts +348 -0
- package/src/types/app-settings.ts +175 -0
- package/src/types/approval.ts +27 -0
- package/src/types/connector.ts +187 -0
- package/src/types/extension.ts +386 -0
- package/src/types/index.ts +16 -3555
- package/src/types/message.ts +57 -0
- package/src/types/misc.ts +739 -0
- package/src/types/mission.ts +185 -0
- package/src/types/protocol.ts +422 -0
- package/src/types/provider.ts +52 -0
- package/src/types/run.ts +183 -0
- package/src/types/schedule.ts +59 -0
- package/src/types/session.ts +265 -0
- package/src/types/skill.ts +157 -0
- package/src/types/task.ts +140 -0
- package/src/types/working-state.ts +211 -0
- package/src/views/settings/section-heartbeat.tsx +2 -2
- package/src/lib/server/session-tools/sandbox.ts +0 -281
|
@@ -76,6 +76,7 @@ import {
|
|
|
76
76
|
import { checkAgentBudgetLimits } from '@/lib/server/cost'
|
|
77
77
|
import {
|
|
78
78
|
classifyMessage,
|
|
79
|
+
type MessageClassification,
|
|
79
80
|
toMessageSemanticsSummary,
|
|
80
81
|
} from '@/lib/server/chat-execution/message-classifier'
|
|
81
82
|
import {
|
|
@@ -87,6 +88,7 @@ import {
|
|
|
87
88
|
} from '@/lib/server/chat-execution/chat-execution-utils'
|
|
88
89
|
import { loadEstopState } from '@/lib/server/runtime/estop'
|
|
89
90
|
import { buildToolSection, joinPromptSegments } from '@/lib/server/chat-execution/prompt-builder'
|
|
91
|
+
import { resolvePromptMode, type PromptMode } from '@/lib/server/chat-execution/prompt-mode'
|
|
90
92
|
import { isDirectConnectorSession } from '@/lib/server/connectors/session-kind'
|
|
91
93
|
import type { ExecuteChatTurnInput } from '@/lib/server/chat-execution/chat-execution'
|
|
92
94
|
|
|
@@ -320,13 +322,17 @@ function buildLightHeartbeatSystemPrompt(session: Session): string | undefined {
|
|
|
320
322
|
return parts.join('\n\n')
|
|
321
323
|
}
|
|
322
324
|
|
|
323
|
-
function buildAgentSystemPrompt(
|
|
325
|
+
function buildAgentSystemPrompt(
|
|
326
|
+
session: Session,
|
|
327
|
+
options?: { lightweightDirectChat?: boolean },
|
|
328
|
+
): string | undefined {
|
|
324
329
|
if (!session.agentId) return undefined
|
|
325
330
|
const agent = getAgent(session.agentId)
|
|
326
331
|
if (!agent) return undefined
|
|
327
332
|
|
|
328
333
|
const settings = loadSettings()
|
|
329
334
|
const allowSilentReplies = isDirectConnectorSession(session)
|
|
335
|
+
const lightweightDirectChat = options?.lightweightDirectChat === true
|
|
330
336
|
const parts: string[] = []
|
|
331
337
|
const enabledExtensions = listUniversalToolAccessExtensionIds(
|
|
332
338
|
getEnabledCapabilityIds(session).length > 0 ? getEnabledCapabilityIds(session) : getEnabledCapabilityIds(agent),
|
|
@@ -341,7 +347,7 @@ function buildAgentSystemPrompt(session: Session): string | undefined {
|
|
|
341
347
|
if (agent.description) identityLines.push(`Description: ${agent.description}`)
|
|
342
348
|
identityLines.push('I should always embody this identity. I am not just an "Assistant" — I am a persistent companion with my own soul and presence.')
|
|
343
349
|
parts.push(identityLines.join('\n'))
|
|
344
|
-
const continuityBlock = buildIdentityContinuityContext(session, agent)
|
|
350
|
+
const continuityBlock = lightweightDirectChat ? null : buildIdentityContinuityContext(session, agent)
|
|
345
351
|
if (continuityBlock) parts.push(continuityBlock)
|
|
346
352
|
|
|
347
353
|
const runtimeLines = [
|
|
@@ -358,50 +364,57 @@ function buildAgentSystemPrompt(session: Session): string | undefined {
|
|
|
358
364
|
if (agent.soul) parts.push(`## Soul\n${agent.soul}`)
|
|
359
365
|
if (agent.systemPrompt) parts.push(`## System Prompt\n${agent.systemPrompt}`)
|
|
360
366
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
367
|
+
if (!lightweightDirectChat) {
|
|
368
|
+
try {
|
|
369
|
+
const runtimeSkills = resolveRuntimeSkills({
|
|
370
|
+
cwd: session.cwd,
|
|
371
|
+
enabledExtensions,
|
|
372
|
+
agentId: agent.id,
|
|
373
|
+
sessionId: session.id,
|
|
374
|
+
userId: session.user,
|
|
375
|
+
agentSkillIds: agent.skillIds || [],
|
|
376
|
+
storedSkills: loadSkills(),
|
|
377
|
+
selectedSkillId: session.skillRuntimeState?.selectedSkillId || null,
|
|
378
|
+
})
|
|
379
|
+
parts.push(...buildRuntimeSkillPromptBlocks(runtimeSkills))
|
|
380
|
+
} catch {
|
|
381
|
+
// Runtime skills are non-critical during prompt assembly.
|
|
382
|
+
}
|
|
376
383
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
384
|
+
try {
|
|
385
|
+
const wsCtx = buildWorkspaceContext({ cwd: session.cwd })
|
|
386
|
+
if (wsCtx.block) parts.push(wsCtx.block)
|
|
387
|
+
} catch {
|
|
388
|
+
// Workspace context is non-critical.
|
|
389
|
+
}
|
|
382
390
|
}
|
|
383
391
|
|
|
384
392
|
const thinkingHint = [
|
|
385
393
|
'## Output Format',
|
|
386
394
|
'If your model supports internal reasoning/thinking, put all internal analysis inside <think>...</think> tags.',
|
|
387
395
|
'Your final response to the user should be clear and concise.',
|
|
396
|
+
...(lightweightDirectChat
|
|
397
|
+
? ['This is a lightweight direct chat turn. Reply naturally in 1-3 short sentences. Do not delegate, plan, or narrate tools unless the user adds a concrete task that needs that escalation.']
|
|
398
|
+
: []),
|
|
388
399
|
allowSilentReplies
|
|
389
400
|
? 'When you truly have nothing to say, respond with ONLY: NO_MESSAGE'
|
|
390
401
|
: 'For direct user chats, always send a visible reply. Never answer with NO_MESSAGE or HEARTBEAT_OK unless this is an explicit heartbeat poll.',
|
|
391
402
|
]
|
|
392
403
|
parts.push(thinkingHint.join('\n'))
|
|
393
404
|
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
405
|
+
if (!lightweightDirectChat) {
|
|
406
|
+
if (enabledExtensions.length === 0) {
|
|
407
|
+
parts.push(buildNoToolsGuidance().join('\n'))
|
|
408
|
+
} else {
|
|
409
|
+
parts.push(buildEnabledToolsAutonomyGuidance().join('\n'))
|
|
410
|
+
}
|
|
411
|
+
const toolSectionLines = buildToolSection(enabledExtensions)
|
|
412
|
+
if (toolSectionLines.length > 0) parts.push(['## Tool Discipline', ...toolSectionLines].join('\n'))
|
|
413
|
+
const operatingGuidance = collectCapabilityOperatingGuidance(enabledExtensions)
|
|
414
|
+
if (operatingGuidance.length > 0) parts.push(['## Tool Guidance', ...operatingGuidance].join('\n'))
|
|
415
|
+
const capabilityLines = collectCapabilityDescriptions(enabledExtensions)
|
|
416
|
+
if (capabilityLines.length > 0) parts.push(['## Tool Capabilities', ...capabilityLines].join('\n'))
|
|
398
417
|
}
|
|
399
|
-
const toolSectionLines = buildToolSection(enabledExtensions)
|
|
400
|
-
if (toolSectionLines.length > 0) parts.push(['## Tool Discipline', ...toolSectionLines].join('\n'))
|
|
401
|
-
const operatingGuidance = collectCapabilityOperatingGuidance(enabledExtensions)
|
|
402
|
-
if (operatingGuidance.length > 0) parts.push(['## Tool Guidance', ...operatingGuidance].join('\n'))
|
|
403
|
-
const capabilityLines = collectCapabilityDescriptions(enabledExtensions)
|
|
404
|
-
if (capabilityLines.length > 0) parts.push(['## Tool Capabilities', ...capabilityLines].join('\n'))
|
|
405
418
|
|
|
406
419
|
parts.push([
|
|
407
420
|
'## Heartbeats',
|
|
@@ -470,6 +483,8 @@ export interface PreparedExecutableChatTurn {
|
|
|
470
483
|
runStartedAt: number
|
|
471
484
|
runMessageStartIndex: number
|
|
472
485
|
toolPolicy: ReturnType<typeof resolveSessionToolPolicy>
|
|
486
|
+
classification: MessageClassification | null
|
|
487
|
+
promptMode: PromptMode
|
|
473
488
|
}
|
|
474
489
|
|
|
475
490
|
export type PreparedChatTurn = PreparedBlockedChatTurn | PreparedExecutableChatTurn
|
|
@@ -620,6 +635,24 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
620
635
|
}
|
|
621
636
|
}
|
|
622
637
|
|
|
638
|
+
const turnHistory = getMessages(sessionId)
|
|
639
|
+
const classification = !internal
|
|
640
|
+
? await classifyMessage({
|
|
641
|
+
sessionId,
|
|
642
|
+
agentId: session.agentId || null,
|
|
643
|
+
message,
|
|
644
|
+
history: turnHistory,
|
|
645
|
+
}).catch(() => null as MessageClassification | null)
|
|
646
|
+
: null
|
|
647
|
+
const lightweightDirectChat = classification?.isLightweightDirectChat === true
|
|
648
|
+
&& !internal
|
|
649
|
+
&& source === 'chat'
|
|
650
|
+
&& !isDirectConnectorSession(sessionForRun)
|
|
651
|
+
const promptMode = resolvePromptMode(sessionForRun, { preferMinimalPrompt: lightweightDirectChat })
|
|
652
|
+
if (lightweightDirectChat && sessionForRun.thinkingLevel !== 'minimal') {
|
|
653
|
+
sessionForRun = { ...sessionForRun, thinkingLevel: 'minimal' }
|
|
654
|
+
}
|
|
655
|
+
|
|
623
656
|
if (isHeartbeatRun && input.modelOverride) {
|
|
624
657
|
sessionForRun = { ...sessionForRun, model: input.modelOverride }
|
|
625
658
|
}
|
|
@@ -632,7 +665,10 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
632
665
|
if (extensionsForRun.length > 0) {
|
|
633
666
|
const modelResolvePrompt = heartbeatLightContext
|
|
634
667
|
? (joinSystemPromptBlocks(buildLightHeartbeatSystemPrompt(sessionForRun), executionBriefContextBlock) || '')
|
|
635
|
-
: (joinSystemPromptBlocks(
|
|
668
|
+
: (joinSystemPromptBlocks(
|
|
669
|
+
buildAgentSystemPrompt(sessionForRun, { lightweightDirectChat }),
|
|
670
|
+
executionBriefContextBlock,
|
|
671
|
+
) || '')
|
|
636
672
|
const modelResolve = await runCapabilityBeforeModelResolve(
|
|
637
673
|
{
|
|
638
674
|
session: sessionForRun,
|
|
@@ -724,14 +760,7 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
724
760
|
if (shouldPersistUserMessage) {
|
|
725
761
|
const [linkAnalysis, semantics] = await Promise.all([
|
|
726
762
|
!internal ? runLinkUnderstanding(message) : Promise.resolve([]),
|
|
727
|
-
|
|
728
|
-
sessionId,
|
|
729
|
-
agentId: session.agentId || null,
|
|
730
|
-
message,
|
|
731
|
-
history: getMessages(sessionId),
|
|
732
|
-
})
|
|
733
|
-
.then((classification) => toMessageSemanticsSummary(classification))
|
|
734
|
-
.catch(() => undefined),
|
|
763
|
+
Promise.resolve(toMessageSemanticsSummary(classification)),
|
|
735
764
|
])
|
|
736
765
|
const guardedUserText = guardUntrustedText({
|
|
737
766
|
text: message,
|
|
@@ -745,6 +774,7 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
745
774
|
role: 'user',
|
|
746
775
|
text: guardedUserText,
|
|
747
776
|
time: Date.now(),
|
|
777
|
+
runId: lifecycleRunId,
|
|
748
778
|
imagePath: imagePath || undefined,
|
|
749
779
|
imageUrl: imageUrl || undefined,
|
|
750
780
|
attachedFiles: attachedFiles?.length ? attachedFiles : undefined,
|
|
@@ -805,7 +835,12 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
805
835
|
|
|
806
836
|
const systemPrompt = heartbeatLightContext
|
|
807
837
|
? joinSystemPromptBlocks(buildLightHeartbeatSystemPrompt(sessionForRun), executionBriefContextBlock)
|
|
808
|
-
: (hasExtensions
|
|
838
|
+
: (hasExtensions
|
|
839
|
+
? undefined
|
|
840
|
+
: joinSystemPromptBlocks(
|
|
841
|
+
buildAgentSystemPrompt(sessionForRun, { lightweightDirectChat }),
|
|
842
|
+
executionBriefContextBlock,
|
|
843
|
+
))
|
|
809
844
|
|
|
810
845
|
return {
|
|
811
846
|
kind: 'ready',
|
|
@@ -837,5 +872,7 @@ export async function prepareChatTurn(input: ExecuteChatTurnInput): Promise<Prep
|
|
|
837
872
|
runStartedAt,
|
|
838
873
|
runMessageStartIndex,
|
|
839
874
|
toolPolicy,
|
|
875
|
+
classification,
|
|
876
|
+
promptMode,
|
|
840
877
|
}
|
|
841
878
|
}
|
|
@@ -76,6 +76,8 @@ export async function executePreparedChatTurn(params: {
|
|
|
76
76
|
isAutoRunNoHistory,
|
|
77
77
|
executionBrief,
|
|
78
78
|
executionBriefContextBlock,
|
|
79
|
+
classification,
|
|
80
|
+
promptMode,
|
|
79
81
|
} = prepared
|
|
80
82
|
|
|
81
83
|
const emit = partialPersistence.emit
|
|
@@ -151,6 +153,8 @@ export async function executePreparedChatTurn(params: {
|
|
|
151
153
|
history: heartbeatHistory ?? applyContextClearBoundary(getSessionMessages(sessionId)),
|
|
152
154
|
signal: abortController.signal,
|
|
153
155
|
source,
|
|
156
|
+
classification,
|
|
157
|
+
promptMode,
|
|
154
158
|
})
|
|
155
159
|
fullResponse = result.finalResponse || result.fullText
|
|
156
160
|
} else {
|
|
@@ -102,6 +102,13 @@ function checkUnfinishedToolCallsPending(ctx: ContinuationContext): Continuation
|
|
|
102
102
|
return null
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
function checkLightweightDirectChat(ctx: ContinuationContext): ContinuationDecision | null {
|
|
106
|
+
if (ctx.classification?.isLightweightDirectChat !== true) return null
|
|
107
|
+
if (!ctx.state.fullText.trim()) return null
|
|
108
|
+
if (ctx.state.hasToolCalls || ctx.state.streamedToolEvents.length > 0) return null
|
|
109
|
+
return { type: false, requiredToolReminderNames: [] }
|
|
110
|
+
}
|
|
111
|
+
|
|
105
112
|
function checkLoopDetection(ctx: ContinuationContext): ContinuationDecision | null {
|
|
106
113
|
const isToolFrequency = (ctx.state.loopDetectionTriggered?.detector === 'tool_frequency') || ctx.state.toolFrequencyBlocked
|
|
107
114
|
if (!ctx.state.loopDetectionTriggered && !isToolFrequency) return null
|
|
@@ -412,6 +419,7 @@ export function evaluateContinuation(ctx: ContinuationContext): ContinuationDeci
|
|
|
412
419
|
const checks = [
|
|
413
420
|
checkUnfinishedToolCallsPending,
|
|
414
421
|
checkLoopDetection,
|
|
422
|
+
checkLightweightDirectChat,
|
|
415
423
|
checkCoordinatorDelegation,
|
|
416
424
|
checkExecutionContinuation,
|
|
417
425
|
checkRequiredTools,
|
|
@@ -112,7 +112,7 @@ export function shouldTerminateOnSuccessfulMemoryMutation(params: {
|
|
|
112
112
|
: exactToolName === 'memory_update'
|
|
113
113
|
? 'update'
|
|
114
114
|
: resolveToolAction(params.toolInput)
|
|
115
|
-
if (action !== 'store' && action !== 'update') return false
|
|
115
|
+
if (action !== 'store' && action !== 'update' && action !== 'write') return false
|
|
116
116
|
const output = extractSuggestions(params.toolOutput || '').clean.trim()
|
|
117
117
|
if (!output || /^error[:\s]/i.test(output)) return false
|
|
118
118
|
if (!/^(stored|updated) memory\b/i.test(output)) return false
|
|
@@ -31,6 +31,7 @@ export const MessageClassificationSchema = z.object({
|
|
|
31
31
|
taskIntent: TaskIntentSchema,
|
|
32
32
|
isDeliverableTask: z.boolean(),
|
|
33
33
|
isBroadGoal: z.boolean(),
|
|
34
|
+
isLightweightDirectChat: z.boolean().optional().default(false),
|
|
34
35
|
walletIntent: z.enum(['none', 'read_only', 'transactional']),
|
|
35
36
|
hasHumanSignals: z.boolean(),
|
|
36
37
|
hasSignificantEvent: z.boolean(),
|
|
@@ -47,6 +48,7 @@ export interface MessageClassification {
|
|
|
47
48
|
taskIntent: MessageTaskIntent
|
|
48
49
|
isDeliverableTask: boolean
|
|
49
50
|
isBroadGoal: boolean
|
|
51
|
+
isLightweightDirectChat?: boolean
|
|
50
52
|
walletIntent: 'none' | 'read_only' | 'transactional'
|
|
51
53
|
hasHumanSignals: boolean
|
|
52
54
|
hasSignificantEvent: boolean
|
|
@@ -102,6 +104,7 @@ function buildClassificationPrompt(message: string, recentHistory: string): stri
|
|
|
102
104
|
'- taskIntent: The primary execution intent. Use exactly one of: "coding", "research", "browsing", "outreach", "scheduling", or "general". Choose "coding" for repo/code/build/debug/edit tasks. Choose "research" for gathering current info or synthesizing sources. Choose "browsing" for page navigation, rendered-page inspection, form work, or literal browser workflows. Choose "outreach" for sending/sharing/delivering updates to an external channel. Choose "scheduling" for reminders, recurring work, monitoring, or follow-up scheduling. Choose "general" when none of the above clearly fits.',
|
|
103
105
|
'- isDeliverableTask (bool): The user wants a concrete artifact produced — a document, report, plan, proposal, landing page, dashboard, HTML file, markdown file, brief, copy, screenshots, or similar deliverable. NOT simple Q&A, code fixes, or single-command tasks.',
|
|
104
106
|
'- isBroadGoal (bool): The message describes a broad, multi-step goal (50+ chars, no code blocks, no file paths, no numbered lists). Short questions ending with "?" are NOT broad goals.',
|
|
107
|
+
'- isLightweightDirectChat (bool): This is a low-signal direct chat turn that should get a natural lightweight reply, such as a greeting, acknowledgment, check-in, or simple social/direct question that does NOT require research, file work, planning, delegation, or tool execution.',
|
|
105
108
|
'- walletIntent: "none" if no crypto/wallet/trading context. "read_only" if mentioning wallet/crypto but only for checking balances, viewing transactions, or research. "transactional" if the user wants to swap, trade, buy, sell, mint, claim, deposit, withdraw, bridge, or execute a transaction.',
|
|
106
109
|
'- hasHumanSignals (bool): The message contains personal signals — preferences ("I prefer", "call me"), relationships ("my wife", "my partner", "my kid"), life events ("birthday", "wedding", "promotion", "moving", "graduation", "hospital"), or personal disclosures.',
|
|
107
110
|
'- hasSignificantEvent (bool): The message mentions a notable life/work event or milestone (birthday, anniversary, wedding, graduation, promotion, new job, relocation, illness, funeral, travel, house, deadline, launch).',
|
|
@@ -115,13 +118,14 @@ function buildClassificationPrompt(message: string, recentHistory: string): stri
|
|
|
115
118
|
'',
|
|
116
119
|
'Rules:',
|
|
117
120
|
'- Be conservative. When unsure, default to false/none/empty.',
|
|
121
|
+
'- Mark isLightweightDirectChat true only when a short natural reply is enough and escalating into planning, delegation, or tool execution would be unnecessary.',
|
|
118
122
|
'- A message can be both a deliverable task AND a broad goal.',
|
|
119
123
|
'- "walletIntent" should be "transactional" only if the user wants to execute a state-changing action, not just discuss crypto.',
|
|
120
124
|
'- For "explicitToolRequests", only include tools the user explicitly mentions by name or clear synonym. Do not infer tool needs from the task type.',
|
|
121
125
|
'- Prefer the most execution-relevant taskIntent. Example: "research this and send me a voice note" is "research", not "outreach".',
|
|
122
126
|
'',
|
|
123
127
|
'Output shape:',
|
|
124
|
-
'{"taskIntent":"coding|research|browsing|outreach|scheduling|general","isDeliverableTask":bool,"isBroadGoal":bool,"walletIntent":"none|read_only|transactional","hasHumanSignals":bool,"hasSignificantEvent":bool,"isResearchSynthesis":bool,"workType":"coding|research|writing|review|operations|general","wantsScreenshots":bool,"wantsOutboundDelivery":bool,"wantsVoiceDelivery":bool,"explicitToolRequests":[],"confidence":0.0-1.0}',
|
|
128
|
+
'{"taskIntent":"coding|research|browsing|outreach|scheduling|general","isDeliverableTask":bool,"isBroadGoal":bool,"isLightweightDirectChat":bool,"walletIntent":"none|read_only|transactional","hasHumanSignals":bool,"hasSignificantEvent":bool,"isResearchSynthesis":bool,"workType":"coding|research|writing|review|operations|general","wantsScreenshots":bool,"wantsOutboundDelivery":bool,"wantsVoiceDelivery":bool,"explicitToolRequests":[],"confidence":0.0-1.0}',
|
|
125
129
|
'',
|
|
126
130
|
recentHistory ? `Recent context:\n${recentHistory}\n` : '',
|
|
127
131
|
`User message: ${JSON.stringify(message)}`,
|
|
@@ -276,6 +280,7 @@ export function toMessageSemanticsSummary(classification: MessageClassification
|
|
|
276
280
|
isDeliverableTask: classification.isDeliverableTask,
|
|
277
281
|
isBroadGoal: classification.isBroadGoal,
|
|
278
282
|
isResearchSynthesis: classification.isResearchSynthesis,
|
|
283
|
+
isLightweightDirectChat: classification.isLightweightDirectChat === true,
|
|
279
284
|
hasHumanSignals: classification.hasHumanSignals,
|
|
280
285
|
hasSignificantEvent: classification.hasSignificantEvent,
|
|
281
286
|
wantsScreenshots: classification.wantsScreenshots === true,
|
|
@@ -324,3 +329,8 @@ export function isResearchSynthesis(classification: MessageClassification | null
|
|
|
324
329
|
void routingIntent
|
|
325
330
|
return classification?.isResearchSynthesis === true
|
|
326
331
|
}
|
|
332
|
+
|
|
333
|
+
export function isLightweightDirectChat(classification: MessageClassification | null, message?: string): boolean {
|
|
334
|
+
void message
|
|
335
|
+
return classification?.isLightweightDirectChat === true
|
|
336
|
+
}
|
|
@@ -26,4 +26,32 @@ describe('buildAgenticExecutionPolicy', () => {
|
|
|
26
26
|
assert.ok(prompt.includes('use the concrete tool now'))
|
|
27
27
|
assert.ok(prompt.includes('prefer the direct `manage_*` tool'))
|
|
28
28
|
})
|
|
29
|
+
|
|
30
|
+
it('adds lightweight direct-chat guidance when classification marks the turn as lightweight', () => {
|
|
31
|
+
const prompt = buildAgenticExecutionPolicy({
|
|
32
|
+
enabledExtensions: ['memory', 'files', 'delegate'],
|
|
33
|
+
loopMode: 'bounded',
|
|
34
|
+
heartbeatPrompt: 'HEARTBEAT',
|
|
35
|
+
heartbeatIntervalSec: 120,
|
|
36
|
+
userMessage: 'Hello',
|
|
37
|
+
history: [],
|
|
38
|
+
classification: {
|
|
39
|
+
taskIntent: 'general',
|
|
40
|
+
isDeliverableTask: false,
|
|
41
|
+
isBroadGoal: false,
|
|
42
|
+
isLightweightDirectChat: true,
|
|
43
|
+
walletIntent: 'none',
|
|
44
|
+
hasHumanSignals: false,
|
|
45
|
+
hasSignificantEvent: false,
|
|
46
|
+
isResearchSynthesis: false,
|
|
47
|
+
workType: 'general',
|
|
48
|
+
explicitToolRequests: [],
|
|
49
|
+
confidence: 0.98,
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
assert.ok(prompt.includes('## Lightweight Chat'))
|
|
54
|
+
assert.ok(prompt.includes('Reply naturally and briefly.'))
|
|
55
|
+
assert.ok(prompt.includes('prefer 1-3 short sentences'))
|
|
56
|
+
})
|
|
29
57
|
})
|
|
@@ -75,7 +75,6 @@ function buildExtensionCapabilityLines(enabledExtensions: string[], opts?: { del
|
|
|
75
75
|
|
|
76
76
|
const DISPLAY_TOOL_ALIASES: Record<string, string[]> = {
|
|
77
77
|
files: ['send_file'],
|
|
78
|
-
shell: ['sandbox_exec', 'sandbox_list_runtimes'],
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
function buildExactToolNameList(enabledExtensions: string[]): string[] {
|
|
@@ -158,6 +157,7 @@ export function buildToolDisciplineLines(enabledExtensions: string[]): string[]
|
|
|
158
157
|
...(researchSearchTools.length || researchFetchTools.length ? [...researchSearchTools, ...researchFetchTools] : []),
|
|
159
158
|
...httpTools,
|
|
160
159
|
...(uniqueTools.includes('shell') ? ['shell'] : []),
|
|
160
|
+
...(uniqueTools.includes('execute') ? ['execute'] : []),
|
|
161
161
|
...(uniqueTools.includes('browser') ? ['browser'] : []),
|
|
162
162
|
]))
|
|
163
163
|
if (alternateResearchTools.length >= 2) {
|
|
@@ -330,6 +330,7 @@ export function buildAgenticExecutionPolicy(opts: {
|
|
|
330
330
|
const hasManageSessions = opts.enabledExtensions.some((toolId) => (canonicalizeExtensionId(toolId) || toolId) === 'manage_sessions')
|
|
331
331
|
const hasManageTasks = opts.enabledExtensions.some((toolId) => (canonicalizeExtensionId(toolId) || toolId) === 'manage_tasks')
|
|
332
332
|
const hasManageSkills = opts.enabledExtensions.some((toolId) => (canonicalizeExtensionId(toolId) || toolId) === 'manage_skills')
|
|
333
|
+
const lightweightDirectChat = opts.classification?.isLightweightDirectChat === true && !opts.isDirectConnectorSession
|
|
333
334
|
const hasDelegationTools = opts.enabledExtensions.some((toolId) => {
|
|
334
335
|
const canonical = canonicalizeExtensionId(toolId) || toolId
|
|
335
336
|
return canonical === 'delegate' || canonical === 'spawn_subagent'
|
|
@@ -359,6 +360,15 @@ export function buildAgenticExecutionPolicy(opts: {
|
|
|
359
360
|
: 'Loop: BOUNDED — execute multiple steps but finish within recursion budget.',
|
|
360
361
|
)
|
|
361
362
|
|
|
363
|
+
if (lightweightDirectChat) {
|
|
364
|
+
parts.push(
|
|
365
|
+
'## Lightweight Chat',
|
|
366
|
+
'This turn is a lightweight direct chat. Reply naturally and briefly.',
|
|
367
|
+
'Do not delegate, create tasks, outline a workflow, or narrate tools unless the user adds a concrete task that actually requires that escalation.',
|
|
368
|
+
'For greetings, acknowledgements, and simple social questions, a short human-sounding answer is sufficient.',
|
|
369
|
+
)
|
|
370
|
+
}
|
|
371
|
+
|
|
362
372
|
if (hasTooling) {
|
|
363
373
|
parts.push(
|
|
364
374
|
'## Routing Matrix',
|
|
@@ -444,6 +454,9 @@ export function buildAgenticExecutionPolicy(opts: {
|
|
|
444
454
|
]),
|
|
445
455
|
'Keep responses concise. Bullet points over prose. After file operations, confirm the result briefly (path and status) without echoing the full file contents.',
|
|
446
456
|
'Do not end every reply with a question. Only ask when a specific missing detail blocks progress. When a task is done, state the result and stop.',
|
|
457
|
+
...(lightweightDirectChat
|
|
458
|
+
? ['For this turn, prefer 1-3 short sentences over bullets, planning, or process narration.']
|
|
459
|
+
: []),
|
|
447
460
|
opts.responseStyle === 'concise'
|
|
448
461
|
? `IMPORTANT: Be extremely concise.${opts.responseMaxChars ? ` Keep responses under ${opts.responseMaxChars} characters.` : ' Target under 500 characters.'} Lead with the answer, skip preamble.`
|
|
449
462
|
: opts.responseStyle === 'detailed'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { describe, it } from 'node:test'
|
|
3
|
+
|
|
4
|
+
import { resolvePromptMode } from '@/lib/server/chat-execution/prompt-mode'
|
|
5
|
+
|
|
6
|
+
describe('resolvePromptMode', () => {
|
|
7
|
+
it('returns full for root sessions by default', () => {
|
|
8
|
+
assert.equal(resolvePromptMode({ id: 'root' } as never), 'full')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('prefers minimal mode for lightweight direct-chat turns', () => {
|
|
12
|
+
assert.equal(
|
|
13
|
+
resolvePromptMode({ id: 'root' } as never, { preferMinimalPrompt: true }),
|
|
14
|
+
'minimal',
|
|
15
|
+
)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('keeps delegated child sessions in minimal mode', () => {
|
|
19
|
+
assert.equal(
|
|
20
|
+
resolvePromptMode({ id: 'child', parentSessionId: 'parent' } as never, { preferMinimalPrompt: false }),
|
|
21
|
+
'minimal',
|
|
22
|
+
)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
@@ -20,7 +20,11 @@ export type PromptMode = 'full' | 'minimal' | 'none'
|
|
|
20
20
|
* proactive memory, thinking guidance
|
|
21
21
|
* - `none` — reserved for bare identity (light heartbeat path)
|
|
22
22
|
*/
|
|
23
|
-
export function resolvePromptMode(
|
|
23
|
+
export function resolvePromptMode(
|
|
24
|
+
session: Session,
|
|
25
|
+
options?: { preferMinimalPrompt?: boolean },
|
|
26
|
+
): PromptMode {
|
|
24
27
|
if (session.parentSessionId) return 'minimal'
|
|
28
|
+
if (options?.preferMinimalPrompt) return 'minimal'
|
|
25
29
|
return 'full'
|
|
26
30
|
}
|
|
@@ -65,14 +65,13 @@ const streamContinuationSource = _readSibling('stream-continuation.ts')
|
|
|
65
65
|
const streamSources = `${streamAgentChatSource}\n${streamContinuationSource}`
|
|
66
66
|
|
|
67
67
|
describe('buildToolDisciplineLines', () => {
|
|
68
|
-
it('lists exact callable tool names for
|
|
68
|
+
it('lists exact callable tool names for legacy sandbox aliases and browser', () => {
|
|
69
69
|
const lines = buildToolAvailabilityLines(['sandbox', 'browser', 'manage_schedules'])
|
|
70
70
|
|
|
71
71
|
assert.equal(lines[0], 'Tool names are case-sensitive. Call tools exactly as listed.')
|
|
72
72
|
assert.ok(lines.includes('- `browser`'))
|
|
73
|
+
assert.ok(lines.includes('- `execute`'))
|
|
73
74
|
assert.ok(lines.includes('- `manage_schedules`'))
|
|
74
|
-
assert.ok(lines.includes('- `sandbox_exec`'))
|
|
75
|
-
assert.ok(lines.includes('- `sandbox_list_runtimes`'))
|
|
76
75
|
})
|
|
77
76
|
|
|
78
77
|
it('tells the agent to use direct platform tools when manage_platform is absent', () => {
|
|
@@ -1033,7 +1032,7 @@ describe('shouldForceDeliverableFollowthrough', () => {
|
|
|
1033
1032
|
{ name: 'web', input: '{"action":"fetch","url":"https://example.com/topic"}', output: '<html>topic</html>' },
|
|
1034
1033
|
],
|
|
1035
1034
|
history: [
|
|
1036
|
-
{ role: 'user', text: 'Research 3 topics, take screenshots, write markdown and PDF files, then build a site for each topic.' },
|
|
1035
|
+
{ role: 'user', text: 'Research 3 topics, take screenshots, write markdown and PDF files, then build a site for each topic.', time: Date.now() },
|
|
1037
1036
|
],
|
|
1038
1037
|
}),
|
|
1039
1038
|
true,
|
|
@@ -1275,6 +1274,7 @@ describe('parseClassificationResponse', () => {
|
|
|
1275
1274
|
|
|
1276
1275
|
describe('message classifier adapter functions', () => {
|
|
1277
1276
|
const deliverableClassification: MessageClassification = {
|
|
1277
|
+
taskIntent: 'general',
|
|
1278
1278
|
isDeliverableTask: true,
|
|
1279
1279
|
isBroadGoal: true,
|
|
1280
1280
|
walletIntent: 'none',
|
|
@@ -1286,6 +1286,7 @@ describe('message classifier adapter functions', () => {
|
|
|
1286
1286
|
}
|
|
1287
1287
|
|
|
1288
1288
|
const walletClassification: MessageClassification = {
|
|
1289
|
+
taskIntent: 'general',
|
|
1289
1290
|
isDeliverableTask: false,
|
|
1290
1291
|
isBroadGoal: false,
|
|
1291
1292
|
walletIntent: 'transactional',
|
|
@@ -1297,6 +1298,7 @@ describe('message classifier adapter functions', () => {
|
|
|
1297
1298
|
}
|
|
1298
1299
|
|
|
1299
1300
|
const humanSignalClassification: MessageClassification = {
|
|
1301
|
+
taskIntent: 'general',
|
|
1300
1302
|
isDeliverableTask: false,
|
|
1301
1303
|
isBroadGoal: false,
|
|
1302
1304
|
walletIntent: 'none',
|
|
@@ -190,6 +190,7 @@ interface StreamAgentChatOpts {
|
|
|
190
190
|
fallbackCredentialIds?: string[]
|
|
191
191
|
signal?: AbortSignal
|
|
192
192
|
promptMode?: PromptMode
|
|
193
|
+
classification?: MessageClassification | null
|
|
193
194
|
/** Run source (e.g. 'heartbeat', 'chat', 'scheduler') — used for heartbeat-specific tuning. */
|
|
194
195
|
source?: string
|
|
195
196
|
}
|
|
@@ -223,10 +224,23 @@ export async function streamAgentChat(opts: StreamAgentChatOpts): Promise<Stream
|
|
|
223
224
|
|
|
224
225
|
async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAgentChatResult> {
|
|
225
226
|
const startTs = Date.now()
|
|
226
|
-
const {
|
|
227
|
+
const {
|
|
228
|
+
session,
|
|
229
|
+
message,
|
|
230
|
+
imagePath,
|
|
231
|
+
imageUrl,
|
|
232
|
+
attachedFiles,
|
|
233
|
+
apiKey,
|
|
234
|
+
systemPrompt,
|
|
235
|
+
executionBrief,
|
|
236
|
+
extraSystemContext,
|
|
237
|
+
write,
|
|
238
|
+
history,
|
|
239
|
+
fallbackCredentialIds,
|
|
240
|
+
signal,
|
|
241
|
+
classification: providedClassification,
|
|
242
|
+
} = opts
|
|
227
243
|
const isHeartbeat = isHeartbeatSource(opts.source)
|
|
228
|
-
const promptMode: PromptMode = opts.promptMode ?? resolvePromptMode(session)
|
|
229
|
-
const isMinimalPrompt = promptMode === 'minimal'
|
|
230
244
|
const isConnectorSession = isDirectConnectorSession(session)
|
|
231
245
|
const rawExtensions = getEnabledCapabilityIds(session)
|
|
232
246
|
const hasShellCapability = rawExtensions.some((toolId) => ['shell', 'execute_command'].includes(String(toolId)))
|
|
@@ -241,6 +255,23 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
|
|
|
241
255
|
|
|
242
256
|
const sessionAgent = session.agentId ? getAgent(session.agentId) : null
|
|
243
257
|
|
|
258
|
+
const classificationPromise = providedClassification !== undefined
|
|
259
|
+
? Promise.resolve(providedClassification)
|
|
260
|
+
: classifyMessage({
|
|
261
|
+
sessionId: session.id,
|
|
262
|
+
agentId: session.agentId,
|
|
263
|
+
message,
|
|
264
|
+
history,
|
|
265
|
+
}).catch(() => null as MessageClassification | null)
|
|
266
|
+
const classification = await classificationPromise
|
|
267
|
+
const lightweightDirectChat = classification?.isLightweightDirectChat === true
|
|
268
|
+
&& !isConnectorSession
|
|
269
|
+
&& !isHeartbeat
|
|
270
|
+
const promptMode: PromptMode = opts.promptMode ?? resolvePromptMode(session, {
|
|
271
|
+
preferMinimalPrompt: lightweightDirectChat,
|
|
272
|
+
})
|
|
273
|
+
const isMinimalPrompt = promptMode === 'minimal'
|
|
274
|
+
|
|
244
275
|
// Resolve agent's thinking level for provider-native params
|
|
245
276
|
let agentThinkingLevel: 'minimal' | 'low' | 'medium' | 'high' | undefined
|
|
246
277
|
if (session.thinkingLevel) {
|
|
@@ -248,6 +279,9 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
|
|
|
248
279
|
} else if (sessionAgent) {
|
|
249
280
|
agentThinkingLevel = sessionAgent.thinkingLevel
|
|
250
281
|
}
|
|
282
|
+
if (lightweightDirectChat) {
|
|
283
|
+
agentThinkingLevel = 'minimal'
|
|
284
|
+
}
|
|
251
285
|
|
|
252
286
|
const llm = buildChatModel({
|
|
253
287
|
provider: session.provider,
|
|
@@ -296,16 +330,6 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
|
|
|
296
330
|
return Math.max(0, Math.min(3600, Math.trunc(parsed)))
|
|
297
331
|
})()
|
|
298
332
|
|
|
299
|
-
// -------------------------------------------------------------------------
|
|
300
|
-
// Start message classification in the background (LLM-based, ~200-800ms)
|
|
301
|
-
// -------------------------------------------------------------------------
|
|
302
|
-
const classificationPromise = classifyMessage({
|
|
303
|
-
sessionId: session.id,
|
|
304
|
-
agentId: session.agentId,
|
|
305
|
-
message,
|
|
306
|
-
history,
|
|
307
|
-
}).catch(() => null as MessageClassification | null)
|
|
308
|
-
|
|
309
333
|
// -------------------------------------------------------------------------
|
|
310
334
|
// System prompt assembly (stays inline — many async calls + local state)
|
|
311
335
|
// -------------------------------------------------------------------------
|
|
@@ -426,8 +450,6 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
|
|
|
426
450
|
const suggestionsBlock = buildSuggestionsSection(settings.suggestionsEnabled, isMinimalPrompt)
|
|
427
451
|
if (suggestionsBlock) promptParts.push(suggestionsBlock)
|
|
428
452
|
|
|
429
|
-
// Await classification before building the agentic execution policy
|
|
430
|
-
const classification = await classificationPromise
|
|
431
453
|
const delegationAdvisory = sessionAgent && agentDelegationEnabled
|
|
432
454
|
? resolveDelegationAdvisory({
|
|
433
455
|
currentAgent: sessionAgent,
|
|
@@ -1138,7 +1160,14 @@ async function streamAgentChatCore(opts: StreamAgentChatOpts): Promise<StreamAge
|
|
|
1138
1160
|
}
|
|
1139
1161
|
|
|
1140
1162
|
// Async LLM-based incomplete-action check: catches "I'll run the deployment:" with no tool calls
|
|
1141
|
-
if (
|
|
1163
|
+
if (
|
|
1164
|
+
!shouldContinue
|
|
1165
|
+
&& outcome
|
|
1166
|
+
&& !state.hasToolCalls
|
|
1167
|
+
&& classification?.isLightweightDirectChat !== true
|
|
1168
|
+
&& state.fullText.trim().length > 0
|
|
1169
|
+
&& state.fullText.trim().length < 500
|
|
1170
|
+
) {
|
|
1142
1171
|
const completeness = await evaluateResponseCompleteness({
|
|
1143
1172
|
sessionId: session.id,
|
|
1144
1173
|
agentId: session.agentId,
|
|
@@ -16,6 +16,8 @@ const agents: Record<string, Agent> = {
|
|
|
16
16
|
model: 'gpt-test',
|
|
17
17
|
systemPrompt: '',
|
|
18
18
|
capabilities: ['deploy', 'infrastructure'],
|
|
19
|
+
createdAt: Date.now(),
|
|
20
|
+
updatedAt: Date.now(),
|
|
19
21
|
},
|
|
20
22
|
design: {
|
|
21
23
|
id: 'design',
|
|
@@ -25,6 +27,8 @@ const agents: Record<string, Agent> = {
|
|
|
25
27
|
model: 'gpt-test',
|
|
26
28
|
systemPrompt: '',
|
|
27
29
|
capabilities: ['design', 'ui'],
|
|
30
|
+
createdAt: Date.now(),
|
|
31
|
+
updatedAt: Date.now(),
|
|
28
32
|
},
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -217,8 +217,8 @@ const discord: PlatformConnector = {
|
|
|
217
217
|
return String(sent.id || '')
|
|
218
218
|
},
|
|
219
219
|
})
|
|
220
|
-
} catch (err:
|
|
221
|
-
log.error(TAG, 'Error handling message:', err
|
|
220
|
+
} catch (err: unknown) {
|
|
221
|
+
log.error(TAG, 'Error handling message:', errorMessage(err))
|
|
222
222
|
try {
|
|
223
223
|
await message.reply('Sorry, I encountered an error processing your message.')
|
|
224
224
|
} catch { /* ignore */ }
|