@dickpy/dsh-imagegen 1.4.0 → 1.5.0

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 (53) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +270 -124
  3. package/cordis.patch.yml +8 -8
  4. package/docs/images/ecommerce-mode.png +0 -0
  5. package/docs/images/image-generation-studio-three-column.png +0 -0
  6. package/docs/images/imagegen-overview.png +0 -0
  7. package/docs/videos/agent-chat-edit.gif +0 -0
  8. package/docs/videos/agent-chat-edit.mp4 +0 -0
  9. package/lib/client.js +1859 -420
  10. package/lib/client.js.map +1 -1
  11. package/lib/index.js +327 -112
  12. package/package.json +69 -68
  13. package/src/agent-image-tools.ts +447 -418
  14. package/src/client/ImageGenPanel.tsx +1242 -348
  15. package/src/client/SettingsCard.tsx +936 -936
  16. package/src/client/TemplateLibrary.tsx +336 -336
  17. package/src/client/api.ts +203 -193
  18. package/src/client/channels-form.ts +263 -263
  19. package/src/client/controller.ts +46 -46
  20. package/src/client/conversation-sync.ts +14 -14
  21. package/src/client/css-modules.d.ts +5 -5
  22. package/src/client/helpers.ts +33 -33
  23. package/src/client/image-toolview.module.css +73 -73
  24. package/src/client/image-toolview.tsx +18 -18
  25. package/src/client/index.ts +22 -22
  26. package/src/client/locales.ts +156 -28
  27. package/src/client/mount.tsx +117 -117
  28. package/src/client/panel.module.css +1243 -455
  29. package/src/client/settings-card.module.css +1023 -1023
  30. package/src/client/settings-form.ts +336 -336
  31. package/src/client/settings-scope.ts +298 -298
  32. package/src/client/sidebar-entry.ts +190 -190
  33. package/src/client/templates.module.css +453 -453
  34. package/src/edit-image-command.ts +110 -0
  35. package/src/engine.ts +520 -520
  36. package/src/gallery-store.ts +306 -286
  37. package/src/generation-runtime.ts +84 -79
  38. package/src/history-store.ts +270 -250
  39. package/src/image-format.ts +11 -11
  40. package/src/image-models.ts +19 -19
  41. package/src/index.ts +337 -318
  42. package/src/model-catalog.ts +115 -115
  43. package/src/presets.ts +71 -71
  44. package/src/prompt-enhancer.ts +137 -137
  45. package/src/protocol.ts +380 -338
  46. package/src/routes.ts +964 -916
  47. package/src/task-queue.ts +113 -113
  48. package/src/templates/cases.json +10196 -10196
  49. package/src/templates-store.ts +278 -278
  50. package/src/updater.ts +117 -117
  51. package/docs/images/agent-chat-edit.png +0 -0
  52. package/docs/images/agent-chat-generate.png +0 -0
  53. package/docs/images/agent-chat-poster-workflow.png +0 -0
