ima2-gen 1.1.21 → 1.1.23

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 (214) hide show
  1. package/README.md +44 -7
  2. package/bin/commands/video.js +14 -0
  3. package/bin/ima2.js +14 -4
  4. package/bin/lib/platform.js +34 -5
  5. package/docs/README.ko.md +43 -2
  6. package/lib/agentQueueWorker.js +6 -0
  7. package/lib/agentRuntime.js +3 -2
  8. package/lib/atomicWrite.js +14 -0
  9. package/lib/grokImageAdapter.js +6 -0
  10. package/lib/grokProxyLauncher.js +5 -3
  11. package/lib/grokVideoAdapter.js +1 -1
  12. package/lib/grokVideoPlannerPrompt.js +10 -0
  13. package/lib/inflight.js +1 -1
  14. package/lib/oauthLauncher.js +5 -0
  15. package/lib/videoFrameExtract.js +3 -3
  16. package/package.json +5 -7
  17. package/routes/capabilities.js +13 -0
  18. package/routes/edit.js +2 -1
  19. package/routes/generate.js +32 -6
  20. package/routes/health.js +4 -3
  21. package/routes/multimode.js +2 -1
  22. package/routes/video.js +35 -3
  23. package/server.js +29 -2
  24. package/skills/ima2/SKILL.md +48 -6
  25. package/ui/dist/.vite/manifest.json +12 -12
  26. package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-C21zqdTZ.js} +1 -1
  27. package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-BN-ga1lG.js} +1 -1
  28. package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BbMa4IhI.js} +1 -1
  29. package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DRwBJRDQ.js} +1 -1
  30. package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-Dp85kHCq.js} +2 -2
  31. package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BE8Q8MLD.js} +1 -1
  32. package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-PtH5x0sc.js} +1 -1
  33. package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-FnM9tHI9.js} +2 -2
  34. package/ui/dist/assets/SettingsWorkspace-MARPGyBL.js +1 -0
  35. package/ui/dist/assets/index-BAFI6htx.js +42 -0
  36. package/ui/dist/assets/{index-31uVIdt4.js → index-BSXxr_Bt.js} +1 -1
  37. package/ui/dist/assets/index-DS-ADE7U.css +1 -0
  38. package/ui/dist/index.html +2 -2
  39. package/bin/commands/annotate.ts +0 -119
  40. package/bin/commands/cancel.ts +0 -48
  41. package/bin/commands/canvas-versions.ts +0 -80
  42. package/bin/commands/capabilities.ts +0 -110
  43. package/bin/commands/cardnews.ts +0 -249
  44. package/bin/commands/comfy.ts +0 -54
  45. package/bin/commands/config.ts +0 -186
  46. package/bin/commands/defaults.ts +0 -192
  47. package/bin/commands/doctor.ts +0 -202
  48. package/bin/commands/edit.ts +0 -150
  49. package/bin/commands/gen.ts +0 -214
  50. package/bin/commands/grok.ts +0 -90
  51. package/bin/commands/history.ts +0 -146
  52. package/bin/commands/ls.ts +0 -64
  53. package/bin/commands/metadata.ts +0 -39
  54. package/bin/commands/multimode.ts +0 -196
  55. package/bin/commands/node.ts +0 -166
  56. package/bin/commands/observability.ts +0 -176
  57. package/bin/commands/ping.ts +0 -31
  58. package/bin/commands/prompt-sub/build.ts +0 -101
  59. package/bin/commands/prompt.ts +0 -492
  60. package/bin/commands/ps.ts +0 -81
  61. package/bin/commands/session.ts +0 -266
  62. package/bin/commands/show.ts +0 -72
  63. package/bin/commands/skill.ts +0 -70
  64. package/bin/commands/video.ts +0 -442
  65. package/bin/ima2.ts +0 -430
  66. package/bin/lib/args.ts +0 -92
  67. package/bin/lib/browser-id.ts +0 -16
  68. package/bin/lib/client.ts +0 -122
  69. package/bin/lib/config-store.ts +0 -120
  70. package/bin/lib/destructive-confirm.ts +0 -19
  71. package/bin/lib/doctor-checks.ts +0 -91
  72. package/bin/lib/error-hints.ts +0 -23
  73. package/bin/lib/files.ts +0 -39
  74. package/bin/lib/output.ts +0 -73
  75. package/bin/lib/platform.ts +0 -99
  76. package/bin/lib/recover-output.ts +0 -139
  77. package/bin/lib/sse.ts +0 -73
  78. package/bin/lib/star-prompt.ts +0 -97
  79. package/bin/lib/storage-doctor.ts +0 -39
  80. package/bin/lib/ui-build.ts +0 -85
  81. package/config.ts +0 -354
  82. package/lib/agentCommandParser.ts +0 -69
  83. package/lib/agentGenerationPlanner.ts +0 -273
  84. package/lib/agentQuestionResponder.ts +0 -266
  85. package/lib/agentQueueStore.ts +0 -270
  86. package/lib/agentQueueWorker.ts +0 -89
  87. package/lib/agentRuntime.ts +0 -604
  88. package/lib/agentSettings.ts +0 -72
  89. package/lib/agentStore.ts +0 -422
  90. package/lib/agentStoreRows.ts +0 -136
  91. package/lib/agentTypes.ts +0 -154
  92. package/lib/apiCachePolicy.ts +0 -11
  93. package/lib/assetLifecycle.ts +0 -146
  94. package/lib/canvasVersionStore.ts +0 -223
  95. package/lib/capabilities.ts +0 -126
  96. package/lib/cardNewsGenerator.ts +0 -271
  97. package/lib/cardNewsJobStore.ts +0 -142
  98. package/lib/cardNewsManifestStore.ts +0 -154
  99. package/lib/cardNewsPlanner.ts +0 -236
  100. package/lib/cardNewsPlannerClient.ts +0 -155
  101. package/lib/cardNewsPlannerPrompt.ts +0 -62
  102. package/lib/cardNewsPlannerSchema.ts +0 -321
  103. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  104. package/lib/cardNewsTemplateStore.ts +0 -252
  105. package/lib/codexDetect.ts +0 -71
  106. package/lib/comfyBridge.ts +0 -235
  107. package/lib/composerSnapshot.ts +0 -33
  108. package/lib/configKeys.ts +0 -62
  109. package/lib/db.ts +0 -295
  110. package/lib/errInfo.ts +0 -43
  111. package/lib/errorClassify.ts +0 -100
  112. package/lib/generationCancel.ts +0 -28
  113. package/lib/generationErrors.ts +0 -238
  114. package/lib/grokImageAdapter.ts +0 -513
  115. package/lib/grokMultimodeAdapter.ts +0 -84
  116. package/lib/grokProxyLauncher.ts +0 -153
  117. package/lib/grokRuntime.ts +0 -23
  118. package/lib/grokSizeMapper.ts +0 -71
  119. package/lib/grokVideoAdapter.ts +0 -458
  120. package/lib/grokVideoCanvas.ts +0 -26
  121. package/lib/grokVideoDownload.ts +0 -59
  122. package/lib/grokVideoPlannerPrompt.ts +0 -67
  123. package/lib/historyIndex.ts +0 -51
  124. package/lib/historyList.ts +0 -181
  125. package/lib/imageMetadata.ts +0 -113
  126. package/lib/imageMetadataStore.ts +0 -67
  127. package/lib/imageModels.ts +0 -165
  128. package/lib/inflight.ts +0 -281
  129. package/lib/localImportStore.ts +0 -114
  130. package/lib/logger.ts +0 -161
  131. package/lib/nodeStore.ts +0 -91
  132. package/lib/oauthLauncher.ts +0 -94
  133. package/lib/oauthNormalize.ts +0 -30
  134. package/lib/oauthProxy/errors.ts +0 -128
  135. package/lib/oauthProxy/generators.ts +0 -494
  136. package/lib/oauthProxy/index.ts +0 -28
  137. package/lib/oauthProxy/prompts.ts +0 -123
  138. package/lib/oauthProxy/references.ts +0 -45
  139. package/lib/oauthProxy/runtime.ts +0 -115
  140. package/lib/oauthProxy/streams.ts +0 -232
  141. package/lib/oauthProxy/types.ts +0 -9
  142. package/lib/oauthProxy.ts +0 -3
  143. package/lib/openDirectory.ts +0 -47
  144. package/lib/pngInfo.ts +0 -26
  145. package/lib/promptBuilder/attachments.ts +0 -74
  146. package/lib/promptBuilder/client.ts +0 -130
  147. package/lib/promptBuilder/constants.ts +0 -9
  148. package/lib/promptBuilder/context.ts +0 -36
  149. package/lib/promptBuilder/errors.ts +0 -12
  150. package/lib/promptBuilder/requestSchema.ts +0 -56
  151. package/lib/promptBuilder/responseParser.ts +0 -219
  152. package/lib/promptBuilder/systemPrompt.ts +0 -135
  153. package/lib/promptBuilder/transport.ts +0 -94
  154. package/lib/promptBuilder/types.ts +0 -109
  155. package/lib/promptImport/curatedSources.ts +0 -141
  156. package/lib/promptImport/discoveryRegistry.ts +0 -329
  157. package/lib/promptImport/errors.ts +0 -18
  158. package/lib/promptImport/githubDiscovery.ts +0 -309
  159. package/lib/promptImport/githubFolder.ts +0 -397
  160. package/lib/promptImport/githubSource.ts +0 -257
  161. package/lib/promptImport/gptImageHints.ts +0 -70
  162. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  163. package/lib/promptImport/promptIndex.ts +0 -326
  164. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  165. package/lib/promptImport/types.ts +0 -103
  166. package/lib/promptSafetyPolicy.ts +0 -5
  167. package/lib/providerOptions.ts +0 -56
  168. package/lib/referenceImageCompress.ts +0 -84
  169. package/lib/refs.ts +0 -133
  170. package/lib/requestLogger.ts +0 -49
  171. package/lib/responsesDoctor.ts +0 -456
  172. package/lib/responsesErrors.ts +0 -83
  173. package/lib/responsesFallback.ts +0 -114
  174. package/lib/responsesImageAdapter.ts +0 -466
  175. package/lib/responsesParse.ts +0 -452
  176. package/lib/responsesTools.ts +0 -28
  177. package/lib/runtimeContext.ts +0 -146
  178. package/lib/runtimePorts.ts +0 -105
  179. package/lib/sessionStore.ts +0 -308
  180. package/lib/storageMigration.ts +0 -310
  181. package/lib/styleSheet.ts +0 -139
  182. package/lib/systemTrash.ts +0 -20
  183. package/lib/videoContinuity.ts +0 -180
  184. package/lib/videoFrameExtract.ts +0 -78
  185. package/lib/videoSeriesChain.ts +0 -29
  186. package/lib/visibleTextLanguagePolicy.ts +0 -7
  187. package/routes/agent.ts +0 -308
  188. package/routes/annotations.ts +0 -118
  189. package/routes/canvasVersions.ts +0 -69
  190. package/routes/capabilities.ts +0 -18
  191. package/routes/cardNews.ts +0 -211
  192. package/routes/comfy.ts +0 -43
  193. package/routes/edit.ts +0 -352
  194. package/routes/generate.ts +0 -492
  195. package/routes/grok.ts +0 -24
  196. package/routes/health.ts +0 -123
  197. package/routes/history.ts +0 -221
  198. package/routes/imageImport.ts +0 -37
  199. package/routes/index.ts +0 -52
  200. package/routes/metadata.ts +0 -77
  201. package/routes/multimode.ts +0 -499
  202. package/routes/nodes.ts +0 -578
  203. package/routes/promptBuilder.ts +0 -37
  204. package/routes/promptImport.ts +0 -379
  205. package/routes/prompts.ts +0 -428
  206. package/routes/quota.ts +0 -89
  207. package/routes/sessions.ts +0 -317
  208. package/routes/storage.ts +0 -47
  209. package/routes/video.ts +0 -300
  210. package/routes/videoExtended.ts +0 -284
  211. package/server.ts +0 -293
  212. package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
  213. package/ui/dist/assets/index-CjgnNtgt.css +0 -1
  214. package/ui/dist/assets/index-Da2s4_-5.js +0 -36
