clawport-ui 0.8.2 → 0.8.3

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 CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/clawport-ui.svg)](https://www.npmjs.com/package/clawport-ui)
10
10
  [![license](https://img.shields.io/npm/l/clawport-ui.svg)](LICENSE)
11
- [![tests](https://img.shields.io/badge/tests-536%20passed-brightgreen)](#testing)
11
+ [![tests](https://img.shields.io/badge/tests-771%20passed-brightgreen)](#testing)
12
12
 
13
13
  [Website](https://clawport.dev) | [Setup Guide](SETUP.md) | [API Docs](docs/API.md) | [npm](https://www.npmjs.com/package/clawport-ui)
14
14
 
@@ -171,7 +171,7 @@ clawport help # Show usage
171
171
  ## Testing
172
172
 
173
173
  ```bash
174
- npm test # 536 tests across 24 suites (Vitest)
174
+ npm test # 771 tests across 31 suites (Vitest)
175
175
  npx tsc --noEmit # Type-check (zero errors)
176
176
  npx next build # Production build
177
177
  ```
@@ -490,6 +490,22 @@ export default function AgentDetailPage({
490
490
  >
491
491
  {agent.title}
492
492
  </p>
493
+ {agent.model && (
494
+ <span
495
+ style={{
496
+ display: "inline-block",
497
+ marginTop: "var(--space-1)",
498
+ fontSize: "var(--text-caption2)",
499
+ fontFamily: "var(--font-mono)",
500
+ color: "var(--text-tertiary)",
501
+ background: "var(--fill-secondary)",
502
+ padding: "1px 8px",
503
+ borderRadius: 6,
504
+ }}
505
+ >
506
+ {agent.model.split("/").pop()}
507
+ </span>
508
+ )}
493
509
  {/* Color swatch */}
494
510
  <div
495
511
  style={{
@@ -93,7 +93,7 @@ export async function POST(
93
93
 
94
94
  try {
95
95
  const stream = await openai.chat.completions.create({
96
- model: 'claude-sonnet-4-6',
96
+ model: agent.model || 'claude-sonnet-4-6',
97
97
  stream: true,
98
98
  messages: [
99
99
  { role: 'system' as const, content: systemPrompt },
@@ -90,7 +90,7 @@ Help the user with this ticket. Stay in character as ${agent.name}, ${agent.titl
90
90
 
91
91
  try {
92
92
  const stream = await openai.chat.completions.create({
93
- model: 'claude-sonnet-4-6',
93
+ model: agent.model || 'claude-sonnet-4-6',
94
94
  stream: true,
95
95
  messages: [
96
96
  { role: 'system' as const, content: systemPrompt },
@@ -129,6 +129,24 @@ export function AgentNode({ data, selected }: NodeProps) {
129
129
  {reportCount} reports
130
130
  </span>
131
131
  )}
132
+ {agent.model && (
133
+ <span
134
+ style={{
135
+ fontSize: "var(--text-caption2)",
136
+ fontWeight: "var(--weight-medium)",
137
+ color: "var(--text-tertiary)",
138
+ background: "var(--fill-tertiary)",
139
+ padding: "1px 7px",
140
+ borderRadius: 10,
141
+ overflow: "hidden",
142
+ textOverflow: "ellipsis",
143
+ whiteSpace: "nowrap",
144
+ maxWidth: 120,
145
+ }}
146
+ >
147
+ {agent.model.split("/").pop()}
148
+ </span>
149
+ )}
132
150
  {hasCrons && (
133
151
  <span
134
152
  style={{
@@ -725,7 +725,7 @@ export function ConversationView({ agent, conversation, onUpdate, onBack }: Conv
725
725
  textOverflow: 'ellipsis',
726
726
  whiteSpace: 'nowrap',
727
727
  }}>
728
- {agent.title}{messages.length > 1 && ' · Synced'}
728
+ {agent.title}{agent.model && ` · ${agent.model.split('/').pop()}`}{messages.length > 1 && ' · Synced'}
729
729
  </div>
730
730
  </div>
731
731
  </div>
@@ -208,6 +208,7 @@ function discoverAgents(workspacePath: string): AgentEntry[] | null {
208
208
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
209
209
  emoji: rootEmoji,
210
210
  tools: ['read', 'write', 'exec', 'message'],
211
+ model: null,
211
212
  memoryPath: null,
212
213
  description: 'Top-level orchestrator.',
213
214
  })
@@ -252,6 +253,7 @@ function discoverAgents(workspacePath: string): AgentEntry[] | null {
252
253
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
253
254
  emoji: subName.charAt(0).toUpperCase(),
254
255
  tools: ['read', 'write'],
256
+ model: null,
255
257
  memoryPath: null,
256
258
  description: `${subName} agent.`,
257
259
  })
@@ -275,6 +277,7 @@ function discoverAgents(workspacePath: string): AgentEntry[] | null {
275
277
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
276
278
  emoji: subName.charAt(0).toUpperCase(),
277
279
  tools: ['read', 'write'],
280
+ model: null,
278
281
  memoryPath: null,
279
282
  description: `${subName} agent.`,
280
283
  })
@@ -343,6 +346,7 @@ function discoverAgents(workspacePath: string): AgentEntry[] | null {
343
346
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
344
347
  emoji: subName.charAt(0).toUpperCase(),
345
348
  tools: ['read', 'write'],
349
+ model: null,
346
350
  memoryPath: null,
347
351
  description: `${subName} agent.`,
348
352
  })
@@ -369,6 +373,7 @@ function discoverAgents(workspacePath: string): AgentEntry[] | null {
369
373
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
370
374
  emoji: subName.charAt(0).toUpperCase(),
371
375
  tools: ['read', 'write'],
376
+ model: null,
372
377
  memoryPath: null,
373
378
  description: `${subName} agent.`,
374
379
  })
@@ -385,6 +390,7 @@ function discoverAgents(workspacePath: string): AgentEntry[] | null {
385
390
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
386
391
  emoji: name.charAt(0).toUpperCase(),
387
392
  tools: ['read', 'write'],
393
+ model: null,
388
394
  memoryPath: null,
389
395
  description: `${name} agent.`,
390
396
  })
@@ -408,6 +414,7 @@ interface CliAgentEntry {
408
414
  id: string
409
415
  identityName?: string
410
416
  identityEmoji?: string
417
+ model?: string
411
418
  workspace?: string
412
419
  isDefault?: boolean
413
420
  }
@@ -457,6 +464,12 @@ function mergeExtraWorkspaces(
457
464
  // Try discovering agents from this workspace's filesystem
458
465
  const discovered = discoverAgents(ws)
459
466
  if (discovered) {
467
+ // Enrich with model from this CLI agent
468
+ if (cli.model) {
469
+ for (const d of discovered) {
470
+ if (!d.model) d.model = cli.model
471
+ }
472
+ }
460
473
  for (const agent of discovered) {
461
474
  if (existingIds.has(agent.id)) continue
462
475
  // Agents from other workspaces are top-level peers (no cross-workspace hierarchy)
@@ -482,6 +495,7 @@ function mergeExtraWorkspaces(
482
495
  color: DISCOVER_COLORS[colorIndex++ % DISCOVER_COLORS.length],
483
496
  emoji: cli.identityEmoji || name.charAt(0).toUpperCase(),
484
497
  tools: ['read', 'write'],
498
+ model: cli.model || null,
485
499
  memoryPath: null,
486
500
  description: `${name} agent.`,
487
501
  })
@@ -492,6 +506,29 @@ function mergeExtraWorkspaces(
492
506
  return [...existing, ...added]
493
507
  }
494
508
 
509
+ /**
510
+ * Enrich filesystem-discovered agents with model data from CLI output.
511
+ *
512
+ * All agents in a workspace share the CLI agent's configured model.
513
+ * CLI agents are matched to discovered agents by workspace path.
514
+ */
515
+ function enrichModelsFromCli(
516
+ agents: AgentEntry[],
517
+ cliAgents: CliAgentEntry[],
518
+ primaryWorkspace: string,
519
+ ): void {
520
+ // Find CLI agent(s) for the primary workspace — take the default or first match
521
+ const primaryCli = cliAgents.find(c => c.workspace === primaryWorkspace && c.isDefault)
522
+ || cliAgents.find(c => c.workspace === primaryWorkspace)
523
+ if (primaryCli?.model) {
524
+ for (const agent of agents) {
525
+ if (!agent.model) {
526
+ agent.model = primaryCli.model
527
+ }
528
+ }
529
+ }
530
+ }
531
+
495
532
  /**
496
533
  * Load the agent registry.
497
534
  *
@@ -521,11 +558,14 @@ export function loadRegistry(): AgentEntry[] {
521
558
  // 2. Auto-discover from primary workspace filesystem
522
559
  const discovered = discoverAgents(workspacePath)
523
560
 
524
- // 2b. Merge agents from other workspaces known to the CLI
561
+ // 2b. Enrich with CLI model data + merge other workspaces
525
562
  if (discovered && openclawBin) {
526
563
  const cliAgents = listCliAgents(openclawBin)
527
- if (cliAgents && cliAgents.length > 1) {
528
- return mergeExtraWorkspaces(discovered, cliAgents, workspacePath)
564
+ if (cliAgents) {
565
+ enrichModelsFromCli(discovered, cliAgents, workspacePath)
566
+ if (cliAgents.length > 1) {
567
+ return mergeExtraWorkspaces(discovered, cliAgents, workspacePath)
568
+ }
529
569
  }
530
570
  return discovered
531
571
  }
package/lib/agents.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "color": "#f5c518",
11
11
  "emoji": "\ud83e\udd16",
12
12
  "tools": ["exec", "read", "write", "edit", "web_search", "tts", "message", "sessions_spawn", "memory_search"],
13
+ "model": null,
13
14
  "memoryPath": null,
14
15
  "description": "Top-level orchestrator. Manages the team, holds memory, delivers briefings."
15
16
  },
@@ -24,6 +25,7 @@
24
25
  "color": "#a855f7",
25
26
  "emoji": "\u265f\ufe0f",
26
27
  "tools": ["web_search", "web_fetch", "read", "write", "sessions_spawn"],
28
+ "model": null,
27
29
  "memoryPath": null,
28
30
  "description": "CSO. Manages validation team. Decides what gets built and what gets killed."
29
31
  },
@@ -38,6 +40,7 @@
38
40
  "color": "#3b82f6",
39
41
  "emoji": "\ud83e\udd85",
40
42
  "tools": ["web_search", "web_fetch", "read", "write", "message"],
43
+ "model": null,
41
44
  "memoryPath": null,
42
45
  "description": "Field operator. Competitive intel, opportunity scouting, lead signals."
43
46
  },
@@ -52,6 +55,7 @@
52
55
  "color": "#06b6d4",
53
56
  "emoji": "\ud83d\udd0d",
54
57
  "tools": ["web_search", "web_fetch", "read", "write"],
58
+ "model": null,
55
59
  "memoryPath": null,
56
60
  "description": "Market research. TAM, competitors, pricing benchmarks. Returns Market Briefs."
57
61
  },
@@ -66,6 +70,7 @@
66
70
  "color": "#06b6d4",
67
71
  "emoji": "\u2705",
68
72
  "tools": ["web_search", "web_fetch", "read", "write"],
73
+ "model": null,
69
74
  "memoryPath": null,
70
75
  "description": "Designs minimum viable tests. Writes outreach copy. Calls BUILD/KILL/PIVOT."
71
76
  },
@@ -80,6 +85,7 @@
80
85
  "color": "#22c55e",
81
86
  "emoji": "\ud83d\udd26",
82
87
  "tools": ["web_search", "web_fetch", "read", "write", "exec"],
88
+ "model": null,
83
89
  "memoryPath": null,
84
90
  "description": "SEO Team Director. Runs SCOUT\u2192ANALYST\u2192STRATEGIST\u2192WRITER pipeline."
85
91
  },
@@ -94,6 +100,7 @@
94
100
  "color": "#86efac",
95
101
  "emoji": "\ud83d\uddfa\ufe0f",
96
102
  "tools": ["web_search", "web_fetch", "read"],
103
+ "model": null,
97
104
  "memoryPath": null,
98
105
  "description": "Scouts trending topics, pulls RSS feeds, identifies content opportunities."
99
106
  },
@@ -108,6 +115,7 @@
108
115
  "color": "#86efac",
109
116
  "emoji": "\ud83d\udcca",
110
117
  "tools": ["web_search", "web_fetch", "read", "write"],
118
+ "model": null,
111
119
  "memoryPath": null,
112
120
  "description": "Keyword research, GSC data analysis, competitive gap identification."
113
121
  },
@@ -122,6 +130,7 @@
122
130
  "color": "#86efac",
123
131
  "emoji": "\ud83c\udfaf",
124
132
  "tools": ["read", "write"],
133
+ "model": null,
125
134
  "memoryPath": null,
126
135
  "description": "Topic angle selection using SAGE and ECHO briefs."
127
136
  },
@@ -136,6 +145,7 @@
136
145
  "color": "#86efac",
137
146
  "emoji": "\u270d\ufe0f",
138
147
  "tools": ["read", "write"],
148
+ "model": null,
139
149
  "memoryPath": null,
140
150
  "description": "1500-2000 word posts in the operator's voice."
141
151
  },
@@ -150,6 +160,7 @@
150
160
  "color": "#86efac",
151
161
  "emoji": "\ud83d\udee1\ufe0f",
152
162
  "tools": ["read", "write"],
163
+ "model": null,
153
164
  "memoryPath": null,
154
165
  "description": "Pre-ship quality gate. 6-item checklist before publishing."
155
166
  },
@@ -164,6 +175,7 @@
164
175
  "color": "#f97316",
165
176
  "emoji": "\ud83d\udce3",
166
177
  "tools": ["web_search", "web_fetch", "read", "write", "message", "exec"],
178
+ "model": null,
167
179
  "memoryPath": null,
168
180
  "description": "LinkedIn content pipeline. Reads Pulse feed, picks angles, briefs QUILL."
169
181
  },
@@ -178,6 +190,7 @@
178
190
  "color": "#fdba74",
179
191
  "emoji": "\ud83d\udd8a\ufe0f",
180
192
  "tools": ["read", "write"],
193
+ "model": null,
181
194
  "memoryPath": null,
182
195
  "description": "Writes LinkedIn posts in the operator's voice."
183
196
  },
@@ -192,6 +205,7 @@
192
205
  "color": "#fdba74",
193
206
  "emoji": "\ud83e\udded",
194
207
  "tools": ["web_search", "read", "write"],
208
+ "model": null,
195
209
  "memoryPath": null,
196
210
  "description": "Weekly LinkedIn strategy and content calendar."
197
211
  },
@@ -206,6 +220,7 @@
206
220
  "color": "#eab308",
207
221
  "emoji": "\ud83c\udf0a",
208
222
  "tools": ["web_search", "web_fetch", "read", "write", "message"],
223
+ "model": null,
209
224
  "memoryPath": null,
210
225
  "description": "Hype radar. Monitors trending signals. Feeds hot topics to LUMEN."
211
226
  },
@@ -220,6 +235,7 @@
220
235
  "color": "#14b8a6",
221
236
  "emoji": "\ud83d\udce1",
222
237
  "tools": ["web_fetch", "read", "write"],
238
+ "model": null,
223
239
  "memoryPath": null,
224
240
  "description": "Scans ICP subreddits weekly. Extracts verbatim customer language."
225
241
  },
@@ -234,6 +250,7 @@
234
250
  "color": "#14b8a6",
235
251
  "emoji": "\ud83e\uddd9",
236
252
  "tools": ["read"],
253
+ "model": null,
237
254
  "memoryPath": null,
238
255
  "description": "Deep ICP and market knowledge. Injected into STRATEGIST and WRITER."
239
256
  },
@@ -248,6 +265,7 @@
248
265
  "color": "#60a5fa",
249
266
  "emoji": "\u2708\ufe0f",
250
267
  "tools": ["web_fetch", "message"],
268
+ "model": null,
251
269
  "memoryPath": null,
252
270
  "description": "Monitors MSP to Tokyo flights. Alerts on deals under $1400."
253
271
  },
@@ -262,6 +280,7 @@
262
280
  "color": "#f59e0b",
263
281
  "emoji": "\u26a1",
264
282
  "tools": ["web_fetch", "web_search", "message"],
283
+ "model": null,
265
284
  "memoryPath": null,
266
285
  "description": "Finds cool OpenClaw builds. Reports every other day."
267
286
  },
@@ -276,6 +295,7 @@
276
295
  "color": "#94a3b8",
277
296
  "emoji": "\ud83d\udcda",
278
297
  "tools": ["read", "write", "exec"],
298
+ "model": null,
279
299
  "memoryPath": null,
280
300
  "description": "Weekly memory compression. Silent worker."
281
301
  }
@@ -18,6 +18,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
18
18
  color: '#f5c518',
19
19
  emoji: 'R',
20
20
  tools: ['exec', 'read', 'write'],
21
+ model: null,
21
22
  memoryPath: null,
22
23
  description: 'Top-level orchestrator.',
23
24
  },
@@ -32,6 +33,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
32
33
  color: '#a855f7',
33
34
  emoji: 'P',
34
35
  tools: ['web_search', 'read'],
36
+ model: null,
35
37
  memoryPath: null,
36
38
  description: 'CSO. Decides what gets built.',
37
39
  },
@@ -46,6 +48,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
46
48
  color: '#3b82f6',
47
49
  emoji: 'E',
48
50
  tools: ['web_search'],
51
+ model: null,
49
52
  memoryPath: null,
50
53
  description: 'Field operator.',
51
54
  },
@@ -60,6 +63,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
60
63
  color: '#22c55e',
61
64
  emoji: 'L',
62
65
  tools: ['web_search', 'read'],
66
+ model: null,
63
67
  memoryPath: null,
64
68
  description: 'SEO Team Director.',
65
69
  },
@@ -74,6 +78,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
74
78
  color: '#86efac',
75
79
  emoji: 'S',
76
80
  tools: ['web_search'],
81
+ model: null,
77
82
  memoryPath: null,
78
83
  description: 'Scouts trending topics.',
79
84
  },
@@ -88,6 +93,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
88
93
  color: '#eab308',
89
94
  emoji: 'W',
90
95
  tools: ['web_search'],
96
+ model: null,
91
97
  memoryPath: null,
92
98
  description: 'Hype radar.',
93
99
  },
@@ -102,6 +108,7 @@ const { mockReadFileSync, mockExistsSync, mockReaddirSync, mockExecSync, bundled
102
108
  color: '#60a5fa',
103
109
  emoji: 'A',
104
110
  tools: ['web_fetch'],
111
+ model: null,
105
112
  memoryPath: null,
106
113
  description: 'Monitors flights.',
107
114
  },
@@ -1115,6 +1122,7 @@ describe('CLI agent discovery (multi-workspace)', () => {
1115
1122
  id: string
1116
1123
  identityName?: string
1117
1124
  identityEmoji?: string
1125
+ model?: string
1118
1126
  workspace?: string
1119
1127
  isDefault?: boolean
1120
1128
  }>) {
@@ -1125,7 +1133,7 @@ describe('CLI agent discovery (multi-workspace)', () => {
1125
1133
  identitySource: 'identity',
1126
1134
  workspace: e.workspace ?? '/tmp/ws',
1127
1135
  agentDir: `/home/.openclaw/agents/${e.id}/agent`,
1128
- model: 'anthropic/claude-sonnet-4-6',
1136
+ model: e.model ?? 'anthropic/claude-sonnet-4-6',
1129
1137
  bindings: 0,
1130
1138
  isDefault: e.isDefault ?? false,
1131
1139
  routes: ['default (no explicit rules)'],
@@ -1251,6 +1259,51 @@ describe('CLI agent discovery (multi-workspace)', () => {
1251
1259
  expect(emptyBot!.tools).toEqual(['read', 'write'])
1252
1260
  })
1253
1261
 
1262
+ it('flows CLI model through to minimal entry', async () => {
1263
+ setupPrimaryWorkspace()
1264
+
1265
+ const origExists = mockExistsSync.getMockImplementation()!
1266
+ mockExistsSync.mockImplementation((p: string) => {
1267
+ if (p.startsWith('/tmp/ws-model')) return false
1268
+ return origExists(p)
1269
+ })
1270
+
1271
+ mockExecSync.mockReturnValue(cliOutput([
1272
+ { id: 'main', workspace: '/tmp/ws', isDefault: true },
1273
+ { id: 'opus-bot', identityName: 'OpusBot', model: 'anthropic/claude-opus-4-6', workspace: '/tmp/ws-model' },
1274
+ ]))
1275
+
1276
+ const agents = await getAgents()
1277
+ const opusBot = agents.find(a => a.id === 'opus-bot')
1278
+ expect(opusBot).toBeDefined()
1279
+ expect(opusBot!.model).toBe('anthropic/claude-opus-4-6')
1280
+ })
1281
+
1282
+ it('enriches primary workspace agents with CLI model', async () => {
1283
+ setupPrimaryWorkspace()
1284
+ mockExecSync.mockReturnValue(cliOutput([
1285
+ { id: 'main', identityName: 'Jarvis', model: 'anthropic/claude-opus-4-6', workspace: '/tmp/ws', isDefault: true },
1286
+ ]))
1287
+
1288
+ const agents = await getAgents()
1289
+ const jarvis = agents.find(a => a.id === 'jarvis')
1290
+ expect(jarvis).toBeDefined()
1291
+ expect(jarvis!.model).toBe('anthropic/claude-opus-4-6')
1292
+ // Sub-agents in the same workspace also get the model
1293
+ const echo = agents.find(a => a.id === 'echo')
1294
+ expect(echo!.model).toBe('anthropic/claude-opus-4-6')
1295
+ })
1296
+
1297
+ it('agents stay model: null when CLI is unavailable', async () => {
1298
+ setupPrimaryWorkspace()
1299
+ mockExecSync.mockImplementation(() => { throw new Error('not found') })
1300
+
1301
+ const agents = await getAgents()
1302
+ const jarvis = agents.find(a => a.id === 'jarvis')
1303
+ expect(jarvis).toBeDefined()
1304
+ expect(jarvis!.model).toBeNull()
1305
+ })
1306
+
1254
1307
  it('does not duplicate agents already found in primary workspace', async () => {
1255
1308
  setupPrimaryWorkspace()
1256
1309
 
@@ -55,6 +55,7 @@ const fakeAgent: Agent = {
55
55
  emoji: '?',
56
56
  tools: [],
57
57
  crons: [],
58
+ model: null,
58
59
  memoryPath: null,
59
60
  description: 'CSO. Decides what gets built.',
60
61
  }
@@ -22,6 +22,7 @@ function makeAgent(overrides: Partial<Agent> = {}): Agent {
22
22
  emoji: '🤖',
23
23
  tools: [],
24
24
  crons: [],
25
+ model: null,
25
26
  memoryPath: null,
26
27
  description: 'A test agent for unit tests.',
27
28
  ...overrides,
package/lib/teams.test.ts CHANGED
@@ -17,6 +17,7 @@ function agent(overrides: Partial<Agent> & { id: string }): Agent {
17
17
  emoji: 'A',
18
18
  tools: [],
19
19
  crons: [],
20
+ model: null,
20
21
  memoryPath: null,
21
22
  description: '',
22
23
  ...overrides,
package/lib/types.ts CHANGED
@@ -11,6 +11,7 @@ export interface Agent {
11
11
  voiceId: string | null // ElevenLabs voice ID
12
12
  color: string // hex color for node
13
13
  emoji: string // emoji identifier
14
+ model: string | null // LLM model identifier (e.g. "anthropic/claude-sonnet-4-6")
14
15
  tools: string[] // list of tools this agent has access to
15
16
  crons: CronJob[] // associated cron jobs
16
17
  memoryPath: string | null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawport-ui",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Open-source dashboard for managing, monitoring, and chatting with your OpenClaw AI agents.",
5
5
  "homepage": "https://clawport.dev",
6
6
  "repository": {