slidev-addon-agent 0.0.1

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.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -0
  3. package/agent/constants.ts +119 -0
  4. package/agent/deck-context.ts +67 -0
  5. package/agent/index.ts +201 -0
  6. package/agent/middleware.ts +163 -0
  7. package/agent/skills/slidev/README.md +61 -0
  8. package/agent/skills/slidev/SKILL.md +189 -0
  9. package/agent/skills/slidev/references/animation-click-marker.md +37 -0
  10. package/agent/skills/slidev/references/animation-drawing.md +68 -0
  11. package/agent/skills/slidev/references/animation-rough-marker.md +53 -0
  12. package/agent/skills/slidev/references/api-slide-hooks.md +37 -0
  13. package/agent/skills/slidev/references/build-og-image.md +36 -0
  14. package/agent/skills/slidev/references/build-pdf.md +40 -0
  15. package/agent/skills/slidev/references/build-remote-assets.md +34 -0
  16. package/agent/skills/slidev/references/build-seo-meta.md +43 -0
  17. package/agent/skills/slidev/references/code-groups.md +64 -0
  18. package/agent/skills/slidev/references/code-import-snippet.md +55 -0
  19. package/agent/skills/slidev/references/code-line-highlighting.md +50 -0
  20. package/agent/skills/slidev/references/code-line-numbers.md +46 -0
  21. package/agent/skills/slidev/references/code-magic-move.md +57 -0
  22. package/agent/skills/slidev/references/code-max-height.md +37 -0
  23. package/agent/skills/slidev/references/code-twoslash.md +42 -0
  24. package/agent/skills/slidev/references/core-animations.md +196 -0
  25. package/agent/skills/slidev/references/core-cli.md +140 -0
  26. package/agent/skills/slidev/references/core-components.md +197 -0
  27. package/agent/skills/slidev/references/core-exporting.md +148 -0
  28. package/agent/skills/slidev/references/core-frontmatter.md +195 -0
  29. package/agent/skills/slidev/references/core-global-context.md +155 -0
  30. package/agent/skills/slidev/references/core-headmatter.md +188 -0
  31. package/agent/skills/slidev/references/core-hosting.md +152 -0
  32. package/agent/skills/slidev/references/core-layouts.md +286 -0
  33. package/agent/skills/slidev/references/core-syntax.md +155 -0
  34. package/agent/skills/slidev/references/diagram-latex.md +55 -0
  35. package/agent/skills/slidev/references/diagram-mermaid.md +44 -0
  36. package/agent/skills/slidev/references/diagram-plantuml.md +45 -0
  37. package/agent/skills/slidev/references/editor-monaco-run.md +44 -0
  38. package/agent/skills/slidev/references/editor-monaco-write.md +24 -0
  39. package/agent/skills/slidev/references/editor-monaco.md +50 -0
  40. package/agent/skills/slidev/references/editor-prettier.md +40 -0
  41. package/agent/skills/slidev/references/editor-side.md +23 -0
  42. package/agent/skills/slidev/references/editor-vscode.md +55 -0
  43. package/agent/skills/slidev/references/layout-canvas-size.md +25 -0
  44. package/agent/skills/slidev/references/layout-draggable.md +57 -0
  45. package/agent/skills/slidev/references/layout-global-layers.md +50 -0
  46. package/agent/skills/slidev/references/layout-slots.md +75 -0
  47. package/agent/skills/slidev/references/layout-transform.md +33 -0
  48. package/agent/skills/slidev/references/layout-zoom.md +39 -0
  49. package/agent/skills/slidev/references/presenter-notes-ruby.md +35 -0
  50. package/agent/skills/slidev/references/presenter-recording.md +30 -0
  51. package/agent/skills/slidev/references/presenter-remote.md +40 -0
  52. package/agent/skills/slidev/references/presenter-timer.md +34 -0
  53. package/agent/skills/slidev/references/style-direction.md +34 -0
  54. package/agent/skills/slidev/references/style-icons.md +46 -0
  55. package/agent/skills/slidev/references/style-scoped.md +50 -0
  56. package/agent/skills/slidev/references/syntax-block-frontmatter.md +39 -0
  57. package/agent/skills/slidev/references/syntax-frontmatter-merging.md +49 -0
  58. package/agent/skills/slidev/references/syntax-importing-slides.md +60 -0
  59. package/agent/skills/slidev/references/syntax-mdc.md +51 -0
  60. package/agent/skills/slidev/references/tool-eject-theme.md +27 -0
  61. package/agent/tools/export-tool.ts +216 -0
  62. package/agent/tools/review-tool.ts +136 -0
  63. package/app/index.ts +124 -0
  64. package/components/MessageItem.vue +231 -0
  65. package/components/SlidevAgentNavButton.vue +48 -0
  66. package/components/SlidevAgentSidebar.vue +766 -0
  67. package/components/SubagentCard.vue +184 -0
  68. package/components/TypingDots.vue +62 -0
  69. package/dist/agent/constants.js +117 -0
  70. package/dist/agent/deck-context.js +47 -0
  71. package/dist/agent/index.js +167 -0
  72. package/dist/agent/middleware.js +134 -0
  73. package/dist/agent/slide-preview-tool.js +257 -0
  74. package/dist/agent/tools/export-tool.js +167 -0
  75. package/dist/agent/tools/review-tool.js +111 -0
  76. package/dist/app/index.js +101 -0
  77. package/dist/bin/slidev-agent.js +155 -0
  78. package/dist/lib/bridge.js +151 -0
  79. package/dist/lib/env.js +17 -0
  80. package/dist/lib/headless-tools.js +10 -0
  81. package/dist/lib/langgraph-init.js +59 -0
  82. package/dist/lib/review-tool.js +98 -0
  83. package/lib/bridge.ts +212 -0
  84. package/lib/config.ts +79 -0
  85. package/lib/env.ts +38 -0
  86. package/lib/headless-tool-impl.ts +26 -0
  87. package/lib/headless-tools.ts +11 -0
  88. package/lib/langgraph-init.ts +79 -0
  89. package/lib/messages.ts +169 -0
  90. package/lib/render-chat-markdown.ts +19 -0
  91. package/lib/sidebar.ts +573 -0
  92. package/lib/state.ts +44 -0
  93. package/package.json +65 -0
  94. package/public/deepagents.svg +12 -0