@@ -1,9 +0,0 @@
1
- export const VALID_PROMPT_BUILDER_MODELS = new Set(["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"]);
2
- export const DEFAULT_PROMPT_BUILDER_MODEL = "gpt-5.5";
3
- export const MAX_MESSAGES = 24;
4
- export const MAX_MESSAGE_CHARS = 16_000;
5
- export const MAX_ATTACHMENTS = 6;
6
- export const MAX_TEXT_ATTACHMENT_CHARS = 20_000;
7
- export const MAX_ATTACHMENT_NAME_CHARS = 160;
8
- export const MAX_ATTACHMENT_MIME_CHARS = 120;
9
- export const PROMPT_BUILDER_RESPONSE_MAX_OUTPUT_TOKENS = 2400;
@@ -1,36 +0,0 @@
1
- import type { PromptBuilderContext } from "./types.js";
2
-
3
- export function contextText(context: PromptBuilderContext | undefined): string {
4
- const lines: string[] = [];
5
- const currentPrompt =
6
- typeof context?.currentPrompt === "string" ? context.currentPrompt.trim() : "";
7
- if (currentPrompt) lines.push(`Current main prompt:\n${currentPrompt}`);
8
-
9
- const blocks = Array.isArray(context?.insertedPrompts) ? context.insertedPrompts : [];
10
- if (blocks.length > 0) {
11
- lines.push(
12
- `Inserted prompt blocks:\n${blocks
13
- .map((block, index) => {
14
- const name =
15
- typeof block.name === "string" && block.name.trim()
16
- ? block.name.trim()
17
- : `Block ${index + 1}`;
18
- const text = typeof block.text === "string" ? block.text.trim() : "";
19
- return `- ${name}: ${text}`;
20
- })
21
- .join("\n")}`,
22
- );
23
- }
24
-
25
- if (context?.settings && typeof context.settings === "object") {
26
- lines.push(`Generation settings:\n${JSON.stringify(context.settings)}`);
27
- }
28
-
29
- const resultPrompt =
30
- typeof context?.currentResultPrompt === "string"
31
- ? context.currentResultPrompt.trim()
32
- : "";
33
- if (resultPrompt) lines.push(`Current result prompt:\n${resultPrompt}`);
34
-
35
- return lines.join("\n\n");
36
- }
@@ -1,12 +0,0 @@
1
- import type { PromptBuilderError } from "./types.js";
2
-
3
- export function promptBuilderError(
4
- message: string,
5
- code: string,
6
- status = 400,
7
- ): PromptBuilderError {
8
- const err = new Error(message) as PromptBuilderError;
9
- err.code = code;
10
- err.status = status;
11
- return err;
12
- }
@@ -1,56 +0,0 @@
1
- import {
2
- VALID_PROMPT_BUILDER_MODELS,
3
- DEFAULT_PROMPT_BUILDER_MODEL,
4
- MAX_MESSAGES,
5
- MAX_MESSAGE_CHARS,
6
- } from "./constants.js";
7
- import { promptBuilderError } from "./errors.js";
8
- import { normalizeAttachments } from "./attachments.js";
9
- import type { PromptBuilderMessage } from "./types.js";
10
-
11
- export function normalizeModel(raw: unknown): string {
12
- if (typeof raw !== "string" || raw.trim().length === 0) return DEFAULT_PROMPT_BUILDER_MODEL;
13
- if (!VALID_PROMPT_BUILDER_MODELS.has(raw)) {
14
- throw promptBuilderError(
15
- "model must be one of: gpt-5.5, gpt-5.4, gpt-5.4-mini",
16
- "PROMPT_BUILDER_BAD_MODEL",
17
- );
18
- }
19
- return raw;
20
- }
21
-
22
- export function normalizeMessages(raw: unknown): PromptBuilderMessage[] {
23
- if (!Array.isArray(raw)) {
24
- throw promptBuilderError("messages must be an array", "PROMPT_BUILDER_BAD_MESSAGES");
25
- }
26
- const messages = raw.slice(-MAX_MESSAGES).map((message): PromptBuilderMessage => {
27
- if (!message || typeof message !== "object") {
28
- throw promptBuilderError("each message must be an object", "PROMPT_BUILDER_BAD_MESSAGES");
29
- }
30
- const item = message as { role?: unknown; content?: unknown; attachments?: unknown };
31
- const role = item.role === "assistant" ? "assistant" : item.role === "user" ? "user" : null;
32
- if (!role) {
33
- throw promptBuilderError(
34
- "message role must be user or assistant",
35
- "PROMPT_BUILDER_BAD_MESSAGES",
36
- );
37
- }
38
- const content = typeof item.content === "string" ? item.content.trim() : "";
39
- if (!content && role === "user") {
40
- throw promptBuilderError("message content is required", "PROMPT_BUILDER_EMPTY_MESSAGE");
41
- }
42
- return {
43
- role,
44
- content: content.slice(0, MAX_MESSAGE_CHARS),
45
- attachments: normalizeAttachments(item.attachments),
46
- };
47
- });
48
- const last = messages.at(-1);
49
- if (!last || last.role !== "user" || !last.content.trim()) {
50
- throw promptBuilderError(
51
- "last message must be a non-empty user message",
52
- "PROMPT_BUILDER_EMPTY_MESSAGE",
53
- );
54
- }
55
- return messages;
56
- }
@@ -1,219 +0,0 @@
1
- import { promptBuilderError } from "./errors.js";
2
- import type {
3
- PromptBuilderError,
4
- ResponseShapeSummary,
5
- ChatCompletionBody,
6
- ResponsesBody,
7
- ResponsesReadResult,
8
- } from "./types.js";
9
-
10
- function safeUpstreamString(value: unknown): string | undefined {
11
- return typeof value === "string" && value.trim()
12
- ? value.trim().slice(0, 160)
13
- : undefined;
14
- }
15
-
16
- export function parseUpstreamError(text: string): Pick<
17
- PromptBuilderError,
18
- "upstreamCode" | "upstreamType" | "upstreamParam"
19
- > {
20
- try {
21
- const body = JSON.parse(text) as { error?: Record<string, unknown> };
22
- const error =
23
- body && typeof body.error === "object" ? body.error : undefined;
24
- return {
25
- upstreamCode: safeUpstreamString(error?.code),
26
- upstreamType: safeUpstreamString(error?.type),
27
- upstreamParam: safeUpstreamString(error?.param),
28
- };
29
- } catch {
30
- return {};
31
- }
32
- }
33
-
34
- export function responseSummary(body: unknown): ResponseShapeSummary {
35
- if (!body || typeof body !== "object") {
36
- return {
37
- responseBodyKeys: "",
38
- responseStatus: undefined,
39
- responseErrorCode: undefined,
40
- responseErrorType: undefined,
41
- responseErrorParam: undefined,
42
- responseIncompleteReason: undefined,
43
- responseOutputTypes: "",
44
- responseContentTypes: "",
45
- responseOutputCount: 0,
46
- responseContentCount: 0,
47
- };
48
- }
49
- const record = body as Record<string, unknown>;
50
- const output = Array.isArray(record.output) ? record.output : [];
51
- const error =
52
- record.error && typeof record.error === "object"
53
- ? (record.error as Record<string, unknown>)
54
- : undefined;
55
- const incomplete =
56
- record.incomplete_details && typeof record.incomplete_details === "object"
57
- ? (record.incomplete_details as Record<string, unknown>)
58
- : undefined;
59
- const contentItems = output.flatMap((item) => {
60
- if (!item || typeof item !== "object") return [];
61
- const content = (item as { content?: unknown }).content;
62
- return Array.isArray(content) ? content : [];
63
- });
64
- const outputTypes = output
65
- .map((item) =>
66
- item && typeof item === "object"
67
- ? (item as { type?: unknown }).type
68
- : undefined,
69
- )
70
- .filter((t): t is string => typeof t === "string" && t.length > 0);
71
- const contentTypes = contentItems
72
- .map((item) =>
73
- item && typeof item === "object"
74
- ? (item as { type?: unknown }).type
75
- : undefined,
76
- )
77
- .filter((t): t is string => typeof t === "string" && t.length > 0);
78
- return {
79
- responseBodyKeys: Object.keys(record).slice(0, 12).join(","),
80
- responseStatus: safeUpstreamString(record.status),
81
- responseErrorCode: safeUpstreamString(error?.code),
82
- responseErrorType: safeUpstreamString(error?.type),
83
- responseErrorParam: safeUpstreamString(error?.param),
84
- responseIncompleteReason: safeUpstreamString(incomplete?.reason),
85
- responseOutputTypes: Array.from(new Set(outputTypes))
86
- .slice(0, 12)
87
- .join(","),
88
- responseContentTypes: Array.from(new Set(contentTypes))
89
- .slice(0, 12)
90
- .join(","),
91
- responseOutputCount: output.length,
92
- responseContentCount: contentItems.length,
93
- };
94
- }
95
-
96
- function extractSseData(block: string): string {
97
- return block
98
- .split("\n")
99
- .filter((line) => line.startsWith("data:"))
100
- .map((line) => line.slice(5).trimStart())
101
- .join("\n");
102
- }
103
-
104
- function parseSseJson(block: string): Record<string, unknown> | null {
105
- const data = extractSseData(block);
106
- if (!data || data === "[DONE]") return null;
107
- try {
108
- const parsed = JSON.parse(data) as unknown;
109
- return parsed && typeof parsed === "object" && !Array.isArray(parsed)
110
- ? (parsed as Record<string, unknown>)
111
- : null;
112
- } catch {
113
- return null;
114
- }
115
- }
116
-
117
- export function extractChatText(body: ChatCompletionBody): string {
118
- return (
119
- body.choices?.find(
120
- (c) => typeof c.message?.content === "string" && c.message.content.trim(),
121
- )?.message?.content ?? ""
122
- );
123
- }
124
-
125
- export function extractResponsesText(body: ResponsesBody): string {
126
- if (typeof body.output_text === "string" && body.output_text.trim())
127
- return body.output_text;
128
- for (const item of body.output ?? []) {
129
- for (const content of item.content ?? []) {
130
- if (typeof content.text === "string" && content.text.trim())
131
- return content.text;
132
- if (
133
- content.text &&
134
- typeof content.text === "object" &&
135
- typeof content.text.value === "string" &&
136
- content.text.value.trim()
137
- )
138
- return content.text.value;
139
- if (typeof content.value === "string" && content.value.trim())
140
- return content.value;
141
- if (typeof content.refusal === "string" && content.refusal.trim())
142
- return content.refusal;
143
- }
144
- }
145
- return "";
146
- }
147
-
148
- export async function readResponsesStream(
149
- res: Response,
150
- ): Promise<ResponsesReadResult> {
151
- const reader = res.body?.getReader();
152
- const decoder = new TextDecoder();
153
- const deltas: string[] = [];
154
- let buffer = "";
155
- let usage: Record<string, unknown> | null = null;
156
- let summary = responseSummary(null);
157
- if (!reader) return { content: "", usage, summary };
158
- while (true) {
159
- const { done, value } = await reader.read();
160
- if (done) break;
161
- buffer += decoder.decode(value, { stream: true });
162
- let boundary = buffer.indexOf("\n\n");
163
- while (boundary !== -1) {
164
- const block = buffer.slice(0, boundary);
165
- buffer = buffer.slice(boundary + 2);
166
- const data = parseSseJson(block);
167
- if (data) {
168
- const type = typeof data.type === "string" ? data.type : "";
169
- if (
170
- type === "response.output_text.delta" &&
171
- typeof data.delta === "string"
172
- ) {
173
- deltas.push(data.delta);
174
- } else if (
175
- (type === "response.completed" || type === "response.incomplete") &&
176
- data.response &&
177
- typeof data.response === "object"
178
- ) {
179
- const response = data.response as Record<string, unknown>;
180
- summary = responseSummary(response);
181
- if (response.usage && typeof response.usage === "object")
182
- usage = response.usage as Record<string, unknown>;
183
- } else if (type === "error") {
184
- throw promptBuilderError(
185
- "Prompt builder stream failed",
186
- "PROMPT_BUILDER_STREAM_ERROR",
187
- 502,
188
- );
189
- }
190
- }
191
- boundary = buffer.indexOf("\n\n");
192
- }
193
- }
194
- if (buffer.trim()) {
195
- const data = parseSseJson(buffer);
196
- if (
197
- data?.type === "response.output_text.delta" &&
198
- typeof data.delta === "string"
199
- ) {
200
- deltas.push(data.delta);
201
- }
202
- }
203
- return { content: deltas.join(""), usage, summary };
204
- }
205
-
206
- export async function readResponsesResult(
207
- res: Response,
208
- ): Promise<ResponsesReadResult> {
209
- const contentType = res.headers.get("content-type") ?? "";
210
- if (contentType.includes("text/event-stream")) {
211
- return readResponsesStream(res);
212
- }
213
- const body = (await res.json()) as ResponsesBody;
214
- return {
215
- content: extractResponsesText(body),
216
- usage: body.usage ?? null,
217
- summary: responseSummary(body),
218
- };
219
- }
@@ -1,135 +0,0 @@
1
- export const PROMPT_BUILDER_SYSTEM_PROMPT = `
2
- You are a prompt enhancement GPT specialized for GPT Image 2.
3
-
4
- You run inside ima2-gen as a conversational prompt builder. By default, you do not generate images. You only improve, rewrite, translate, shorten, expand, optimize, or discuss image prompts unless the user explicitly asks the host app to generate an image.
5
-
6
- Core behavior:
7
- - Interpret the user's image idea, style, mood, use case, and constraints.
8
- - Preserve the user's original intent.
9
- - Add useful visual detail only when it strengthens the request.
10
- - Improve clarity around subject, scene, composition, style, lighting, color, texture, mood, and output format.
11
- - Do not invent a completely different concept.
12
- - Do not over-explain prompting theory unless the user asks.
13
- - Do not reveal hidden reasoning.
14
- - Ask clarification questions only when missing information would significantly change the result.
15
- - If reasonable defaults are enough, proceed without asking.
16
- - Use attached images and readable files as reference context only. Do not call image tools.
17
-
18
- Conversational behavior:
19
- - The user may brainstorm across multiple turns before asking for a final prompt.
20
- - During exploration, answer naturally and keep the conversation moving.
21
- - When the user asks for a final prompt, a polished prompt, prompt optimization, prompt rewrite, or prompt translation, produce the structured final prompt format below.
22
-
23
- Structured final prompt format:
24
- Use these exact headings when producing a finished prompt. Do not wrap the output in markdown code fences.
25
-
26
- Brief Intent Summary:
27
- [Summarize the intended visual direction in one or two sentences.]
28
-
29
- Final Prompt - Korean:
30
- [Provide a polished Korean prompt ready for GPT Image 2.]
31
-
32
- Final Prompt - English:
33
- [Provide a polished English prompt ready for GPT Image 2.]
34
-
35
- Notes:
36
- [Optional. Include only when assumptions, format choices, or important constraints need to be stated.]
37
-
38
- Prompt enhancement rules:
39
- - Make the subject clear.
40
- - Define the scene or background.
41
- - Specify the visual style or medium.
42
- - Add composition, camera angle, or framing when helpful.
43
- - Add lighting and color direction when helpful.
44
- - Add texture, material, and detail level when helpful.
45
- - Include intended use, such as poster, thumbnail, banner, product image, character design, profile image, concept art, or editorial image, when relevant.
46
- - Include aspect ratio or format when the user specifies it or when it can be reasonably inferred.
47
- - Keep the prompt visually actionable rather than abstract.
48
- - If the user mentions something to avoid, incorporate that constraint naturally into the final prompt text instead of creating a separate negative prompt section.
49
-
50
- Positive-only prompting rules:
51
- The final prompt must be written as a positive description of the desired image, not as a list of things to avoid.
52
-
53
- When the user describes something they do not want, treat it as an internal constraint only. Do not repeat the unwanted concept in the final Korean or English prompt unless it is absolutely necessary for user-facing clarification.
54
-
55
- Convert negative instructions into positive target attributes:
56
- - "not elderly" -> "young adult"
57
- - "not messy" -> "clean, organized composition"
58
- - "not scary" -> "calm, approachable mood"
59
- - "not cartoonish" -> "realistic, natural proportions and textures"
60
- - "not too colorful" -> "restrained, muted color palette"
61
- - "no clutter" -> "minimal background with clear focal hierarchy"
62
- - "do not change the face" -> "preserve the original facial identity, expression, and proportions"
63
- - "do not change the product shape" -> "preserve the original product silhouette, proportions, and key design features"
64
-
65
- Avoid these patterns in the final Korean and English prompt text:
66
- - "not ..."
67
- - "no ..."
68
- - "without ..."
69
- - "avoid ..."
70
- - "do not ..."
71
- - "instead of ..."
72
- - "rather than ..."
73
- - "unlike ..."
74
-
75
- Before finalizing, perform a positive-only rewrite pass:
76
- 1. Identify any unwanted concept mentioned by the user.
77
- 2. Replace it with the desired visual target.
78
- 3. Remove the unwanted concept from the final prompt.
79
- 4. Remove negation phrasing from both Korean and English prompts.
80
- 5. Ensure the final prompt describes only what should appear in the image.
81
-
82
- When the user gives a vague style word, translate it into concrete visual language:
83
- - Minimal: clean composition, negative space, simple forms, restrained palette.
84
- - Cinematic: filmic framing, dramatic lighting, atmospheric depth, controlled contrast.
85
- - Luxury: refined materials, elegant lighting, polished surfaces, restrained color palette.
86
- - Cute: rounded shapes, friendly expression, soft proportions, bright or pastel colors.
87
- - Dreamy: soft focus, glowing light, haze, delicate details, ethereal mood.
88
- - Vintage: film grain, faded tones, retro palette, nostalgic texture.
89
- - Futuristic: sleek forms, advanced materials, luminous accents, clean technology-inspired design.
90
- - Cyberpunk: neon lighting, rainy urban atmosphere, reflective surfaces, dark high-contrast palette.
91
- - Photorealistic: realistic lighting, natural textures, camera-based composition, believable details.
92
- - 3D: dimensional form, clear materials, shadows, polished rendering.
93
- - Illustration: stylized shapes, linework or painterly treatment, controlled color design.
94
-
95
- For image editing prompts:
96
- - Clearly state what should be preserved.
97
- - Clearly state what should be changed.
98
- - Explain how the new elements should blend with the original image.
99
- - Mention consistency of lighting, perspective, edges, identity, and material when relevant.
100
- - Provide both Korean and English edit prompts.
101
- - If there are unwanted changes to prevent, express them as preservation constraints inside the prompt, such as "keep the original face, pose, clothing, and proportions unchanged."
102
-
103
- For reference images:
104
- - Identify whether the image is a style reference, subject reference, composition reference, product reference, color reference, mood reference, or edit target.
105
- - Preserve the important traits requested by the user.
106
- - Do not assume the reference image should control every detail unless the user says so.
107
-
108
- For text inside images:
109
- - Preserve the exact wording provided by the user.
110
- - Put the exact text in quotation marks.
111
- - Specify placement, typography, hierarchy, and legibility when relevant.
112
- - Do not translate visible text unless the user asks for translation.
113
-
114
- For variations:
115
- - Provide clearly separated versions.
116
- - Each version must include both Korean and English prompts.
117
- - Vary only the requested axis, such as style, mood, color palette, composition, camera angle, background, medium, or lighting.
118
- - Do not generate images unless explicitly asked.
119
-
120
- Safety and style limits:
121
- - Do not create prompts that violate safety policy.
122
- - Do not directly imitate a living artist's distinctive current style.
123
- - When a living artist style is requested, replace it with broader visual characteristics such as medium, color, lighting, era, composition, texture, or mood.
124
- - Avoid prompts that enable deception, impersonation, or harmful misuse.
125
- - For real people, avoid defamatory, sexualized, misleading, or dignity-violating framing.
126
-
127
- Before finalizing, check:
128
- - Does the prompt preserve the user's original idea?
129
- - Are both Korean and English versions included?
130
- - Are the two versions semantically aligned?
131
- - Is the prompt specific enough for image generation?
132
- - Are constraints expressed inside the prompt text rather than as a separate negative prompt?
133
- - Are any assumptions brief and reasonable?
134
- - Is the output ready to copy and use?
135
- `.trim();
@@ -1,94 +0,0 @@
1
- import { attachmentText, hasImageAttachments } from "./attachments.js";
2
- import { PROMPT_BUILDER_RESPONSE_MAX_OUTPUT_TOKENS } from "./constants.js";
3
- import { PROMPT_BUILDER_SYSTEM_PROMPT } from "./systemPrompt.js";
4
- import { contextText } from "./context.js";
5
- import type {
6
- PromptBuilderMessage,
7
- PromptBuilderContext,
8
- ChatContentPart,
9
- ResponsesContentPart,
10
- } from "./types.js";
11
-
12
- function toChatContent(
13
- message: PromptBuilderMessage,
14
- ): string | ChatContentPart[] {
15
- const text = [message.content, attachmentText(message.attachments)]
16
- .filter(Boolean)
17
- .join("\n\n");
18
- const imageParts = (message.attachments ?? [])
19
- .filter((a) => a.kind === "image" && a.dataUrl)
20
- .map(
21
- (a): ChatContentPart => ({
22
- type: "image_url",
23
- image_url: { url: a.dataUrl as string },
24
- }),
25
- );
26
- if (imageParts.length === 0) return text;
27
- return [{ type: "text", text }, ...imageParts];
28
- }
29
-
30
- function toResponsesContent(
31
- message: PromptBuilderMessage,
32
- ): string | ResponsesContentPart[] {
33
- const text = [message.content, attachmentText(message.attachments)]
34
- .filter(Boolean)
35
- .join("\n\n");
36
- const imageParts = (message.attachments ?? [])
37
- .filter((a) => a.kind === "image" && a.dataUrl)
38
- .map(
39
- (a): ResponsesContentPart => ({
40
- type: "input_image",
41
- image_url: a.dataUrl as string,
42
- }),
43
- );
44
- if (imageParts.length === 0) return text;
45
- return [{ type: "input_text", text }, ...imageParts];
46
- }
47
-
48
- export type TransportPayload = {
49
- endpoint: "chat" | "responses";
50
- body: Record<string, unknown>;
51
- };
52
-
53
- export function buildTransportPayload(
54
- model: string,
55
- messages: PromptBuilderMessage[],
56
- context: PromptBuilderContext | undefined,
57
- ): TransportPayload {
58
- const currentContextText = contextText(context);
59
- const systemText = [
60
- PROMPT_BUILDER_SYSTEM_PROMPT,
61
- currentContextText ? `Current ima2-gen context:\n${currentContextText}` : "",
62
- ]
63
- .filter(Boolean)
64
- .join("\n\n");
65
-
66
- const useResponses = hasImageAttachments(messages);
67
- const endpoint = useResponses ? "responses" : "chat";
68
-
69
- const body = useResponses
70
- ? {
71
- model,
72
- instructions: systemText,
73
- input: messages.map((m) => ({
74
- role: m.role,
75
- content: toResponsesContent(m),
76
- })),
77
- stream: true,
78
- max_output_tokens: PROMPT_BUILDER_RESPONSE_MAX_OUTPUT_TOKENS,
79
- }
80
- : {
81
- model,
82
- messages: [
83
- { role: "system", content: systemText },
84
- ...messages.map((m) => ({
85
- role: m.role,
86
- content: toChatContent(m),
87
- })),
88
- ],
89
- stream: false,
90
- reasoning_effort: "low",
91
- };
92
-
93
- return { endpoint, body };
94
- }
@@ -1,109 +0,0 @@
1
- export type PromptBuilderRole = "user" | "assistant";
2
-
3
- export type PromptBuilderAttachment = {
4
- kind: "image" | "text" | "file";
5
- name: string;
6
- mimeType: string;
7
- size: number;
8
- dataUrl?: string;
9
- text?: string;
10
- };
11
-
12
- export type PromptBuilderMessage = {
13
- role: PromptBuilderRole;
14
- content: string;
15
- attachments?: PromptBuilderAttachment[];
16
- };
17
-
18
- export type PromptBuilderContext = {
19
- currentPrompt?: string;
20
- insertedPrompts?: Array<{ name?: string; text?: string }>;
21
- settings?: Record<string, unknown>;
22
- currentResultPrompt?: string | null;
23
- };
24
-
25
- export type PromptBuilderRequest = {
26
- model?: unknown;
27
- messages?: unknown;
28
- context?: PromptBuilderContext;
29
- };
30
-
31
- export type PromptBuilderError = Error & {
32
- status?: number;
33
- code?: string;
34
- upstreamStatus?: number;
35
- upstreamBodyChars?: number;
36
- upstreamEndpoint?: "chat" | "responses";
37
- upstreamCode?: string;
38
- upstreamType?: string;
39
- upstreamParam?: string;
40
- responseBodyKeys?: string;
41
- responseStatus?: string;
42
- responseErrorCode?: string;
43
- responseErrorType?: string;
44
- responseErrorParam?: string;
45
- responseIncompleteReason?: string;
46
- responseOutputTypes?: string;
47
- responseContentTypes?: string;
48
- responseOutputCount?: number;
49
- responseContentCount?: number;
50
- };
51
-
52
- export type ResponseShapeSummary = Pick<
53
- PromptBuilderError,
54
- | "responseBodyKeys"
55
- | "responseStatus"
56
- | "responseErrorCode"
57
- | "responseErrorType"
58
- | "responseErrorParam"
59
- | "responseIncompleteReason"
60
- | "responseOutputTypes"
61
- | "responseContentTypes"
62
- | "responseOutputCount"
63
- | "responseContentCount"
64
- >;
65
-
66
- export type ChatCompletionBody = {
67
- choices?: Array<{
68
- message?: {
69
- role?: string;
70
- content?: string | null;
71
- };
72
- }>;
73
- usage?: Record<string, unknown>;
74
- };
75
-
76
- export type ResponsesBody = {
77
- output_text?: string;
78
- output?: Array<{
79
- type?: string;
80
- content?: Array<{
81
- type?: string;
82
- text?: string | { value?: string };
83
- value?: string;
84
- refusal?: string;
85
- }>;
86
- }>;
87
- usage?: Record<string, unknown>;
88
- };
89
-
90
- export type ResponsesReadResult = {
91
- content: string;
92
- usage: Record<string, unknown> | null;
93
- summary: ResponseShapeSummary;
94
- };
95
-
96
- export type ChatContentPart =
97
- | { type: "text"; text: string }
98
- | { type: "image_url"; image_url: { url: string } };
99
-
100
- export type ResponsesContentPart =
101
- | { type: "input_text"; text: string }
102
- | { type: "input_image"; image_url: string };
103
-
104
- export type PromptBuilderChatResult = {
105
- provider: "oauth";
106
- model: string;
107
- message: { role: "assistant"; content: string };
108
- usage: Record<string, unknown> | null;
109
- };