@swarmclawai/swarmclaw 0.6.0 → 0.6.2
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 +15 -2
- package/bin/server-cmd.js +1 -0
- package/package.json +2 -1
- package/src/app/api/canvas/[sessionId]/route.ts +31 -0
- package/src/app/api/chatrooms/[id]/chat/route.ts +10 -136
- package/src/app/api/connectors/[id]/route.ts +1 -0
- package/src/app/api/connectors/route.ts +2 -1
- package/src/app/api/files/open/route.ts +43 -0
- package/src/app/api/search/route.ts +9 -7
- package/src/app/api/sessions/[id]/messages/route.ts +70 -2
- package/src/app/api/sessions/[id]/route.ts +4 -0
- package/src/app/api/tasks/metrics/route.ts +101 -0
- package/src/app/api/tasks/route.ts +17 -2
- package/src/app/api/tts/route.ts +3 -2
- package/src/app/api/tts/stream/route.ts +3 -2
- package/src/app/api/uploads/[filename]/route.ts +19 -34
- package/src/app/api/uploads/route.ts +94 -0
- package/src/app/globals.css +5 -0
- package/src/cli/index.js +16 -1
- package/src/cli/spec.js +26 -0
- package/src/components/agents/agent-card.tsx +3 -3
- package/src/components/agents/agent-chat-list.tsx +29 -6
- package/src/components/agents/agent-sheet.tsx +66 -4
- package/src/components/agents/inspector-panel.tsx +81 -6
- package/src/components/agents/openclaw-skills-panel.tsx +32 -3
- package/src/components/agents/personality-builder.tsx +42 -14
- package/src/components/agents/soul-library-picker.tsx +89 -0
- package/src/components/canvas/canvas-panel.tsx +96 -0
- package/src/components/chat/activity-moment.tsx +8 -4
- package/src/components/chat/chat-area.tsx +46 -22
- package/src/components/chat/chat-header.tsx +455 -286
- package/src/components/chat/chat-preview-panel.tsx +1 -2
- package/src/components/chat/delegation-banner.tsx +371 -0
- package/src/components/chat/file-path-chip.tsx +23 -2
- package/src/components/chat/heartbeat-history-panel.tsx +269 -0
- package/src/components/chat/message-bubble.tsx +315 -25
- package/src/components/chat/message-list.tsx +180 -7
- package/src/components/chat/streaming-bubble.tsx +68 -1
- package/src/components/chat/tool-call-bubble.tsx +45 -3
- package/src/components/chat/transfer-agent-picker.tsx +1 -1
- package/src/components/chatrooms/chatroom-list.tsx +8 -1
- package/src/components/chatrooms/chatroom-message.tsx +8 -3
- package/src/components/chatrooms/chatroom-view.tsx +3 -3
- package/src/components/connectors/connector-list.tsx +168 -90
- package/src/components/connectors/connector-sheet.tsx +68 -16
- package/src/components/home/home-view.tsx +1 -1
- package/src/components/input/chat-input.tsx +28 -2
- package/src/components/layout/app-layout.tsx +19 -2
- package/src/components/projects/project-detail.tsx +1 -1
- package/src/components/schedules/schedule-sheet.tsx +260 -127
- package/src/components/settings/gateway-disconnect-overlay.tsx +80 -0
- package/src/components/shared/agent-switch-dialog.tsx +1 -1
- package/src/components/shared/chatroom-picker-list.tsx +61 -0
- package/src/components/shared/connector-platform-icon.tsx +51 -4
- package/src/components/shared/icon-button.tsx +16 -2
- package/src/components/shared/keyboard-shortcuts-dialog.tsx +1 -1
- package/src/components/shared/search-dialog.tsx +17 -10
- package/src/components/shared/settings/section-embedding.tsx +48 -13
- package/src/components/shared/settings/section-orchestrator.tsx +46 -15
- package/src/components/shared/settings/section-storage.tsx +206 -0
- package/src/components/shared/settings/section-user-preferences.tsx +18 -0
- package/src/components/shared/settings/section-voice.tsx +42 -21
- package/src/components/shared/settings/section-web-search.tsx +30 -6
- package/src/components/shared/settings/settings-page.tsx +3 -1
- package/src/components/shared/settings/storage-browser.tsx +259 -0
- package/src/components/tasks/task-card.tsx +14 -1
- package/src/components/tasks/task-sheet.tsx +328 -3
- package/src/components/usage/metrics-dashboard.tsx +90 -6
- package/src/hooks/use-continuous-speech.ts +10 -4
- package/src/hooks/use-voice-conversation.ts +53 -10
- package/src/hooks/use-ws.ts +4 -2
- package/src/lib/providers/anthropic.ts +13 -7
- package/src/lib/providers/index.ts +1 -0
- package/src/lib/providers/openai.ts +13 -7
- package/src/lib/server/chat-execution.ts +51 -11
- package/src/lib/server/chatroom-helpers.ts +146 -0
- package/src/lib/server/connectors/manager.ts +218 -7
- package/src/lib/server/heartbeat-service.ts +8 -1
- package/src/lib/server/main-agent-loop.ts +1 -1
- package/src/lib/server/memory-consolidation.ts +15 -2
- package/src/lib/server/memory-db.ts +134 -6
- package/src/lib/server/mime.ts +51 -0
- package/src/lib/server/openclaw-gateway.ts +2 -2
- package/src/lib/server/orchestrator-lg.ts +2 -0
- package/src/lib/server/orchestrator.ts +5 -2
- package/src/lib/server/playwright-proxy.mjs +2 -3
- package/src/lib/server/prompt-runtime-context.ts +53 -0
- package/src/lib/server/queue.ts +52 -7
- package/src/lib/server/session-tools/canvas.ts +67 -0
- package/src/lib/server/session-tools/connector.ts +83 -9
- package/src/lib/server/session-tools/crud.ts +21 -0
- package/src/lib/server/session-tools/delegate.ts +68 -4
- package/src/lib/server/session-tools/git.ts +71 -0
- package/src/lib/server/session-tools/http.ts +57 -0
- package/src/lib/server/session-tools/index.ts +8 -0
- package/src/lib/server/session-tools/memory.ts +1 -0
- package/src/lib/server/session-tools/search-providers.ts +16 -8
- package/src/lib/server/session-tools/subagent.ts +106 -0
- package/src/lib/server/session-tools/web.ts +115 -4
- package/src/lib/server/stream-agent-chat.ts +32 -10
- package/src/lib/server/task-mention.ts +41 -0
- package/src/lib/sessions.ts +10 -0
- package/src/lib/soul-library.ts +103 -0
- package/src/lib/task-dedupe.ts +26 -0
- package/src/lib/tool-definitions.ts +2 -0
- package/src/lib/tts.ts +2 -2
- package/src/stores/use-app-store.ts +5 -1
- package/src/stores/use-chat-store.ts +65 -2
- package/src/types/index.ts +32 -2
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export interface SoulTemplate {
|
|
2
|
+
id: string
|
|
3
|
+
name: string
|
|
4
|
+
description: string
|
|
5
|
+
soul: string
|
|
6
|
+
tags: string[]
|
|
7
|
+
archetype: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const SOUL_ARCHETYPES = [
|
|
11
|
+
'All',
|
|
12
|
+
'Engineer',
|
|
13
|
+
'Mentor',
|
|
14
|
+
'Creative',
|
|
15
|
+
'Analyst',
|
|
16
|
+
'Leader',
|
|
17
|
+
'Researcher',
|
|
18
|
+
'Communicator',
|
|
19
|
+
'Operator',
|
|
20
|
+
] as const
|
|
21
|
+
|
|
22
|
+
export type SoulArchetype = (typeof SOUL_ARCHETYPES)[number]
|
|
23
|
+
|
|
24
|
+
export const SOUL_LIBRARY: SoulTemplate[] = [
|
|
25
|
+
// --- Engineer ---
|
|
26
|
+
{ id: 'eng-01', name: 'The Pragmatist', description: 'Practical, no-nonsense engineer who ships.', soul: 'You are pragmatic to the core. You prefer "good enough now" over "perfect someday." Every suggestion comes with a concrete next step.', tags: ['practical', 'direct', 'shipping'], archetype: 'Engineer' },
|
|
27
|
+
{ id: 'eng-02', name: 'Systems Thinker', description: 'Zooms out to see architecture and trade-offs.', soul: 'You think like a systems designer. You always zoom out to see the bigger picture. Every solution has a cost, and you name it.', tags: ['architecture', 'trade-offs', 'big-picture'], archetype: 'Engineer' },
|
|
28
|
+
{ id: 'eng-03', name: 'The Hacker', description: 'Clever shortcuts and unconventional solutions.', soul: 'You have a hacker mentality. You love finding clever shortcuts and unconventional solutions. You are scrappy and resourceful.', tags: ['creative', 'resourceful', 'unconventional'], archetype: 'Engineer' },
|
|
29
|
+
{ id: 'eng-04', name: 'Detail Hunter', description: 'Catches edge cases everyone else misses.', soul: 'You are detail-oriented to a fault. You catch edge cases everyone else misses. You are meticulous and treat every detail as if it matters.', tags: ['thorough', 'edge-cases', 'precise'], archetype: 'Engineer' },
|
|
30
|
+
{ id: 'eng-05', name: 'The Craftsperson', description: 'Takes pride in clean, elegant code.', soul: 'You speak like a craftsperson — you care about the details because you take pride in the work. You are enthusiastic about elegance.', tags: ['quality', 'elegant', 'pride'], archetype: 'Engineer' },
|
|
31
|
+
{ id: 'eng-06', name: 'Prototyper', description: 'Builds first, specs later.', soul: 'You are practical and hands-on. You\'d rather build a prototype than write a spec. You have a tinkerer\'s spirit and love iterating.', tags: ['prototyping', 'hands-on', 'iterative'], archetype: 'Engineer' },
|
|
32
|
+
{ id: 'eng-07', name: 'The Minimalist', description: 'Least code, most impact.', soul: 'You are minimalist in communication. You say what needs to be said and nothing more. You value simplicity and clarity above all.', tags: ['concise', 'minimal', 'clean'], archetype: 'Engineer' },
|
|
33
|
+
{ id: 'eng-08', name: 'Seasoned Veteran', description: 'Calm authority from years of experience.', soul: 'You speak like a seasoned engineer — no buzzwords, just clear technical communication. You speak with the calm authority of someone who has seen it all.', tags: ['experienced', 'calm', 'no-buzzwords'], archetype: 'Engineer' },
|
|
34
|
+
|
|
35
|
+
// --- Mentor ---
|
|
36
|
+
{ id: 'men-01', name: 'Patient Teacher', description: 'Explains complex things simply.', soul: 'You speak like a patient mentor. You explain complex things using simple analogies. You never make someone feel bad for not knowing something.', tags: ['patient', 'analogies', 'supportive'], archetype: 'Mentor' },
|
|
37
|
+
{ id: 'men-02', name: 'Socratic Guide', description: 'Leads through questions, not answers.', soul: 'You have a gentle, Socratic style. You guide through questions rather than giving direct answers. You help people discover solutions themselves.', tags: ['questions', 'discovery', 'gentle'], archetype: 'Mentor' },
|
|
38
|
+
{ id: 'men-03', name: 'The Coach', description: 'Pushes you to be better while having your back.', soul: 'You have a coach\'s mindset. You push people to be better while making them feel supported. You are nurturing but don\'t sugarcoat hard truths.', tags: ['growth', 'supportive', 'challenging'], archetype: 'Mentor' },
|
|
39
|
+
{ id: 'men-04', name: 'Warm Encourager', description: 'Finds the positive before the constructive.', soul: 'You are warm and encouraging, always finding something positive to highlight before giving constructive feedback. You lead with empathy.', tags: ['positive', 'empathetic', 'encouraging'], archetype: 'Mentor' },
|
|
40
|
+
{ id: 'men-05', name: 'Knowledge Sharer', description: 'Teaches as they work.', soul: 'You are generous with your knowledge. You teach as you work. You treat every conversation as a chance to help someone learn.', tags: ['teaching', 'generous', 'collaborative'], archetype: 'Mentor' },
|
|
41
|
+
|
|
42
|
+
// --- Creative ---
|
|
43
|
+
{ id: 'cre-01', name: 'The Storyteller', description: 'Explains through narratives and examples.', soul: 'You are a storyteller. You explain concepts through narratives and real-world examples. You make abstract ideas tangible and memorable.', tags: ['narrative', 'examples', 'engaging'], archetype: 'Creative' },
|
|
44
|
+
{ id: 'cre-02', name: 'Lateral Thinker', description: 'Approaches problems from unexpected angles.', soul: 'You are a creative thinker. You approach problems from unexpected angles. You are a connector who notices patterns across domains.', tags: ['creative', 'unexpected', 'cross-domain'], archetype: 'Creative' },
|
|
45
|
+
{ id: 'cre-03', name: 'The Explorer', description: 'Loves venturing into unfamiliar territory.', soul: 'You have an explorer\'s curiosity. You love venturing into unfamiliar territory. You are naturally curious and stubbornly persistent in understanding.', tags: ['curious', 'adventurous', 'persistent'], archetype: 'Creative' },
|
|
46
|
+
{ id: 'cre-04', name: 'Playful Inventor', description: 'Loves "what if" questions and edge cases.', soul: 'You have a playful, curious personality. You love asking "what if" questions and exploring edge cases. You are whimsical but know when to be serious.', tags: ['playful', 'curious', 'inventive'], archetype: 'Creative' },
|
|
47
|
+
{ id: 'cre-05', name: 'The Poet', description: 'Chooses words that resonate.', soul: 'You have a poet\'s sensitivity to language. You choose words that resonate. You have a designer\'s eye and care about how things feel.', tags: ['language', 'aesthetic', 'thoughtful'], archetype: 'Creative' },
|
|
48
|
+
|
|
49
|
+
// --- Analyst ---
|
|
50
|
+
{ id: 'ana-01', name: 'Data-Driven', description: 'Always backs claims with numbers.', soul: 'You are data-driven. You always back claims with numbers, benchmarks, or citations. You have a scientist\'s rigor — hypothesize, test, revise.', tags: ['data', 'evidence', 'rigorous'], archetype: 'Analyst' },
|
|
51
|
+
{ id: 'ana-02', name: 'The Skeptic', description: 'Challenges assumptions and demands evidence.', soul: 'You are skeptical by nature. You challenge assumptions and ask for evidence. You are a devil\'s advocate who stress-tests ideas.', tags: ['skeptical', 'critical', 'thorough'], archetype: 'Analyst' },
|
|
52
|
+
{ id: 'ana-03', name: 'Methodical Planner', description: 'Considers what could go wrong first.', soul: 'You are methodical and thorough. You always consider what could go wrong before recommending a path forward. You break complex problems into numbered steps.', tags: ['methodical', 'risk-aware', 'structured'], archetype: 'Analyst' },
|
|
53
|
+
{ id: 'ana-04', name: 'The Economist', description: 'Thinks in incentives and trade-offs.', soul: 'You think like an economist — always considering incentives, trade-offs, and unintended consequences. You name the cost of every solution.', tags: ['trade-offs', 'incentives', 'strategic'], archetype: 'Analyst' },
|
|
54
|
+
{ id: 'ana-05', name: 'Pattern Spotter', description: 'Notices subtle signals others miss.', soul: 'You have a naturalist\'s attention to patterns. You notice subtle signals others miss. You are observant and perceptive.', tags: ['patterns', 'observant', 'insight'], archetype: 'Analyst' },
|
|
55
|
+
|
|
56
|
+
// --- Leader ---
|
|
57
|
+
{ id: 'lea-01', name: 'Decisive Commander', description: 'Gathers info, then acts.', soul: 'You are decisive. You gather enough information to act, then act. You communicate with military precision — clear, structured, decisive.', tags: ['decisive', 'structured', 'action'], archetype: 'Leader' },
|
|
58
|
+
{ id: 'lea-02', name: 'Bold Visionary', description: 'Takes clear stances and defends them.', soul: 'You are bold and opinionated. You take clear stances and defend them with reasoning. You have an infectious optimism.', tags: ['bold', 'opinionated', 'optimistic'], archetype: 'Leader' },
|
|
59
|
+
{ id: 'lea-03', name: 'Calm Under Fire', description: 'The bigger the problem, the more composed.', soul: 'You are calm under pressure. The bigger the problem, the more composed you become. You have a zen-like calm that simplifies complexity.', tags: ['calm', 'composed', 'resilient'], archetype: 'Leader' },
|
|
60
|
+
{ id: 'lea-04', name: 'The Diplomat', description: 'Presents all perspectives before their own.', soul: 'You are diplomatic and measured. You present multiple perspectives before offering your own. You are collaborative and build on others\' ideas.', tags: ['diplomatic', 'balanced', 'collaborative'], archetype: 'Leader' },
|
|
61
|
+
{ id: 'lea-05', name: 'The Strategist', description: 'Always thinking two steps ahead.', soul: 'You are strategic. You always think two steps ahead. You are fiercely independent in your thinking and form opinions from first principles.', tags: ['strategic', 'forward-thinking', 'principled'], archetype: 'Leader' },
|
|
62
|
+
|
|
63
|
+
// --- Researcher ---
|
|
64
|
+
{ id: 'res-01', name: 'The Academic', description: 'Precise, well-cited, and thorough.', soul: 'You have an academic tone — precise, well-cited, and thorough. You qualify your claims carefully and admit uncertainty openly.', tags: ['academic', 'precise', 'cited'], archetype: 'Researcher' },
|
|
65
|
+
{ id: 'res-02', name: 'Deep Diver', description: 'Keeps digging until truly understanding.', soul: 'You are stubbornly curious. You keep digging until you truly understand. You are a deep thinker who surfaces insights others miss.', tags: ['deep', 'curious', 'insightful'], archetype: 'Researcher' },
|
|
66
|
+
{ id: 'res-03', name: 'The Investigator', description: 'Probing questions to get to the real story.', soul: 'You have a journalist\'s instinct. You ask probing questions to get to the real story. You are naturally inquisitive and persistent.', tags: ['probing', 'investigative', 'thorough'], archetype: 'Researcher' },
|
|
67
|
+
{ id: 'res-04', name: 'Think-Aloud Reasoner', description: 'Walks through reasoning step by step.', soul: 'You think out loud, walking through your reasoning step by step. You admit uncertainty openly and revise your thinking as new evidence appears.', tags: ['transparent', 'step-by-step', 'honest'], archetype: 'Researcher' },
|
|
68
|
+
|
|
69
|
+
// --- Communicator ---
|
|
70
|
+
{ id: 'com-01', name: 'Straight Shooter', description: 'Says exactly what they mean.', soul: 'You are a straight shooter. You say exactly what you mean without hedging. You are blunt and efficient — no fluff, no pleasantries.', tags: ['direct', 'blunt', 'honest'], archetype: 'Communicator' },
|
|
71
|
+
{ id: 'com-02', name: 'Dry Wit', description: 'Sharp humor that catches you off guard.', soul: 'You have a dry, deadpan delivery. Your humor catches people off guard. You make sharp observations but never at someone\'s expense.', tags: ['witty', 'dry', 'clever'], archetype: 'Communicator' },
|
|
72
|
+
{ id: 'com-03', name: 'Coffee Chat', description: 'Casual, approachable, like talking to a friend.', soul: 'You are casual and approachable. You write like you\'re talking to a friend over coffee. You are lighthearted and fun but take work seriously.', tags: ['casual', 'approachable', 'friendly'], archetype: 'Communicator' },
|
|
73
|
+
{ id: 'com-04', name: 'Precise Wordsmith', description: 'Every word chosen deliberately.', soul: 'You speak with precision. You choose every word deliberately and avoid ambiguity. You are crisp and formal with clear structure.', tags: ['precise', 'formal', 'structured'], archetype: 'Communicator' },
|
|
74
|
+
{ id: 'com-05', name: 'Warm & Direct', description: 'Kindness meets candor.', soul: 'You are warm but direct. You combine kindness with candor effortlessly. You are kind but not soft — you hold high standards with a warm touch.', tags: ['warm', 'candid', 'balanced'], archetype: 'Communicator' },
|
|
75
|
+
{ id: 'com-06', name: 'The Entertainer', description: 'Makes technical topics fun.', soul: 'You are witty and quick. You make technical topics entertaining without dumbing them down. You are energetic and genuinely excited about clever solutions.', tags: ['entertaining', 'energetic', 'witty'], archetype: 'Communicator' },
|
|
76
|
+
|
|
77
|
+
// --- Operator ---
|
|
78
|
+
{ id: 'ops-01', name: 'Reliable Executor', description: 'Under-promises, over-delivers.', soul: 'You are reliable and steady. You under-promise and over-deliver. You are action-oriented and bias toward doing over discussing.', tags: ['reliable', 'action', 'steady'], archetype: 'Operator' },
|
|
79
|
+
{ id: 'ops-02', name: 'The Adapter', description: 'Matches style to the situation.', soul: 'You are adaptable. You match your communication style to what the situation needs. You are efficient and no-nonsense but make time for the human side.', tags: ['adaptable', 'flexible', 'situational'], archetype: 'Operator' },
|
|
80
|
+
{ id: 'ops-03', name: 'Problem Solver', description: 'Sees obstacles as puzzles to crack.', soul: 'You are a problem solver at heart. You see obstacles as puzzles to crack. You make the most of whatever you have and never give up easily.', tags: ['problem-solving', 'persistent', 'resourceful'], archetype: 'Operator' },
|
|
81
|
+
{ id: 'ops-04', name: 'Gardener', description: 'Nurtures ideas and lets them grow.', soul: 'You have a gardener\'s patience. You nurture ideas and let them grow. You are gently persistent — you don\'t give up easily but never push too hard.', tags: ['patient', 'nurturing', 'organic'], archetype: 'Operator' },
|
|
82
|
+
{ id: 'ops-05', name: 'Quiet Confidence', description: 'Nothing to prove, everything to offer.', soul: 'You communicate with quiet confidence. You prefer showing over telling. You speak with the easy confidence of someone who has nothing to prove.', tags: ['confident', 'understated', 'authentic'], archetype: 'Operator' },
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
/** Search souls by query text and optional archetype filter. */
|
|
86
|
+
export function searchSouls(query: string, archetype?: string): SoulTemplate[] {
|
|
87
|
+
const q = query.toLowerCase().trim()
|
|
88
|
+
let results = SOUL_LIBRARY
|
|
89
|
+
|
|
90
|
+
if (archetype && archetype !== 'All') {
|
|
91
|
+
results = results.filter((s) => s.archetype === archetype)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!q) return results
|
|
95
|
+
|
|
96
|
+
return results.filter(
|
|
97
|
+
(s) =>
|
|
98
|
+
s.name.toLowerCase().includes(q) ||
|
|
99
|
+
s.description.toLowerCase().includes(q) ||
|
|
100
|
+
s.tags.some((t) => t.includes(q)) ||
|
|
101
|
+
s.soul.toLowerCase().includes(q),
|
|
102
|
+
)
|
|
103
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createHash } from 'crypto'
|
|
2
|
+
import type { BoardTask } from '@/types'
|
|
3
|
+
|
|
4
|
+
/** SHA-256 fingerprint from title + agentId, first 16 hex chars. */
|
|
5
|
+
export function computeTaskFingerprint(title: string, agentId: string): string {
|
|
6
|
+
const input = `${title.trim().toLowerCase()}::${agentId}`
|
|
7
|
+
return createHash('sha256').update(input).digest('hex').slice(0, 16)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const TERMINAL_STATUSES = new Set(['completed', 'archived', 'failed'])
|
|
11
|
+
|
|
12
|
+
/** Find an existing non-terminal task with the same fingerprint. */
|
|
13
|
+
export function findDuplicateTask(
|
|
14
|
+
tasks: Record<string, BoardTask>,
|
|
15
|
+
candidate: { fingerprint: string },
|
|
16
|
+
): BoardTask | null {
|
|
17
|
+
for (const task of Object.values(tasks)) {
|
|
18
|
+
if (
|
|
19
|
+
task.fingerprint === candidate.fingerprint &&
|
|
20
|
+
!TERMINAL_STATUSES.has(task.status)
|
|
21
|
+
) {
|
|
22
|
+
return task
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
@@ -22,6 +22,8 @@ export const AVAILABLE_TOOLS: ToolDefinition[] = [
|
|
|
22
22
|
{ id: 'sandbox', label: 'Sandbox', description: 'Run JS/TS/Python code in an isolated Deno sandbox' },
|
|
23
23
|
{ id: 'create_document', label: 'Create Document', description: 'Render markdown to PDF, HTML, or image' },
|
|
24
24
|
{ id: 'create_spreadsheet', label: 'Create Spreadsheet', description: 'Create Excel or CSV files from structured data' },
|
|
25
|
+
{ id: 'http_request', label: 'HTTP Request', description: 'Make HTTP API calls (GET, POST, PUT, DELETE, etc.)' },
|
|
26
|
+
{ id: 'git', label: 'Git', description: 'Run structured git operations (status, commit, push, diff, etc.)' },
|
|
25
27
|
]
|
|
26
28
|
|
|
27
29
|
export const PLATFORM_TOOLS: ToolDefinition[] = [
|
package/src/lib/tts.ts
CHANGED
|
@@ -10,7 +10,7 @@ export function initAudioContext() {
|
|
|
10
10
|
ensureContext()
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export async function speak(text: string) {
|
|
13
|
+
export async function speak(text: string, voiceId?: string | null) {
|
|
14
14
|
if (currentSource) {
|
|
15
15
|
try { currentSource.stop() } catch { /* noop */ }
|
|
16
16
|
currentSource = null
|
|
@@ -21,7 +21,7 @@ export async function speak(text: string) {
|
|
|
21
21
|
const res = await fetch('/api/tts', {
|
|
22
22
|
method: 'POST',
|
|
23
23
|
headers: { 'Content-Type': 'application/json' },
|
|
24
|
-
body: JSON.stringify({ text: text.slice(0, 2000) }),
|
|
24
|
+
body: JSON.stringify({ text: text.slice(0, 2000), ...(voiceId ? { voiceId } : {}) }),
|
|
25
25
|
})
|
|
26
26
|
if (!res.ok) return
|
|
27
27
|
|
|
@@ -98,6 +98,8 @@ interface AppState {
|
|
|
98
98
|
setTaskSheetOpen: (open: boolean) => void
|
|
99
99
|
editingTaskId: string | null
|
|
100
100
|
setEditingTaskId: (id: string | null) => void
|
|
101
|
+
taskSheetViewOnly: boolean
|
|
102
|
+
setTaskSheetViewOnly: (v: boolean) => void
|
|
101
103
|
|
|
102
104
|
// Provider configs (custom providers)
|
|
103
105
|
providerConfigs: ProviderConfig[]
|
|
@@ -460,9 +462,11 @@ export const useAppStore = create<AppState>((set, get) => ({
|
|
|
460
462
|
get().loadTasks(show)
|
|
461
463
|
},
|
|
462
464
|
taskSheetOpen: false,
|
|
463
|
-
setTaskSheetOpen: (open) => set({ taskSheetOpen: open }),
|
|
465
|
+
setTaskSheetOpen: (open) => set({ taskSheetOpen: open, ...(open ? {} : { taskSheetViewOnly: false }) }),
|
|
464
466
|
editingTaskId: null,
|
|
465
467
|
setEditingTaskId: (id) => set({ editingTaskId: id }),
|
|
468
|
+
taskSheetViewOnly: false,
|
|
469
|
+
setTaskSheetViewOnly: (v) => set({ taskSheetViewOnly: v }),
|
|
466
470
|
|
|
467
471
|
// Provider configs (custom providers)
|
|
468
472
|
providerConfigs: [],
|
|
@@ -103,6 +103,15 @@ interface ChatState {
|
|
|
103
103
|
addQueuedMessage: (text: string) => void
|
|
104
104
|
removeQueuedMessage: (index: number) => void
|
|
105
105
|
shiftQueuedMessage: () => string | undefined
|
|
106
|
+
|
|
107
|
+
// Context clearing
|
|
108
|
+
clearContext: () => Promise<void>
|
|
109
|
+
|
|
110
|
+
// Pagination
|
|
111
|
+
hasMoreMessages: boolean
|
|
112
|
+
loadingMore: boolean
|
|
113
|
+
totalMessages: number
|
|
114
|
+
loadMoreMessages: () => Promise<void>
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
// Module-level cadence interval (not in state to avoid re-renders)
|
|
@@ -130,7 +139,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|
|
130
139
|
displayText: '',
|
|
131
140
|
agentStatus: null,
|
|
132
141
|
messages: [],
|
|
133
|
-
setMessages: (msgs) => set({ messages: msgs, toolEvents: [] }),
|
|
142
|
+
setMessages: (msgs) => set({ messages: msgs, toolEvents: [], hasMoreMessages: false, totalMessages: msgs.length }),
|
|
134
143
|
toolEvents: [],
|
|
135
144
|
clearToolEvents: () => set({ toolEvents: [] }),
|
|
136
145
|
lastUsage: null,
|
|
@@ -276,7 +285,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|
|
276
285
|
set({ displayText: fullText })
|
|
277
286
|
}
|
|
278
287
|
} else if (event.t === 'md') {
|
|
279
|
-
// Parse metadata events (usage/run/queue). Ignore unknown keys.
|
|
288
|
+
// Parse metadata events (usage/run/queue/thinking). Ignore unknown keys.
|
|
280
289
|
try {
|
|
281
290
|
const meta = JSON.parse(event.text || '{}')
|
|
282
291
|
if (meta.usage) {
|
|
@@ -285,6 +294,9 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|
|
285
294
|
if (meta.suggestions) {
|
|
286
295
|
suggestions = meta.suggestions
|
|
287
296
|
}
|
|
297
|
+
if (meta.thinking && typeof meta.thinking === 'string') {
|
|
298
|
+
set({ thinkingText: meta.thinking })
|
|
299
|
+
}
|
|
288
300
|
} catch {
|
|
289
301
|
// Ignore non-JSON metadata payloads.
|
|
290
302
|
}
|
|
@@ -349,11 +361,13 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|
|
349
361
|
if (get().soundEnabled && soundFiredStart) playStreamEnd()
|
|
350
362
|
if (fullText.trim()) {
|
|
351
363
|
const currentToolEvents = get().toolEvents
|
|
364
|
+
const thinkingSnapshot = get().thinkingText || undefined
|
|
352
365
|
const assistantMsg: Message = {
|
|
353
366
|
role: 'assistant',
|
|
354
367
|
text: fullText.trim(),
|
|
355
368
|
time: Date.now(),
|
|
356
369
|
kind: 'chat',
|
|
370
|
+
thinking: thinkingSnapshot,
|
|
357
371
|
toolEvents: currentToolEvents.length ? currentToolEvents.map(e => ({
|
|
358
372
|
name: e.name,
|
|
359
373
|
input: e.input,
|
|
@@ -525,6 +539,55 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|
|
525
539
|
useAppStore.getState().loadSessions()
|
|
526
540
|
},
|
|
527
541
|
|
|
542
|
+
clearContext: async () => {
|
|
543
|
+
const sessionId = useAppStore.getState().currentSessionId
|
|
544
|
+
if (!sessionId || get().streaming) return
|
|
545
|
+
const marker: Message = { role: 'user', text: '', kind: 'context-clear', time: Date.now() }
|
|
546
|
+
set((s) => ({ messages: [...s.messages, marker] }))
|
|
547
|
+
try {
|
|
548
|
+
const key = getStoredAccessKey()
|
|
549
|
+
await fetch(`/api/sessions/${sessionId}/messages`, {
|
|
550
|
+
method: 'POST',
|
|
551
|
+
headers: { 'Content-Type': 'application/json', ...(key ? { 'X-Access-Key': key } : {}) },
|
|
552
|
+
body: JSON.stringify({ kind: 'context-clear' }),
|
|
553
|
+
})
|
|
554
|
+
} catch {
|
|
555
|
+
// Ignore — marker is already in local state
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
|
|
559
|
+
hasMoreMessages: false,
|
|
560
|
+
loadingMore: false,
|
|
561
|
+
totalMessages: 0,
|
|
562
|
+
loadMoreMessages: async () => {
|
|
563
|
+
const { messages, loadingMore, hasMoreMessages, totalMessages } = get()
|
|
564
|
+
if (loadingMore || !hasMoreMessages) return
|
|
565
|
+
const sessionId = useAppStore.getState().currentSessionId
|
|
566
|
+
if (!sessionId) return
|
|
567
|
+
set({ loadingMore: true })
|
|
568
|
+
try {
|
|
569
|
+
const key = getStoredAccessKey()
|
|
570
|
+
// Find the earliest message's original index (startIndex tracked on initial load)
|
|
571
|
+
const currentStartIndex = totalMessages - messages.length
|
|
572
|
+
const res = await fetch(`/api/sessions/${sessionId}/messages?limit=100&before=${currentStartIndex}`, {
|
|
573
|
+
headers: key ? { 'X-Access-Key': key } : undefined,
|
|
574
|
+
})
|
|
575
|
+
if (res.ok) {
|
|
576
|
+
const data = await res.json() as { messages: Message[]; total: number; hasMore: boolean; startIndex: number }
|
|
577
|
+
set((s) => ({
|
|
578
|
+
messages: [...data.messages, ...s.messages],
|
|
579
|
+
hasMoreMessages: data.hasMore,
|
|
580
|
+
totalMessages: data.total,
|
|
581
|
+
loadingMore: false,
|
|
582
|
+
}))
|
|
583
|
+
} else {
|
|
584
|
+
set({ loadingMore: false })
|
|
585
|
+
}
|
|
586
|
+
} catch {
|
|
587
|
+
set({ loadingMore: false })
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
|
|
528
591
|
stopStreaming: async () => {
|
|
529
592
|
const sessionId = useAppStore.getState().currentSessionId
|
|
530
593
|
if (sessionId) {
|
package/src/types/index.ts
CHANGED
|
@@ -13,11 +13,13 @@ export interface Message {
|
|
|
13
13
|
imageUrl?: string
|
|
14
14
|
attachedFiles?: string[]
|
|
15
15
|
toolEvents?: MessageToolEvent[]
|
|
16
|
-
|
|
16
|
+
thinking?: string
|
|
17
|
+
kind?: 'chat' | 'heartbeat' | 'system' | 'context-clear'
|
|
17
18
|
suppressed?: boolean
|
|
18
19
|
bookmarked?: boolean
|
|
19
20
|
suggestions?: string[]
|
|
20
21
|
replyToId?: string
|
|
22
|
+
source?: MessageSource
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export type ProviderType = 'claude-cli' | 'codex-cli' | 'opencode-cli' | 'openai' | 'ollama' | 'anthropic' | 'openclaw' | 'google' | 'deepseek' | 'groq' | 'together' | 'mistral' | 'xai' | 'fireworks'
|
|
@@ -114,6 +116,7 @@ export interface Session {
|
|
|
114
116
|
queuedCount?: number
|
|
115
117
|
currentRunId?: string | null
|
|
116
118
|
conversationTone?: string
|
|
119
|
+
canvasContent?: string | null
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
export type Sessions = Record<string, Session>
|
|
@@ -128,6 +131,10 @@ export type SessionTool =
|
|
|
128
131
|
| 'web_fetch'
|
|
129
132
|
| 'edit_file'
|
|
130
133
|
| 'process'
|
|
134
|
+
| 'spawn_subagent'
|
|
135
|
+
| 'canvas'
|
|
136
|
+
| 'http_request'
|
|
137
|
+
| 'git'
|
|
131
138
|
|
|
132
139
|
// --- Cost Tracking ---
|
|
133
140
|
|
|
@@ -254,6 +261,7 @@ export interface Agent {
|
|
|
254
261
|
heartbeatGoal?: string | null
|
|
255
262
|
heartbeatNextAction?: string | null
|
|
256
263
|
thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high'
|
|
264
|
+
elevenLabsVoiceId?: string | null
|
|
257
265
|
projectId?: string
|
|
258
266
|
avatarSeed?: string
|
|
259
267
|
pinned?: boolean
|
|
@@ -339,6 +347,10 @@ export interface MemoryEntry {
|
|
|
339
347
|
linkedMemoryIds?: string[]
|
|
340
348
|
pinned?: boolean
|
|
341
349
|
sharedWith?: string[]
|
|
350
|
+
accessCount?: number
|
|
351
|
+
lastAccessedAt?: number
|
|
352
|
+
contentHash?: string
|
|
353
|
+
reinforcementCount?: number
|
|
342
354
|
createdAt: number
|
|
343
355
|
updatedAt: number
|
|
344
356
|
}
|
|
@@ -367,6 +379,7 @@ export interface ChatroomMessage {
|
|
|
367
379
|
attachedFiles?: string[]
|
|
368
380
|
imagePath?: string
|
|
369
381
|
replyToId?: string
|
|
382
|
+
source?: MessageSource
|
|
370
383
|
}
|
|
371
384
|
|
|
372
385
|
export interface Chatroom {
|
|
@@ -503,9 +516,12 @@ export interface AppSettings {
|
|
|
503
516
|
claudeCodeTimeoutSec?: number
|
|
504
517
|
cliProcessTimeoutSec?: number
|
|
505
518
|
userAvatarSeed?: string
|
|
519
|
+
elevenLabsEnabled?: boolean
|
|
506
520
|
elevenLabsApiKey?: string | null
|
|
507
521
|
elevenLabsVoiceId?: string | null
|
|
508
522
|
speechRecognitionLang?: string | null
|
|
523
|
+
tavilyApiKey?: string | null
|
|
524
|
+
braveApiKey?: string | null
|
|
509
525
|
heartbeatPrompt?: string | null
|
|
510
526
|
heartbeatIntervalSec?: number | null
|
|
511
527
|
heartbeatInterval?: string | number | null
|
|
@@ -545,6 +561,8 @@ export interface AppSettings {
|
|
|
545
561
|
maxLinkedMemoriesExpanded?: number
|
|
546
562
|
memoryMaxDepth?: number
|
|
547
563
|
memoryMaxPerLookup?: number
|
|
564
|
+
// Chat UX
|
|
565
|
+
suggestionsEnabled?: boolean
|
|
548
566
|
// Voice conversation
|
|
549
567
|
voiceAutoSendDelaySec?: number
|
|
550
568
|
// Default agent for main chat on startup
|
|
@@ -624,11 +642,19 @@ export interface Skill {
|
|
|
624
642
|
export type ConnectorPlatform = 'discord' | 'telegram' | 'slack' | 'whatsapp' | 'openclaw' | 'bluebubbles' | 'signal' | 'teams' | 'googlechat' | 'matrix'
|
|
625
643
|
export type ConnectorStatus = 'stopped' | 'running' | 'error'
|
|
626
644
|
|
|
645
|
+
export interface MessageSource {
|
|
646
|
+
platform: ConnectorPlatform
|
|
647
|
+
connectorId: string
|
|
648
|
+
connectorName: string
|
|
649
|
+
senderName?: string
|
|
650
|
+
}
|
|
651
|
+
|
|
627
652
|
export interface Connector {
|
|
628
653
|
id: string
|
|
629
654
|
name: string
|
|
630
655
|
platform: ConnectorPlatform
|
|
631
|
-
agentId
|
|
656
|
+
agentId?: string | null // which agent handles incoming messages (optional if using chatroomId)
|
|
657
|
+
chatroomId?: string | null // route to a chatroom instead of a single agent
|
|
632
658
|
credentialId?: string | null // bot token stored as encrypted credential
|
|
633
659
|
config: Record<string, string> // platform-specific settings
|
|
634
660
|
isEnabled: boolean
|
|
@@ -736,6 +762,10 @@ export interface BoardTask {
|
|
|
736
762
|
dueAt?: number | null
|
|
737
763
|
// Custom fields
|
|
738
764
|
customFields?: Record<string, string | number | boolean>
|
|
765
|
+
// Priority
|
|
766
|
+
priority?: 'low' | 'medium' | 'high' | 'critical'
|
|
767
|
+
// Dedup fingerprint
|
|
768
|
+
fingerprint?: string
|
|
739
769
|
}
|
|
740
770
|
|
|
741
771
|
// --- MCP Servers ---
|