@@ -0,0 +1,110 @@
1
+ /** Direct `/edit_image` command for editing the latest image in the session. */
2
+
3
+ import type { Context } from '@deepseek-ai/cordis'
4
+ import type { CommandResult } from '@deepseek-ai/dsh-commands'
5
+ import type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
6
+ import type {} from '@deepseek-ai/dsh-commands'
7
+ import type {} from '@deepseek-ai/dsh-attachment'
8
+ import {
9
+ submitAgentImageEdit,
10
+ type AgentImageToolConfig,
11
+ } from './agent-image-tools.ts'
12
+ import type { ImageGenerationRuntime } from './generation-runtime.ts'
13
+
14
+ function isImageReference(value: unknown): value is ImageAttachmentRef {
15
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) return false
16
+ const ref = value as Record<string, unknown>
17
+ return typeof ref.attachmentId === 'string'
18
+ && (ref.mediaType === 'image/png' || ref.mediaType === 'image/jpeg' || ref.mediaType === 'image/webp' || ref.mediaType === 'image/gif')
19
+ && Number.isInteger(ref.bytes) && (ref.bytes as number) > 0
20
+ && Number.isInteger(ref.width) && (ref.width as number) > 0
21
+ && Number.isInteger(ref.height) && (ref.height as number) > 0
22
+ }
23
+
24
+ function imageInContent(value: unknown): ImageAttachmentRef | undefined {
25
+ if (!Array.isArray(value)) return undefined
26
+ for (let index = value.length - 1; index >= 0; index -= 1) {
27
+ const block = value[index]
28
+ if (typeof block !== 'object' || block === null || Array.isArray(block)) continue
29
+ const raw = block as Record<string, unknown>
30
+ if (raw.type === 'image' && isImageReference(raw.attachment)) return raw.attachment
31
+ if (raw.type === 'tool-result') {
32
+ const nested = imageInContent(raw.content)
33
+ if (nested !== undefined) return nested
34
+ }
35
+ }
36
+ return undefined
37
+ }
38
+
39
+ /** Pick the newest image explicitly attached to this command invocation. */
40
+ function imageInInvocation(value: unknown): ImageAttachmentRef | undefined {
41
+ if (!Array.isArray(value)) return undefined
42
+ for (let index = value.length - 1; index >= 0; index -= 1) {
43
+ const block = value[index]
44
+ if (typeof block !== 'object' || block === null || Array.isArray(block)) continue
45
+ const raw = block as Record<string, unknown>
46
+ if (raw.type === 'image' && isImageReference(raw.attachment)) return raw.attachment
47
+ }
48
+ return undefined
49
+ }
50
+
51
+ /** Find the newest durable image reference, including nested tool results. */
52
+ export function latestSessionImage(messages: readonly unknown[]): ImageAttachmentRef | undefined {
53
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
54
+ const message = messages[index]
55
+ if (typeof message !== 'object' || message === null || Array.isArray(message)) continue
56
+ const image = imageInContent((message as { content?: unknown }).content)
57
+ if (image !== undefined) return image
58
+ }
59
+ return undefined
60
+ }
61
+
62
+ function commandError(error: unknown): CommandResult {
63
+ const text = error instanceof Error ? error.message : String(error)
64
+ return { kind: 'error', text: text.trim() === '' ? '图片编辑失败。' : text }
65
+ }
66
+
67
+ /** Register the host-side command; it never sends the command line to a chat model. */
68
+ export function registerEditImageCommand(
69
+ ctx: Context,
70
+ runtime: ImageGenerationRuntime,
71
+ resolve: () => AgentImageToolConfig,
72
+ pendingImages?: {
73
+ get: (sessionId: string) => ImageAttachmentRef | undefined
74
+ consume: (sessionId: string, ref: ImageAttachmentRef) => void
75
+ },
76
+ ): () => void {
77
+ return ctx.commands.register({
78
+ name: 'edit_image',
79
+ description: 'Edit the latest image in this conversation with the plugin image model',
80
+ // `images` is understood by the newer host command protocol. Keep the
81
+ // source compatible with older development-only command typings.
82
+ input: { hint: 'Describe how to modify the latest image', images: true } as { hint: string; images: boolean },
83
+ async handler(invocation): Promise<CommandResult> {
84
+ const prompt = invocation.rawInput.trim()
85
+ if (prompt === '') return { kind: 'error', text: '请提供图片修改描述,例如:/edit_image 把背景改成夜景' }
86
+ const invocationImage = imageInInvocation((invocation as typeof invocation & { attachments?: readonly unknown[] }).attachments)
87
+ // A staged composer image is newer than anything already committed to
88
+ // the session, so it must win when the user explicitly adds a preview
89
+ // or gallery image before running the command.
90
+ const pendingImage = pendingImages?.get(String(invocation.agent.id))
91
+ const durableImage = latestSessionImage(invocation.agent.session.deriveMessages())
92
+ const sourceImage = invocationImage ?? pendingImage ?? durableImage
93
+ if (sourceImage === undefined) return { kind: 'error', text: '当前对话没有可用图片,请先上传图片或把画廊图片加入对话。' }
94
+ try {
95
+ const task = await submitAgentImageEdit(ctx.attachments as Pick<AttachmentStore, 'readImage'>, runtime, resolve, {
96
+ prompt,
97
+ sourceImage,
98
+ signal: invocation.signal,
99
+ })
100
+ if (task.status === 'completed') {
101
+ if (pendingImage !== undefined) pendingImages?.consume(String(invocation.agent.id), pendingImage)
102
+ return { kind: 'success', text: '图片编辑已完成,可在 AI 生图面板查看结果。' }
103
+ }
104
+ return { kind: 'error', text: task.error ?? `图片编辑${task.status === 'cancelled' ? '已取消' : '失败'}。` }
105
+ } catch (error) {
106
+ return commandError(error)
107
+ }
108
+ },
109
+ })
110
+ }