@agimon-ai/po-image-gen 0.0.0-alpha.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.
@@ -0,0 +1,501 @@
1
+ import { apiResponse, createApiClient, defineActivityGroup, defineApiRoutes, defineFill, defineToolRenderer, defineWebPlugin, sessionApiAddress } from "@agimon-ai/po-core/web";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { sealedTransport } from "@agimon-ai/po-web-security/browser";
4
+ import { Button, MediaPreview, MessageItem, MessageItemBody, MessageItemHeader, MessageItemStatus, Skeleton, resultTextLines, toolTone } from "@agimon-ai/po-web-components";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/types/apiRoutes.ts
7
+ const routes = defineApiRoutes({
8
+ listImages: {
9
+ method: "GET",
10
+ path: "/artifacts",
11
+ query: ["limit", "cursor"],
12
+ response: apiResponse()
13
+ },
14
+ readImage: {
15
+ method: "GET",
16
+ path: "/artifact",
17
+ query: ["id", "toolCallId"],
18
+ response: apiResponse()
19
+ }
20
+ });
21
+ const api = createApiClient(routes, {
22
+ scopes: ["session"],
23
+ basePath: "images",
24
+ transport: (input, init) => sealedTransport.fetch(input, init),
25
+ sessionAddress: sessionApiAddress
26
+ });
27
+ //#endregion
28
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/imageFeedback.ts
29
+ const imageFeedbackSlot = {
30
+ slot: "author.image-feedback",
31
+ parse(input) {
32
+ if (input === null || typeof input !== "object") return null;
33
+ const value = input;
34
+ return value.version === 1 && typeof value.panel === "function" ? value : null;
35
+ }
36
+ };
37
+ /** Inline save failures are preview bytes, never filesystem authority. */
38
+ function inlineImageData(src) {
39
+ if (src === void 0 || !src.startsWith("data:image/png;base64,")) return void 0;
40
+ const data = src.slice(22);
41
+ if (data.length === 0 || data.length > Math.ceil(20971520 / 3) * 4 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)) return void 0;
42
+ try {
43
+ const bytes = atob(data);
44
+ return bytes.length <= 20971520 && bytes.startsWith("‰PNG\r\n\n") ? data : void 0;
45
+ } catch {
46
+ return;
47
+ }
48
+ }
49
+ //#endregion
50
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/sessionImagesApi.ts
51
+ /** Resolve transcript identity at the session boundary, not from result metadata paths. */
52
+ async function resolveTranscriptImage(sessionId, toolCallId, src, signal, inlineOnly = false) {
53
+ if (inlineOnly) {
54
+ signal.throwIfAborted();
55
+ const inlineData = inlineImageData(src);
56
+ if (!inlineData) throw new Error("The inline image is not a valid bounded PNG.");
57
+ return {
58
+ id: `inline-${toolCallId}`,
59
+ inlineData
60
+ };
61
+ }
62
+ const response = await api.session(sessionId).readImage({
63
+ query: { toolCallId },
64
+ signal
65
+ });
66
+ signal.throwIfAborted();
67
+ if (response.ok) {
68
+ if (response.data.sessionId !== sessionId) throw new Error("Image belongs to another session.");
69
+ return {
70
+ id: response.data.id,
71
+ artifact: response.data
72
+ };
73
+ }
74
+ if (response.status !== 404) throw new Error(response.error || "This image could not be loaded.");
75
+ const inlineData = inlineImageData(src);
76
+ if (!inlineData) throw new Error("The inline image is not a valid bounded PNG.");
77
+ return {
78
+ id: `inline-${toolCallId}`,
79
+ inlineData
80
+ };
81
+ }
82
+ //#endregion
83
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImagesView.tsx
84
+ /** Presentation only. The session container owns metadata and verified image URLs. */
85
+ function ImagesGridView({ images, state, error, onOpen, variant, hasMore, onMore }) {
86
+ if (state === "error") return /* @__PURE__ */ jsx("p", {
87
+ role: "alert",
88
+ className: "p-3 text-sm text-doom-red",
89
+ children: error ?? "Images could not be loaded."
90
+ });
91
+ if (state === "ready" && images.length === 0) return /* @__PURE__ */ jsx("p", {
92
+ className: "p-3 text-sm text-doom-dim",
93
+ children: "Images generated in this session will appear here."
94
+ });
95
+ const visible = variant === "activity" ? images.slice(0, 6) : images;
96
+ return /* @__PURE__ */ jsxs("div", {
97
+ className: "flex flex-col gap-3 p-3",
98
+ children: [/* @__PURE__ */ jsx("div", {
99
+ className: "grid grid-cols-3 gap-2",
100
+ children: state === "loading" && visible.length === 0 ? Array.from({ length: 6 }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "aspect-square rounded-md" }, index)) : visible.map((image) => /* @__PURE__ */ jsxs("button", {
101
+ "data-testid": `image-thumbnail-${image.id}`,
102
+ type: "button",
103
+ onClick: () => onOpen(image.id),
104
+ title: image.label,
105
+ "aria-label": `Open ${image.label}`,
106
+ className: "group min-w-0 overflow-hidden rounded-md border border-doom-border bg-doom-deep focus-visible:outline-2 focus-visible:outline-doom-selected",
107
+ children: [image.src ? /* @__PURE__ */ jsx("img", {
108
+ src: image.src,
109
+ alt: image.label,
110
+ className: "aspect-square w-full object-cover transition-opacity group-hover:opacity-80"
111
+ }) : /* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-full" }), variant === "gallery" ? /* @__PURE__ */ jsx("span", {
112
+ className: "block truncate px-2 py-2 text-sm text-doom-text",
113
+ children: image.label
114
+ }) : null]
115
+ }, image.id))
116
+ }), hasMore ? /* @__PURE__ */ jsx(Button, {
117
+ variant: "outline",
118
+ onClick: onMore,
119
+ disabled: state === "loading",
120
+ children: "Load more images"
121
+ }) : null]
122
+ });
123
+ }
124
+ function ImageViewerView({ image, state, error, feedback }) {
125
+ return /* @__PURE__ */ jsxs("section", {
126
+ className: "flex h-full min-h-0 flex-col gap-3 overflow-y-auto p-4",
127
+ children: [
128
+ /* @__PURE__ */ jsx("h2", {
129
+ className: "truncate text-lg font-semibold text-doom-hi",
130
+ title: image.label,
131
+ children: image.label
132
+ }),
133
+ feedback ? feedback : state === "error" ? /* @__PURE__ */ jsx("p", {
134
+ role: "alert",
135
+ className: "text-sm text-doom-red",
136
+ children: error ?? "This image could not be loaded."
137
+ }) : state === "loading" || !image.src ? /* @__PURE__ */ jsx(Skeleton, { className: "h-64 w-full rounded-md" }) : /* @__PURE__ */ jsx(MediaPreview, {
138
+ src: image.src,
139
+ path: `${image.label}.png`,
140
+ kind: "image",
141
+ contentType: "image/png",
142
+ className: "min-h-0 flex-1 object-contain"
143
+ }),
144
+ !feedback ? /* @__PURE__ */ jsx("p", {
145
+ className: "text-sm text-doom-dim",
146
+ children: "Original image, read only."
147
+ }) : null
148
+ ]
149
+ });
150
+ }
151
+ //#endregion
152
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImages.tsx
153
+ function imagesGalleryTab() {
154
+ return {
155
+ id: "image-gen-gallery",
156
+ label: "Images",
157
+ panel: ImagesGallery
158
+ };
159
+ }
160
+ function pngUrl(data) {
161
+ const bytes = Uint8Array.from(atob(data), (character) => character.charCodeAt(0));
162
+ return URL.createObjectURL(new Blob([bytes], { type: "image/png" }));
163
+ }
164
+ function imageViewerTab(sessionId, image) {
165
+ return {
166
+ id: `${image.inlineData === void 0 ? "image-gen-image" : "image-gen-inline"}-${encodeURIComponent(image.id)}`,
167
+ label: image.label ?? `Image ${image.id}`,
168
+ panel: (props) => props.sessionId === sessionId ? /* @__PURE__ */ jsx(SessionImageViewer, {
169
+ ...props,
170
+ image
171
+ }) : null
172
+ };
173
+ }
174
+ /** Inline bytes are a fallback only when no durable artifact exists. */
175
+ async function transcriptImageTab(sessionId, toolCallId, src, label, signal, inlineOnly = false) {
176
+ return imageViewerTab(sessionId, {
177
+ ...await resolveTranscriptImage(sessionId, toolCallId, src, signal, inlineOnly),
178
+ label
179
+ });
180
+ }
181
+ function ImagesActivity(props) {
182
+ return /* @__PURE__ */ jsx("div", {
183
+ "data-testid": "session-images-activity",
184
+ children: /* @__PURE__ */ jsx(SessionImages, {
185
+ ...props,
186
+ variant: "activity"
187
+ })
188
+ });
189
+ }
190
+ function ImagesGallery(props) {
191
+ return /* @__PURE__ */ jsxs("section", {
192
+ "data-testid": "session-images-gallery",
193
+ className: "h-full min-h-0 overflow-y-auto p-4",
194
+ "aria-label": "Session image gallery",
195
+ children: [
196
+ /* @__PURE__ */ jsx("h2", {
197
+ className: "text-lg font-semibold text-doom-hi",
198
+ children: "Images"
199
+ }),
200
+ /* @__PURE__ */ jsx("p", {
201
+ className: "text-sm text-doom-dim",
202
+ children: "Generated in this session, newest first."
203
+ }),
204
+ /* @__PURE__ */ jsx(SessionImages, {
205
+ ...props,
206
+ variant: "gallery"
207
+ })
208
+ ]
209
+ });
210
+ }
211
+ function SessionImages(props) {
212
+ if (props.sessionId === null) return null;
213
+ return /* @__PURE__ */ jsx(ImagesPage, {
214
+ ...props,
215
+ sessionId: props.sessionId
216
+ }, `${props.sessionId}:${props.statuses["image-gen.images"] ?? ""}`);
217
+ }
218
+ function ImagesPage(props) {
219
+ const [images, setImages] = useState([]);
220
+ const [cursor, setCursor] = useState("0");
221
+ const [nextCursor, setNextCursor] = useState(null);
222
+ const [state, setState] = useState("loading");
223
+ const [error, setError] = useState("");
224
+ const urls = useRef([]);
225
+ useEffect(() => () => {
226
+ for (const url of urls.current) URL.revokeObjectURL(url);
227
+ }, []);
228
+ useEffect(() => {
229
+ const controller = new AbortController();
230
+ setState("loading");
231
+ (async () => {
232
+ const response = await api.session(props.sessionId).listImages({
233
+ query: {
234
+ limit: "6",
235
+ cursor
236
+ },
237
+ signal: controller.signal
238
+ });
239
+ if (!response.ok) throw new Error(response.error || "Images could not be loaded.");
240
+ if (response.data.sessionId !== props.sessionId) throw new Error("Image history belongs to another session.");
241
+ const artifacts = await Promise.all(response.data.items.map(async ({ id }) => {
242
+ const result = await api.session(props.sessionId).readImage({
243
+ query: { id },
244
+ signal: controller.signal
245
+ });
246
+ if (!result.ok) {
247
+ if (result.status === 404) return null;
248
+ throw new Error(result.error || "An image could not be loaded.");
249
+ }
250
+ if (result.data.sessionId !== props.sessionId) throw new Error("Image belongs to another session.");
251
+ return result.data;
252
+ }));
253
+ controller.signal.throwIfAborted();
254
+ const tiles = artifacts.flatMap((artifact) => {
255
+ if (!artifact) return [];
256
+ const src = pngUrl(artifact.data);
257
+ urls.current.push(src);
258
+ return [{
259
+ id: artifact.id,
260
+ label: `Image ${artifact.id}`,
261
+ src
262
+ }];
263
+ });
264
+ setImages((previous) => cursor === "0" ? tiles : [...previous, ...tiles.filter((tile) => !previous.some(({ id }) => id === tile.id))]);
265
+ setNextCursor(response.data.nextCursor);
266
+ setState("ready");
267
+ })().catch((reason) => {
268
+ if (controller.signal.aborted) return;
269
+ setError(reason instanceof Error ? reason.message : "Images could not be loaded.");
270
+ setState("error");
271
+ });
272
+ return () => controller.abort();
273
+ }, [props.sessionId, cursor]);
274
+ return /* @__PURE__ */ jsx(ImagesGridView, {
275
+ images,
276
+ state,
277
+ error,
278
+ variant: props.variant,
279
+ onOpen: (id) => props.openTransientTab(imageViewerTab(props.sessionId, { id })),
280
+ hasMore: props.variant === "gallery" && nextCursor !== null,
281
+ onMore: () => {
282
+ if (nextCursor !== null && state !== "loading") setCursor(nextCursor);
283
+ }
284
+ });
285
+ }
286
+ function SessionImageViewer(props) {
287
+ const [artifact, setArtifact] = useState();
288
+ const [src, setSrc] = useState();
289
+ const [error, setError] = useState("");
290
+ const [state, setState] = useState("loading");
291
+ useEffect(() => {
292
+ const controller = new AbortController();
293
+ let objectUrl;
294
+ setArtifact(void 0);
295
+ setSrc(void 0);
296
+ setError("");
297
+ setState("loading");
298
+ (async () => {
299
+ if (props.sessionId === null) return;
300
+ let data = props.image.inlineData;
301
+ if (!data) {
302
+ let target = props.image.artifact;
303
+ if (!target) {
304
+ const result = await api.session(props.sessionId).readImage({
305
+ query: { id: props.image.id },
306
+ signal: controller.signal
307
+ });
308
+ if (!result.ok) throw new Error(result.error || "This image could not be loaded.");
309
+ target = result.data;
310
+ }
311
+ if (target.sessionId !== props.sessionId) throw new Error("Image belongs to another session.");
312
+ controller.signal.throwIfAborted();
313
+ setArtifact(target);
314
+ data = target.data;
315
+ }
316
+ controller.signal.throwIfAborted();
317
+ objectUrl = pngUrl(data);
318
+ setSrc(objectUrl);
319
+ setState("ready");
320
+ })().catch((reason) => {
321
+ if (controller.signal.aborted) return;
322
+ setError(reason instanceof Error ? reason.message : "This image could not be loaded.");
323
+ setState("error");
324
+ });
325
+ return () => {
326
+ controller.abort();
327
+ if (objectUrl) URL.revokeObjectURL(objectUrl);
328
+ };
329
+ }, [props.sessionId, props.image]);
330
+ const Panel = artifact && props.activeMinorModes?.includes("author") ? props.slotData(imageFeedbackSlot)[0]?.data.panel : void 0;
331
+ return /* @__PURE__ */ jsxs("section", {
332
+ "data-testid": "session-image-viewer",
333
+ "data-image-id": props.image.id,
334
+ className: "flex h-full min-h-0 flex-col",
335
+ children: [/* @__PURE__ */ jsx("div", {
336
+ className: "min-h-0 flex-1",
337
+ children: /* @__PURE__ */ jsx(ImageViewerView, {
338
+ image: {
339
+ id: props.image.id,
340
+ label: props.image.label ?? `Image ${props.image.id}`,
341
+ src
342
+ },
343
+ state,
344
+ error,
345
+ feedback: Panel && artifact ? /* @__PURE__ */ jsx(Panel, {
346
+ ...props,
347
+ target: artifact
348
+ }) : void 0
349
+ })
350
+ }), props.image.inlineData ? /* @__PURE__ */ jsx("p", {
351
+ className: "px-4 pb-4 text-sm text-doom-dim",
352
+ children: "This inline image was not saved. Original-path refinement is unavailable."
353
+ }) : null]
354
+ });
355
+ }
356
+ //#endregion
357
+ //#region src/extensions/workspaces/sessions/(frontend)/activity-group/images.web.ts
358
+ var images_web_default = defineActivityGroup({
359
+ name: "Images",
360
+ keys: "",
361
+ activeSource: {
362
+ subscribe: () => () => void 0,
363
+ isActive: () => false
364
+ },
365
+ marksBackgroundWork: false,
366
+ transientTab: imagesGalleryTab,
367
+ order: 35
368
+ });
369
+ //#endregion
370
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web.tsx
371
+ var Images_activity_Images_web_default = defineFill({
372
+ slot: "activity.Images",
373
+ component: ImagesActivity
374
+ });
375
+ //#endregion
376
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_lib/imagegenToolView.ts
377
+ function imagegenToolView({ args, result }) {
378
+ const prompt = typeof args.prompt === "string" ? args.prompt : "";
379
+ const editing = Array.isArray(args.referenced_image_paths) && args.referenced_image_paths.length > 0;
380
+ const image = result?.content.find((block) => block !== null && typeof block === "object" && "type" in block && block.type === "image" && "mimeType" in block && block.mimeType === "image/png" && "data" in block && typeof block.data === "string");
381
+ const src = image ? `data:image/png;base64,${image.data}` : void 0;
382
+ const details = result?.details;
383
+ return {
384
+ prompt,
385
+ editing,
386
+ src,
387
+ inlineOnly: details !== null && typeof details === "object" && "saveWarning" in details && typeof details.saveWarning === "string"
388
+ };
389
+ }
390
+ //#endregion
391
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/_components/ImagegenToolMessage.tsx
392
+ function ImagegenToolMessage(props) {
393
+ const { result, output, running, isError } = props;
394
+ const view = imagegenToolView(props);
395
+ const [opening, setOpening] = useState(false);
396
+ const [openError, setOpenError] = useState("");
397
+ const request = useRef(void 0);
398
+ useEffect(() => {
399
+ setOpening(false);
400
+ setOpenError("");
401
+ return () => request.current?.abort();
402
+ }, [props.sessionId, props.toolCallId]);
403
+ return /* @__PURE__ */ jsx(MessageItem, {
404
+ tone: toolTone({
405
+ running,
406
+ isError
407
+ }),
408
+ expandable: true,
409
+ defaultExpanded: true,
410
+ children: ({ expanded }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(MessageItemHeader, {
411
+ title: "imagegen",
412
+ children: [/* @__PURE__ */ jsx("span", {
413
+ "data-testid": "tool-call-imagegen",
414
+ className: "min-w-0 flex-1 truncate text-doom-text",
415
+ children: view.prompt
416
+ }), /* @__PURE__ */ jsx("span", {
417
+ className: "shrink-0 text-doom-faint",
418
+ children: view.editing ? "edit" : "generate"
419
+ })]
420
+ }), expanded ? /* @__PURE__ */ jsxs(MessageItemBody, {
421
+ "data-testid": "tool-result-imagegen",
422
+ className: "flex flex-col gap-2",
423
+ children: [
424
+ running ? /* @__PURE__ */ jsx(MessageItemStatus, {
425
+ tone: "running",
426
+ children: "creating image"
427
+ }) : null,
428
+ isError ? /* @__PURE__ */ jsx(MessageItemStatus, {
429
+ tone: "error",
430
+ children: "failed"
431
+ }) : null,
432
+ !isError && view.src ? /* @__PURE__ */ jsx("button", {
433
+ type: "button",
434
+ "aria-label": `Open ${view.prompt || "generated image"}`,
435
+ disabled: opening || props.sessionId === null,
436
+ className: "max-w-full self-start rounded-md focus-visible:outline-2 focus-visible:outline-doom-selected",
437
+ onClick: async () => {
438
+ if (props.sessionId === null || !view.src || opening) return;
439
+ const controller = new AbortController();
440
+ request.current?.abort();
441
+ request.current = controller;
442
+ setOpening(true);
443
+ setOpenError("");
444
+ try {
445
+ const tab = await transcriptImageTab(props.sessionId, props.toolCallId, view.src, view.prompt || "Generated image", controller.signal, view.inlineOnly);
446
+ if (!controller.signal.aborted) props.openTransientTab(tab);
447
+ } catch (reason) {
448
+ if (!controller.signal.aborted) setOpenError(reason instanceof Error ? reason.message : "This image could not be opened.");
449
+ } finally {
450
+ if (!controller.signal.aborted) setOpening(false);
451
+ }
452
+ },
453
+ children: /* @__PURE__ */ jsx("img", {
454
+ src: view.src,
455
+ alt: view.prompt || "Generated image",
456
+ className: "max-h-96 max-w-full rounded-md object-contain"
457
+ })
458
+ }) : null,
459
+ openError ? /* @__PURE__ */ jsx("p", {
460
+ role: "alert",
461
+ className: "text-sm text-doom-red",
462
+ children: openError
463
+ }) : null,
464
+ resultTextLines(result, output).map((line, index) => /* @__PURE__ */ jsx("span", {
465
+ className: `whitespace-pre-wrap break-words ${isError ? "text-doom-red" : "text-doom-dim"}`,
466
+ children: line
467
+ }, `${String(index)}-${line}`))
468
+ ]
469
+ }) : null] })
470
+ });
471
+ }
472
+ //#endregion
473
+ //#region src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web.tsx
474
+ var imagegen_web_default = defineToolRenderer({ message: ImagegenToolMessage });
475
+ //#endregion
476
+ //#region generated/web.ts
477
+ const via = (identity, value) => value === void 0 ? void 0 : {
478
+ ...identity,
479
+ ...value
480
+ };
481
+ const webPlugin = defineWebPlugin({
482
+ id: "image-gen",
483
+ session: {
484
+ get activityGroups() {
485
+ return [via({ name: "images" }, images_web_default)];
486
+ },
487
+ get fills() {
488
+ return [via({
489
+ slot: "activity.Images",
490
+ id: "images"
491
+ }, Images_activity_Images_web_default)];
492
+ },
493
+ get toolRenderers() {
494
+ return [via({ tools: ["imagegen"] }, imagegen_web_default)];
495
+ }
496
+ }
497
+ });
498
+ //#endregion
499
+ export { webPlugin };
500
+
501
+ //# sourceMappingURL=web.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.mjs","names":["activityGroupImages","fillImages","toolImagegen"],"sources":["../../src/types/apiRoutes.ts","../../generated/client.ts","../../src/constants/imagegen.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/imageFeedback.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/sessionImagesApi.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImagesView.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImages.tsx","../../src/extensions/workspaces/sessions/(frontend)/activity-group/images.web.ts","../../src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/imagegenToolView.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/ImagegenToolMessage.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web.tsx","../../generated/web.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, sessionApiAddress } from '@agimon-ai/po-core/web';\nimport { sealedTransport } from '@agimon-ai/po-web-security/browser';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'images' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'images',\n transport: (input, init) => sealedTransport.fetch(input, init),\n sessionAddress: sessionApiAddress,\n});\n","export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import type { SlotDeclaration, WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport type { ComponentType } from 'react';\n\nimport { MAX_REFERENCE_BYTES } from '../../../../../../constants/imagegen';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\n\ninterface ImageFeedbackContribution {\n version: 1;\n panel: ComponentType<WebPluginSlotProps & { target: ImageArtifact }>;\n}\n\nexport const imageFeedbackSlot = {\n slot: 'author.image-feedback',\n parse(input) {\n if (input === null || typeof input !== 'object') return null;\n const value = input as Partial<ImageFeedbackContribution>;\n return value.version === 1 && typeof value.panel === 'function' ? (value as ImageFeedbackContribution) : null;\n },\n} satisfies SlotDeclaration<ImageFeedbackContribution>;\n\n/** Inline save failures are preview bytes, never filesystem authority. */\nexport function inlineImageData(src: string | undefined): string | undefined {\n const prefix = 'data:image/png;base64,';\n if (src === undefined || !src.startsWith(prefix)) return undefined;\n const data = src.slice(prefix.length);\n if (\n data.length === 0 ||\n data.length > Math.ceil(MAX_REFERENCE_BYTES / 3) * 4 ||\n !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)\n )\n return undefined;\n try {\n const bytes = atob(data);\n return bytes.length <= MAX_REFERENCE_BYTES && bytes.startsWith('\\x89PNG\\r\\n\\x1a\\n') ? data : undefined;\n } catch {\n return undefined;\n }\n}\n","import { api } from '../../../../../../../generated/client';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\nimport { inlineImageData } from './imageFeedback';\n\n/** Resolve transcript identity at the session boundary, not from result metadata paths. */\nexport async function resolveTranscriptImage(\n sessionId: string,\n toolCallId: string,\n src: string,\n signal: AbortSignal,\n inlineOnly = false,\n): Promise<{ id: string; artifact?: ImageArtifact; inlineData?: string }> {\n if (inlineOnly) {\n signal.throwIfAborted();\n const inlineData = inlineImageData(src);\n if (!inlineData) throw new Error('The inline image is not a valid bounded PNG.');\n return { id: `inline-${toolCallId}`, inlineData };\n }\n const response = await api.session(sessionId).readImage({ query: { toolCallId }, signal });\n signal.throwIfAborted();\n if (response.ok) {\n if (response.data.sessionId !== sessionId) throw new Error('Image belongs to another session.');\n return { id: response.data.id, artifact: response.data };\n }\n if (response.status !== 404) throw new Error(response.error || 'This image could not be loaded.');\n const inlineData = inlineImageData(src);\n if (!inlineData) throw new Error('The inline image is not a valid bounded PNG.');\n return { id: `inline-${toolCallId}`, inlineData };\n}\n","import { Button, MediaPreview, Skeleton } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nexport interface ImageTile {\n id: string;\n label: string;\n src?: string;\n}\n\nexport interface ImagesGridViewProps {\n images: readonly ImageTile[];\n state: 'ready' | 'loading' | 'error';\n error?: string;\n onOpen: (id: string) => void;\n variant: 'activity' | 'gallery';\n hasMore?: boolean;\n onMore?: () => void;\n}\n\n/** Presentation only. The session container owns metadata and verified image URLs. */\nexport function ImagesGridView({ images, state, error, onOpen, variant, hasMore, onMore }: ImagesGridViewProps) {\n if (state === 'error')\n return (\n <p role=\"alert\" className=\"p-3 text-sm text-doom-red\">\n {error ?? 'Images could not be loaded.'}\n </p>\n );\n if (state === 'ready' && images.length === 0)\n return <p className=\"p-3 text-sm text-doom-dim\">Images generated in this session will appear here.</p>;\n const visible = variant === 'activity' ? images.slice(0, 6) : images;\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"grid grid-cols-3 gap-2\">\n {state === 'loading' && visible.length === 0\n ? Array.from({ length: 6 }, (_, index) => <Skeleton key={index} className=\"aspect-square rounded-md\" />)\n : visible.map((image) => (\n <button\n key={image.id}\n data-testid={`image-thumbnail-${image.id}`}\n type=\"button\"\n onClick={() => onOpen(image.id)}\n title={image.label}\n aria-label={`Open ${image.label}`}\n className=\"group min-w-0 overflow-hidden rounded-md border border-doom-border bg-doom-deep focus-visible:outline-2 focus-visible:outline-doom-selected\"\n >\n {image.src ? (\n <img\n src={image.src}\n alt={image.label}\n className=\"aspect-square w-full object-cover transition-opacity group-hover:opacity-80\"\n />\n ) : (\n <Skeleton className=\"aspect-square w-full\" />\n )}\n {variant === 'gallery' ? (\n <span className=\"block truncate px-2 py-2 text-sm text-doom-text\">{image.label}</span>\n ) : null}\n </button>\n ))}\n </div>\n {hasMore ? (\n <Button variant=\"outline\" onClick={onMore} disabled={state === 'loading'}>\n Load more images\n </Button>\n ) : null}\n </div>\n );\n}\n\nexport interface ImageViewerViewProps {\n image: ImageTile;\n state: 'ready' | 'loading' | 'error';\n error?: string;\n feedback?: ReactNode;\n}\n\nexport function ImageViewerView({ image, state, error, feedback }: ImageViewerViewProps) {\n return (\n <section className=\"flex h-full min-h-0 flex-col gap-3 overflow-y-auto p-4\">\n <h2 className=\"truncate text-lg font-semibold text-doom-hi\" title={image.label}>\n {image.label}\n </h2>\n {feedback ? (\n feedback\n ) : state === 'error' ? (\n <p role=\"alert\" className=\"text-sm text-doom-red\">\n {error ?? 'This image could not be loaded.'}\n </p>\n ) : state === 'loading' || !image.src ? (\n <Skeleton className=\"h-64 w-full rounded-md\" />\n ) : (\n <MediaPreview\n src={image.src}\n path={`${image.label}.png`}\n kind=\"image\"\n contentType=\"image/png\"\n className=\"min-h-0 flex-1 object-contain\"\n />\n )}\n {!feedback ? <p className=\"text-sm text-doom-dim\">Original image, read only.</p> : null}\n </section>\n );\n}\n","import { type TransientTab, type WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { api } from '../../../../../../../generated/client';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\nimport { imageFeedbackSlot } from '../_lib/imageFeedback';\nimport { resolveTranscriptImage } from '../_lib/sessionImagesApi';\nimport { ImagesGridView, ImageViewerView, type ImageTile } from './SessionImagesView';\n\nexport function imagesGalleryTab(): TransientTab {\n return { id: 'image-gen-gallery', label: 'Images', panel: ImagesGallery };\n}\n\nfunction pngUrl(data: string): string {\n const bytes = Uint8Array.from(atob(data), (character) => character.charCodeAt(0));\n return URL.createObjectURL(new Blob([bytes], { type: 'image/png' }));\n}\n\nexport function imageViewerTab(\n sessionId: string,\n image: { id: string; artifact?: ImageArtifact; inlineData?: string; label?: string },\n): TransientTab {\n return {\n id: `${image.inlineData === undefined ? 'image-gen-image' : 'image-gen-inline'}-${encodeURIComponent(image.id)}`,\n label: image.label ?? `Image ${image.id}`,\n panel: (props) => (props.sessionId === sessionId ? <SessionImageViewer {...props} image={image} /> : null),\n };\n}\n\n/** Inline bytes are a fallback only when no durable artifact exists. */\nexport async function transcriptImageTab(\n sessionId: string,\n toolCallId: string,\n src: string,\n label: string,\n signal: AbortSignal,\n inlineOnly = false,\n): Promise<TransientTab> {\n const image = await resolveTranscriptImage(sessionId, toolCallId, src, signal, inlineOnly);\n return imageViewerTab(sessionId, { ...image, label });\n}\n\nexport function ImagesActivity(props: WebPluginSlotProps) {\n return (\n <div data-testid=\"session-images-activity\">\n <SessionImages {...props} variant=\"activity\" />\n </div>\n );\n}\n\nfunction ImagesGallery(props: WebPluginSlotProps) {\n return (\n <section\n data-testid=\"session-images-gallery\"\n className=\"h-full min-h-0 overflow-y-auto p-4\"\n aria-label=\"Session image gallery\"\n >\n <h2 className=\"text-lg font-semibold text-doom-hi\">Images</h2>\n <p className=\"text-sm text-doom-dim\">Generated in this session, newest first.</p>\n <SessionImages {...props} variant=\"gallery\" />\n </section>\n );\n}\n\nfunction SessionImages(props: WebPluginSlotProps & { variant: 'activity' | 'gallery' }) {\n if (props.sessionId === null) return null;\n return (\n <ImagesPage\n key={`${props.sessionId}:${props.statuses['image-gen.images'] ?? ''}`}\n {...props}\n sessionId={props.sessionId}\n />\n );\n}\n\nfunction ImagesPage(props: WebPluginSlotProps & { sessionId: string; variant: 'activity' | 'gallery' }) {\n const [images, setImages] = useState<ImageTile[]>([]);\n const [cursor, setCursor] = useState('0');\n const [nextCursor, setNextCursor] = useState<string | null>(null);\n const [state, setState] = useState<'ready' | 'loading' | 'error'>('loading');\n const [error, setError] = useState('');\n const urls = useRef<string[]>([]);\n useEffect(\n () => () => {\n for (const url of urls.current) URL.revokeObjectURL(url);\n },\n [],\n );\n useEffect(() => {\n const controller = new AbortController();\n setState('loading');\n void (async () => {\n const response = await api\n .session(props.sessionId)\n .listImages({ query: { limit: '6', cursor }, signal: controller.signal });\n if (!response.ok) throw new Error(response.error || 'Images could not be loaded.');\n if (response.data.sessionId !== props.sessionId) throw new Error('Image history belongs to another session.');\n const artifacts = await Promise.all(\n response.data.items.map(async ({ id }) => {\n const result = await api.session(props.sessionId).readImage({ query: { id }, signal: controller.signal });\n if (!result.ok) {\n if (result.status === 404) return null;\n throw new Error(result.error || 'An image could not be loaded.');\n }\n if (result.data.sessionId !== props.sessionId) throw new Error('Image belongs to another session.');\n return result.data;\n }),\n );\n controller.signal.throwIfAborted();\n const tiles = artifacts.flatMap((artifact) => {\n if (!artifact) return [];\n const src = pngUrl(artifact.data);\n urls.current.push(src);\n return [{ id: artifact.id, label: `Image ${artifact.id}`, src }];\n });\n setImages((previous) =>\n cursor === '0' ? tiles : [...previous, ...tiles.filter((tile) => !previous.some(({ id }) => id === tile.id))],\n );\n setNextCursor(response.data.nextCursor);\n setState('ready');\n })().catch((reason: unknown) => {\n if (controller.signal.aborted) return;\n setError(reason instanceof Error ? reason.message : 'Images could not be loaded.');\n setState('error');\n });\n return () => controller.abort();\n }, [props.sessionId, cursor]);\n return (\n <ImagesGridView\n images={images}\n state={state}\n error={error}\n variant={props.variant}\n onOpen={(id) => props.openTransientTab(imageViewerTab(props.sessionId, { id }))}\n hasMore={props.variant === 'gallery' && nextCursor !== null}\n onMore={() => {\n if (nextCursor !== null && state !== 'loading') setCursor(nextCursor);\n }}\n />\n );\n}\n\nfunction SessionImageViewer(\n props: WebPluginSlotProps & { image: { id: string; artifact?: ImageArtifact; inlineData?: string; label?: string } },\n) {\n const [artifact, setArtifact] = useState<ImageArtifact>();\n const [src, setSrc] = useState<string>();\n const [error, setError] = useState('');\n const [state, setState] = useState<'ready' | 'loading' | 'error'>('loading');\n useEffect(() => {\n const controller = new AbortController();\n let objectUrl: string | undefined;\n setArtifact(undefined);\n setSrc(undefined);\n setError('');\n setState('loading');\n void (async () => {\n if (props.sessionId === null) return;\n let data = props.image.inlineData;\n if (!data) {\n let target = props.image.artifact;\n if (!target) {\n const result = await api\n .session(props.sessionId)\n .readImage({ query: { id: props.image.id }, signal: controller.signal });\n if (!result.ok) throw new Error(result.error || 'This image could not be loaded.');\n target = result.data;\n }\n if (target.sessionId !== props.sessionId) throw new Error('Image belongs to another session.');\n controller.signal.throwIfAborted();\n setArtifact(target);\n data = target.data;\n }\n controller.signal.throwIfAborted();\n objectUrl = pngUrl(data);\n setSrc(objectUrl);\n setState('ready');\n })().catch((reason: unknown) => {\n if (controller.signal.aborted) return;\n setError(reason instanceof Error ? reason.message : 'This image could not be loaded.');\n setState('error');\n });\n return () => {\n controller.abort();\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n };\n }, [props.sessionId, props.image]);\n const Panel =\n artifact && props.activeMinorModes?.includes('author')\n ? props.slotData(imageFeedbackSlot)[0]?.data.panel\n : undefined;\n return (\n <section data-testid=\"session-image-viewer\" data-image-id={props.image.id} className=\"flex h-full min-h-0 flex-col\">\n <div className=\"min-h-0 flex-1\">\n <ImageViewerView\n image={{ id: props.image.id, label: props.image.label ?? `Image ${props.image.id}`, src }}\n state={state}\n error={error}\n feedback={Panel && artifact ? <Panel {...props} target={artifact} /> : undefined}\n />\n </div>\n {props.image.inlineData ? (\n <p className=\"px-4 pb-4 text-sm text-doom-dim\">\n This inline image was not saved. Original-path refinement is unavailable.\n </p>\n ) : null}\n </section>\n );\n}\n","import { defineActivityGroup } from '@agimon-ai/po-core/web';\n\nimport { imagesGalleryTab } from '../tool/_components/SessionImages';\n\nexport default defineActivityGroup({\n name: 'Images',\n keys: '',\n activeSource: { subscribe: () => () => undefined, isActive: () => false },\n marksBackgroundWork: false,\n transientTab: imagesGalleryTab,\n order: 35,\n});\n","import { defineFill } from '@agimon-ai/po-core/web';\n\nimport { ImagesActivity } from '../tool/_components/SessionImages';\n\nexport default defineFill({ slot: 'activity.Images', component: ImagesActivity });\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\n\nexport function imagegenToolView({ args, result }: Pick<ToolMessageRenderProps, 'args' | 'result'>) {\n const prompt = typeof args.prompt === 'string' ? args.prompt : '';\n const editing = Array.isArray(args.referenced_image_paths) && args.referenced_image_paths.length > 0;\n // Only inline PNG results from this tool, never a URL supplied in details.\n const image = result?.content.find(\n (block): block is { type: 'image'; data: string; mimeType: 'image/png' } =>\n block !== null &&\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'image' &&\n 'mimeType' in block &&\n block.mimeType === 'image/png' &&\n 'data' in block &&\n typeof block.data === 'string',\n );\n const src = image ? `data:image/png;base64,${image.data}` : undefined;\n const details = result?.details;\n const inlineOnly =\n details !== null &&\n typeof details === 'object' &&\n 'saveWarning' in details &&\n typeof details.saveWarning === 'string';\n return { prompt, editing, src, inlineOnly };\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\nimport {\n MessageItem,\n MessageItemBody,\n MessageItemHeader,\n MessageItemStatus,\n resultTextLines,\n toolTone,\n} from '@agimon-ai/po-web-components';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { imagegenToolView } from '../_lib/imagegenToolView';\nimport { transcriptImageTab } from './SessionImages';\n\nexport function ImagegenToolMessage(props: ToolMessageRenderProps) {\n const { result, output, running, isError } = props;\n const view = imagegenToolView(props);\n const [opening, setOpening] = useState(false);\n const [openError, setOpenError] = useState('');\n const request = useRef<AbortController | undefined>(undefined);\n useEffect(() => {\n setOpening(false);\n setOpenError('');\n return () => request.current?.abort();\n }, [props.sessionId, props.toolCallId]);\n return (\n <MessageItem tone={toolTone({ running, isError })} expandable defaultExpanded>\n {({ expanded }) => (\n <>\n <MessageItemHeader title=\"imagegen\">\n <span data-testid=\"tool-call-imagegen\" className=\"min-w-0 flex-1 truncate text-doom-text\">\n {view.prompt}\n </span>\n <span className=\"shrink-0 text-doom-faint\">{view.editing ? 'edit' : 'generate'}</span>\n </MessageItemHeader>\n {expanded ? (\n <MessageItemBody data-testid=\"tool-result-imagegen\" className=\"flex flex-col gap-2\">\n {running ? <MessageItemStatus tone=\"running\">creating image</MessageItemStatus> : null}\n {isError ? <MessageItemStatus tone=\"error\">failed</MessageItemStatus> : null}\n {!isError && view.src ? (\n <button\n type=\"button\"\n aria-label={`Open ${view.prompt || 'generated image'}`}\n disabled={opening || props.sessionId === null}\n className=\"max-w-full self-start rounded-md focus-visible:outline-2 focus-visible:outline-doom-selected\"\n onClick={async () => {\n if (props.sessionId === null || !view.src || opening) return;\n const controller = new AbortController();\n request.current?.abort();\n request.current = controller;\n setOpening(true);\n setOpenError('');\n try {\n const tab = await transcriptImageTab(\n props.sessionId,\n props.toolCallId,\n view.src,\n view.prompt || 'Generated image',\n controller.signal,\n view.inlineOnly,\n );\n if (!controller.signal.aborted) props.openTransientTab(tab);\n } catch (reason) {\n if (!controller.signal.aborted)\n setOpenError(reason instanceof Error ? reason.message : 'This image could not be opened.');\n } finally {\n if (!controller.signal.aborted) setOpening(false);\n }\n }}\n >\n <img\n src={view.src}\n alt={view.prompt || 'Generated image'}\n className=\"max-h-96 max-w-full rounded-md object-contain\"\n />\n </button>\n ) : null}\n {openError ? (\n <p role=\"alert\" className=\"text-sm text-doom-red\">\n {openError}\n </p>\n ) : null}\n {resultTextLines(result, output).map((line, index) => (\n <span\n key={`${String(index)}-${line}`}\n className={`whitespace-pre-wrap break-words ${isError ? 'text-doom-red' : 'text-doom-dim'}`}\n >\n {line}\n </span>\n ))}\n </MessageItemBody>\n ) : null}\n </>\n )}\n </MessageItem>\n );\n}\n","import { defineToolRenderer } from '@agimon-ai/po-core/web';\n\nimport { ImagegenToolMessage } from './_components/ImagegenToolMessage';\n\nexport default defineToolRenderer({ message: ImagegenToolMessage });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport activityGroupImages from '../src/extensions/workspaces/sessions/(frontend)/activity-group/images.web';\nimport fillImages from '../src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'image-gen',\n session: {\n get activityGroups(): WebPluginContributions['activityGroups'] { return [via({ name: 'images' }, activityGroupImages)]; },\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'activity.Images', id: 'images' }, fillImages)]; },\n get toolRenderers(): WebPluginContributions['toolRenderers'] { return [via({ tools: ['imagegen'] }, toolImagegen)]; },\n },\n});\n"],"mappings":"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"}