package/lib/sidebar.ts ADDED
@@ -0,0 +1,573 @@
1
+ import { unref } from "vue"
2
+
3
+ import {
4
+ getMessageContent,
5
+ getMessageRole,
6
+ getMessageToolCallId,
7
+ getMessageToolCalls,
8
+ getMessageToolName,
9
+ } from "./messages"
10
+
11
+ export type ToolCallResult = {
12
+ call?: {
13
+ id?: string
14
+ name?: string
15
+ args?: unknown
16
+ }
17
+ result?: unknown
18
+ /** From LangGraph SDK `getToolCallsWithResults`; omitted in some code paths. */
19
+ state?: "pending" | "completed" | "error"
20
+ }
21
+
22
+ export type StreamToolCall = ToolCallResult
23
+
24
+ export type StreamSubagent = {
25
+ id: string
26
+ status: string
27
+ messages: unknown[]
28
+ toolCall: {
29
+ args?: Record<string, unknown>
30
+ id?: string
31
+ }
32
+ toolCalls: StreamToolCall[]
33
+ }
34
+
35
+ export type SubagentActivity = {
36
+ id: string
37
+ type: string
38
+ typeHeadline: string
39
+ status: string
40
+ statusLabel: string
41
+ initiatorToolCallId: string
42
+ taskSummary: string
43
+ latestToolName: string
44
+ latestToolHeadline: string
45
+ latestToolArgs: string
46
+ /** Lifecycle of the **last** subagent tool only (max one row in the UI). */
47
+ latestToolState: "pending" | "completed" | "error"
48
+ latestToolStateLabel: string
49
+ latestToolSummary: string
50
+ files: string[]
51
+ messageCount: number
52
+ hasVisibleActivity: boolean
53
+ }
54
+
55
+ type SidebarBaseMessage = {
56
+ key: string
57
+ role: string
58
+ }
59
+
60
+ export type SidebarToolMessage = SidebarBaseMessage & {
61
+ kind: "tool"
62
+ toolName: string
63
+ toolHeadline: string
64
+ argsSummary: string
65
+ resultSummary: string
66
+ }
67
+
68
+ export type SidebarTextMessage = SidebarBaseMessage & {
69
+ kind: "message"
70
+ messageId: string
71
+ label: string
72
+ content: string
73
+ subagents: SubagentActivity[]
74
+ }
75
+
76
+ export type SidebarMessage = SidebarToolMessage | SidebarTextMessage
77
+
78
+ export function normalizeMessages(value: unknown) {
79
+ const unwrapped = unref(value)
80
+ return Array.isArray(unwrapped) ? unwrapped : []
81
+ }
82
+
83
+ export function getMessageId(message: unknown): string {
84
+ if (!message || typeof message !== "object")
85
+ return ""
86
+
87
+ const id = Reflect.get(message, "id")
88
+ return typeof id === "string" ? id : ""
89
+ }
90
+
91
+ export function buildToolCallLookup(toolCalls: unknown, rawMessages: unknown[]) {
92
+ const lookup = new Map<string, ToolCallResult>()
93
+
94
+ normalizeMessages(toolCalls).forEach((entry) => {
95
+ if (!entry || typeof entry !== "object")
96
+ return
97
+
98
+ const call = Reflect.get(entry, "call")
99
+ if (!call || typeof call !== "object")
100
+ return
101
+
102
+ const id = Reflect.get(call, "id")
103
+ if (typeof id !== "string" || !id)
104
+ return
105
+
106
+ lookup.set(id, {
107
+ call: {
108
+ id,
109
+ name: typeof Reflect.get(call, "name") === "string"
110
+ ? Reflect.get(call, "name") as string
111
+ : undefined,
112
+ args: Reflect.get(call, "args"),
113
+ },
114
+ result: Reflect.get(entry, "result"),
115
+ })
116
+ })
117
+
118
+ rawMessages.forEach((message) => {
119
+ getMessageToolCalls(message).forEach((toolCall) => {
120
+ if (!toolCall.id || lookup.has(toolCall.id))
121
+ return
122
+
123
+ lookup.set(toolCall.id, { call: toolCall })
124
+ })
125
+ })
126
+
127
+ return lookup
128
+ }
129
+
130
+ export function collectActiveSubagentIds(activeSubagents: unknown) {
131
+ const ids = new Set<string>()
132
+
133
+ normalizeMessages(activeSubagents).forEach((subagent) => {
134
+ if (!subagent || typeof subagent !== "object")
135
+ return
136
+
137
+ const id = Reflect.get(subagent, "id")
138
+ if (typeof id === "string" && id)
139
+ ids.add(id)
140
+ })
141
+
142
+ return ids
143
+ }
144
+
145
+ export function truncateText(value: string, maxLength = 96) {
146
+ if (value.length <= maxLength)
147
+ return value
148
+
149
+ return `${value.slice(0, maxLength - 1)}...`
150
+ }
151
+
152
+ const TOOL_HEADLINES: Record<string, string> = {
153
+ slide_generator: "Generate or revise a slide",
154
+ slidev_go_to_slide: "Open generated slide",
155
+ slidev_review_screenshot: "Review slide screenshot",
156
+ read_file: "Read file",
157
+ write_file: "Write file",
158
+ edit_file: "Edit file",
159
+ ls: "List directory",
160
+ glob: "Find files",
161
+ grep: "Search in files",
162
+ execute: "Run command",
163
+ }
164
+
165
+ function titleCaseFromSnake(name: string) {
166
+ return name
167
+ .split(/[_\s]+/)
168
+ .filter(Boolean)
169
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
170
+ .join(" ")
171
+ }
172
+
173
+ /** User-facing label for a tool or subagent identifier (snake_case). */
174
+ export function toolCallHeadline(rawName: string) {
175
+ const trimmed = rawName.trim()
176
+ if (!trimmed)
177
+ return "Tool"
178
+
179
+ const mapped = TOOL_HEADLINES[trimmed]
180
+ if (mapped)
181
+ return mapped
182
+
183
+ return titleCaseFromSnake(trimmed)
184
+ }
185
+
186
+ export function summarizeToolResult(toolName: string, content: string) {
187
+ const trimmed = content.trim()
188
+ if (toolName === "slidev_go_to_slide") {
189
+ const toolUse = JSON.parse(content)
190
+ const payload = toolUse[Object.keys(toolUse)[0]]
191
+ return `Page: ${payload.page}`
192
+ }
193
+
194
+ if (!trimmed)
195
+ return "Completed"
196
+
197
+ const lines = trimmed.split("\n").map(line => line.trim()).filter(Boolean)
198
+ if (toolName === "read_file" && lines.length > 0)
199
+ return `${lines.length} line${lines.length === 1 ? "" : "s"}`
200
+
201
+ if (["ls", "glob", "grep"].includes(toolName) && lines.length > 0)
202
+ return `${lines.length} item${lines.length === 1 ? "" : "s"}`
203
+
204
+ return truncateText(lines[0] || trimmed)
205
+ }
206
+
207
+ export function formatToolArgs(args: unknown) {
208
+ if (!args || typeof args !== "object")
209
+ return ""
210
+
211
+ const preferredKeys = ["path", "filePath", "file_path", "pattern", "glob", "command", "page"]
212
+ return preferredKeys
213
+ .map((key) => {
214
+ const value = Reflect.get(args, key)
215
+ if (typeof value !== "string" || !value.trim())
216
+ return ""
217
+
218
+ return `${key}: ${truncateText(value.trim(), 48)}`
219
+ })
220
+ .filter(Boolean)
221
+ .join(" · ")
222
+ }
223
+
224
+ /** Prefer path-like fields; otherwise a compact JSON snapshot for subagent progress. */
225
+ export function formatToolArgsWithFallback(args: unknown, maxLength = 140) {
226
+ const preferred = formatToolArgs(args)
227
+ if (preferred)
228
+ return preferred
229
+
230
+ if (!args || typeof args !== "object")
231
+ return ""
232
+
233
+ try {
234
+ return truncateText(JSON.stringify(args), maxLength)
235
+ }
236
+ catch {
237
+ return ""
238
+ }
239
+ }
240
+
241
+ function stringifyUnknownResult(value: unknown): string {
242
+ if (typeof value === "string")
243
+ return value
244
+
245
+ if (Array.isArray(value))
246
+ return value.map(entry => stringifyUnknownResult(entry)).filter(Boolean).join("\n")
247
+
248
+ if (!value || typeof value !== "object")
249
+ return ""
250
+
251
+ const content = Reflect.get(value, "content")
252
+ if (typeof content === "string")
253
+ return content
254
+
255
+ const text = Reflect.get(value, "text")
256
+ if (typeof text === "string")
257
+ return text
258
+
259
+ return ""
260
+ }
261
+
262
+ function getStreamToolCallState(entry: StreamToolCall | undefined): "pending" | "completed" | "error" {
263
+ if (!entry)
264
+ return "pending"
265
+
266
+ if (entry.state)
267
+ return entry.state
268
+
269
+ const result = entry.result
270
+ if (result == null)
271
+ return "pending"
272
+
273
+ if (typeof result === "object" && Reflect.get(result, "status") === "error")
274
+ return "error"
275
+
276
+ return "completed"
277
+ }
278
+
279
+ function labelForSubagentToolState(state: "pending" | "completed" | "error") {
280
+ switch (state) {
281
+ case "pending":
282
+ return "Running…"
283
+ case "completed":
284
+ return "Done"
285
+ case "error":
286
+ return "Error"
287
+ }
288
+ }
289
+
290
+ function extractSubagentTask(toolCall: { args?: Record<string, unknown> } | undefined) {
291
+ const args = toolCall?.args
292
+ if (!args)
293
+ return ""
294
+
295
+ const preferredKeys = ["task", "prompt", "description", "instructions", "content", "goal"]
296
+ for (const key of preferredKeys) {
297
+ const value = Reflect.get(args, key)
298
+ if (typeof value === "string" && value.trim())
299
+ return truncateText(value.trim(), 140)
300
+ }
301
+
302
+ return ""
303
+ }
304
+
305
+ function getSubagentType(toolCall: { args?: Record<string, unknown> } | undefined) {
306
+ const subagentType = toolCall?.args?.subagent_type
307
+ return typeof subagentType === "string" && subagentType
308
+ ? subagentType
309
+ : "subagent"
310
+ }
311
+
312
+ function normalizePossiblePath(value: unknown): string | null {
313
+ if (typeof value !== "string")
314
+ return null
315
+
316
+ const normalized = value.trim()
317
+ if (!normalized)
318
+ return null
319
+
320
+ if (
321
+ normalized.includes("/")
322
+ || normalized.endsWith(".md")
323
+ || normalized.endsWith(".vue")
324
+ || normalized.endsWith(".ts")
325
+ ) {
326
+ return normalized
327
+ }
328
+
329
+ return null
330
+ }
331
+
332
+ function collectPathsFromUnknown(value: unknown, files: Set<string>) {
333
+ if (typeof value === "string") {
334
+ const maybePath = normalizePossiblePath(value)
335
+ if (maybePath)
336
+ files.add(maybePath)
337
+ return
338
+ }
339
+
340
+ if (Array.isArray(value)) {
341
+ value.forEach(entry => collectPathsFromUnknown(entry, files))
342
+ return
343
+ }
344
+
345
+ if (!value || typeof value !== "object")
346
+ return
347
+
348
+ Object.entries(value).forEach(([key, entry]) => {
349
+ if (["path", "filePath", "file_path", "paths", "glob"].includes(key))
350
+ collectPathsFromUnknown(entry, files)
351
+ })
352
+ }
353
+
354
+ function extractTouchedFiles(toolCalls: Array<{ call?: { name?: string, args?: unknown } }> | undefined) {
355
+ const files = new Set<string>()
356
+
357
+ toolCalls?.forEach((toolCall) => {
358
+ const callName = toolCall.call?.name
359
+ if (!callName)
360
+ return
361
+
362
+ if ([
363
+ "read_file",
364
+ "write_file",
365
+ "edit_file",
366
+ "ls",
367
+ "glob",
368
+ "grep",
369
+ "execute",
370
+ ].includes(callName)) {
371
+ collectPathsFromUnknown(toolCall.call?.args, files)
372
+ }
373
+ })
374
+
375
+ return Array.from(files).slice(0, 8)
376
+ }
377
+
378
+ export function getSubagentStatusPriority(status: string) {
379
+ switch (status) {
380
+ case "running":
381
+ return 0
382
+ case "pending":
383
+ return 1
384
+ case "error":
385
+ return 2
386
+ case "complete":
387
+ return 3
388
+ default:
389
+ return 4
390
+ }
391
+ }
392
+
393
+ export function summarizeSubagent(subagent: StreamSubagent, activeSubagentIds: Set<string>): SubagentActivity {
394
+ const type = getSubagentType(subagent.toolCall)
395
+ const taskSummary = extractSubagentTask(subagent.toolCall)
396
+ const files = extractTouchedFiles(subagent.toolCalls)
397
+ const messageCount = subagent.messages.length
398
+ const latestToolCall = subagent.toolCalls.at(-1)
399
+ const latestToolName = latestToolCall?.call?.name || ""
400
+ const latestToolHeadline = latestToolName ? toolCallHeadline(latestToolName) : ""
401
+ const latestToolArgs = formatToolArgsWithFallback(latestToolCall?.call?.args)
402
+ const latestToolState = getStreamToolCallState(latestToolCall)
403
+ const latestToolStateLabel = labelForSubagentToolState(latestToolState)
404
+ const resultText = stringifyUnknownResult(latestToolCall?.result)
405
+ const latestToolSummary = latestToolName && latestToolState !== "pending"
406
+ ? summarizeToolResult(latestToolName, resultText)
407
+ : ""
408
+ const isActive = activeSubagentIds.has(subagent.id) || ["running", "pending"].includes(subagent.status)
409
+ const status = isActive ? "running" : subagent.status
410
+ const statusLabel = status === "running" ? "running..." : status
411
+
412
+ return {
413
+ id: subagent.id,
414
+ type,
415
+ typeHeadline: toolCallHeadline(type),
416
+ status,
417
+ statusLabel,
418
+ initiatorToolCallId: subagent.toolCall?.id || "",
419
+ taskSummary,
420
+ latestToolName,
421
+ latestToolHeadline,
422
+ latestToolArgs,
423
+ latestToolState,
424
+ latestToolStateLabel,
425
+ latestToolSummary,
426
+ files,
427
+ messageCount,
428
+ hasVisibleActivity: Boolean(
429
+ taskSummary
430
+ || latestToolName
431
+ || files.length > 0
432
+ || messageCount > 0,
433
+ ),
434
+ }
435
+ }
436
+
437
+ export function summarizeSubagentActivities(
438
+ subagents: StreamSubagent[],
439
+ activeSubagentIds: Set<string>,
440
+ ) {
441
+ return subagents
442
+ .map(subagent => summarizeSubagent(subagent, activeSubagentIds))
443
+ .filter(subagent => subagent.hasVisibleActivity || ["running", "pending", "error"].includes(subagent.status))
444
+ .sort((left, right) => {
445
+ const statusPriority = getSubagentStatusPriority(left.status) - getSubagentStatusPriority(right.status)
446
+ if (statusPriority !== 0)
447
+ return statusPriority
448
+
449
+ return left.type.localeCompare(right.type)
450
+ })
451
+ }
452
+
453
+ function getRoleLabel(role: string) {
454
+ if (role === "human")
455
+ return "You"
456
+
457
+ if (role === "assistant" || !role)
458
+ return "Agent"
459
+
460
+ return role.charAt(0).toUpperCase() + role.slice(1)
461
+ }
462
+
463
+ function getMessageKey(message: unknown, role: string, index: number) {
464
+ const messageId = getMessageId(message)
465
+ if (messageId)
466
+ return `message:${messageId}`
467
+
468
+ const toolCallId = getMessageToolCallId(message)
469
+ if (toolCallId)
470
+ return `tool:${toolCallId}`
471
+
472
+ const content = getMessageContent(message).trim()
473
+ return `${role || "message"}:${index}:${truncateText(content, 24)}`
474
+ }
475
+
476
+ export function buildSidebarMessages(options: {
477
+ rawMessages: unknown[]
478
+ toolCallLookup: Map<string, ToolCallResult>
479
+ getSubagentsByMessage: (messageId: string) => StreamSubagent[]
480
+ activeSubagentIds: Set<string>
481
+ knownSubagentIds: Set<string>
482
+ }) {
483
+ return options.rawMessages.map((message, index): SidebarMessage => {
484
+ const role = getMessageRole(message)
485
+ const key = getMessageKey(message, role, index)
486
+
487
+ if (role === "tool") {
488
+ const toolCallId = getMessageToolCallId(message)
489
+ const toolCall = toolCallId ? options.toolCallLookup.get(toolCallId) : undefined
490
+ const inlineToolCall = getMessageToolCalls(message).at(0)
491
+ const toolName = toolCall?.call?.name || inlineToolCall?.name || getMessageToolName(message) || "tool"
492
+ const argsSummary = formatToolArgs(toolCall?.call?.args ?? inlineToolCall?.args)
493
+ const resultSummary = summarizeToolResult(toolName, getMessageContent(message))
494
+
495
+ return {
496
+ key,
497
+ kind: "tool",
498
+ role,
499
+ toolName,
500
+ toolHeadline: toolCallHeadline(toolName),
501
+ argsSummary,
502
+ resultSummary,
503
+ }
504
+ }
505
+
506
+ const messageId = getMessageId(message)
507
+ const subagents = messageId
508
+ ? options.getSubagentsByMessage(messageId)
509
+ .map(subagent => summarizeSubagent(subagent, options.activeSubagentIds))
510
+ .filter(subagent => {
511
+ return (
512
+ options.knownSubagentIds.has(subagent.id)
513
+ || options.activeSubagentIds.has(subagent.id)
514
+ || subagent.hasVisibleActivity
515
+ )
516
+ })
517
+ : []
518
+
519
+ return {
520
+ key,
521
+ kind: "message",
522
+ role,
523
+ messageId,
524
+ label: getRoleLabel(role),
525
+ content: getMessageContent(message),
526
+ subagents,
527
+ }
528
+ })
529
+ }
530
+
531
+ /** Parent `task` tool calls only spawn subagents; subagent cards already represent that work. */
532
+ const HIDDEN_TOOL_NAMES = new Set(["task"])
533
+
534
+ export function filterVisibleSidebarMessages(messages: SidebarMessage[]) {
535
+ return messages.filter((message) => {
536
+ if (message.kind === "tool") {
537
+ if (HIDDEN_TOOL_NAMES.has(message.toolName))
538
+ return false
539
+
540
+ return true
541
+ }
542
+
543
+ if (message.content.trim())
544
+ return true
545
+
546
+ return message.subagents.length > 0
547
+ })
548
+ }
549
+
550
+ export function getMappedSubagentIds(messages: SidebarMessage[]) {
551
+ const ids = new Set<string>()
552
+
553
+ messages.forEach((message) => {
554
+ if (message.kind !== "message")
555
+ return
556
+
557
+ message.subagents.forEach(subagent => ids.add(subagent.id))
558
+ })
559
+
560
+ return ids
561
+ }
562
+
563
+ export function createSubagentActivityMessage(subagent: SubagentActivity): SidebarTextMessage {
564
+ return {
565
+ key: `subagent:${subagent.id}`,
566
+ kind: "message",
567
+ role: "subagent",
568
+ messageId: "",
569
+ label: "Subagent",
570
+ content: "",
571
+ subagents: [subagent],
572
+ }
573
+ }
package/lib/state.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { reactive } from "vue"
2
+
3
+ const storageKey = "slidev-agent:ui"
4
+
5
+ function readInitialState() {
6
+ if (typeof window === "undefined")
7
+ return { isOpen: false }
8
+
9
+ try {
10
+ const raw = window.localStorage.getItem(storageKey)
11
+ if (!raw)
12
+ return { isOpen: false }
13
+
14
+ const parsed = JSON.parse(raw)
15
+ return {
16
+ isOpen: Boolean(parsed.isOpen),
17
+ }
18
+ }
19
+ catch {
20
+ return { isOpen: false }
21
+ }
22
+ }
23
+
24
+ export const slidevAgentUiState = reactive(readInitialState())
25
+
26
+ export function setSlidevAgentOpen(nextValue: boolean) {
27
+ slidevAgentUiState.isOpen = nextValue
28
+
29
+ if (typeof window === "undefined")
30
+ return
31
+
32
+ try {
33
+ window.localStorage.setItem(storageKey, JSON.stringify({
34
+ isOpen: slidevAgentUiState.isOpen,
35
+ }))
36
+ }
37
+ catch {
38
+ // Ignore storage failures so the sidebar still works.
39
+ }
40
+ }
41
+
42
+ export function toggleSlidevAgent() {
43
+ setSlidevAgentOpen(!slidevAgentUiState.isOpen)
44
+ }
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "slidev-addon-agent",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "description": "Slidev addon and wrapper CLI for LangChain-powered slide authoring.",
6
+ "scripts": {
7
+ "build": "tsc -p tsconfig.build.json"
8
+ },
9
+ "keywords": [
10
+ "slidev-addon",
11
+ "slidev",
12
+ "langchain",
13
+ "langgraph"
14
+ ],
15
+ "bin": {
16
+ "slidev-agent": "./dist/bin/slidev-agent.js"
17
+ },
18
+ "exports": {
19
+ ".": "./package.json",
20
+ "./agent": "./agent/index.ts",
21
+ "./app": "./app/index.ts"
22
+ },
23
+ "files": [
24
+ "README.md",
25
+ "agent",
26
+ "app",
27
+ "dist",
28
+ "components",
29
+ "lib",
30
+ "public"
31
+ ],
32
+ "dependencies": {
33
+ "@langchain/langgraph-cli": "^1.1.17",
34
+ "@langchain/vue": "^0.4.5",
35
+ "deepagents": "^1.8.8",
36
+ "dompurify": "^3.3.3",
37
+ "hono": "^4.12.10",
38
+ "langchain": "^1.3.0",
39
+ "marked": "^17.0.5",
40
+ "zod": "^4.3.6"
41
+ },
42
+ "peerDependencies": {
43
+ "@langchain/anthropic": "^1.3.26",
44
+ "@langchain/google": "^0.1.9",
45
+ "@langchain/langgraph": "^1.2.6",
46
+ "@langchain/openai": "^1.4.1",
47
+ "@slidev/cli": "^52.14.1",
48
+ "vue": "^3.5.0"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "@langchain/anthropic": {
52
+ "optional": true
53
+ },
54
+ "@langchain/google": {
55
+ "optional": true
56
+ },
57
+ "@langchain/openai": {
58
+ "optional": true
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@types/node": "^25.5.0",
63
+ "typescript": "^5.9.3"
64
+ }
65
+ }
@@ -0,0 +1,12 @@
1
+ <svg width="98" height="98" viewBox="0 0 98 98" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="97.2502" height="97.2502" rx="19.4855" fill="#7FC8FF"/>
3
+ <g clip-path="url(#clip0_195_1432)">
4
+ <path d="M72.5361 42.2004V22.0426H51.7354L51.7354 22.5212C62.5113 22.7991 71.2917 31.6243 72.1695 42.2004H72.5361Z" fill="#030710"/>
5
+ <path d="M49.223 22.0428H24.8759V63.0891C24.8759 70.6689 30.7215 75.3844 40.133 75.3844H72.5471V45.3962H49.223V22.0428Z" fill="#030710"/>
6
+ </g>
7
+ <defs>
8
+ <clipPath id="clip0_195_1432">
9
+ <rect width="47.6713" height="53.3416" fill="white" transform="translate(24.8799 22.0442)"/>
10
+ </clipPath>
11
+ </defs>
12
+ </svg>