dsh-image-gen 0.6.7 → 0.6.9

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 (45) hide show
  1. package/LICENSE +201 -21
  2. package/README.en.md +391 -375
  3. package/README.md +391 -375
  4. package/README.zh-CN.md +3 -3
  5. package/docs/assets/readme/chat-generate.webp +0 -0
  6. package/docs/assets/readme/other-features.webp +0 -0
  7. package/lib/client.js +315 -49
  8. package/lib/client.js.map +1 -1
  9. package/lib/index.js +259 -49
  10. package/lib/types/client/conversation-image-revisions.d.ts +2 -2
  11. package/lib/types/client/gallery-view.d.ts +4 -0
  12. package/lib/types/client/index.d.ts +7 -1
  13. package/lib/types/client/multi-model-compare.d.ts +3 -3
  14. package/lib/types/client/provider-pill.d.ts +1 -1
  15. package/lib/types/client/studio-chat-panel.d.ts +23 -0
  16. package/lib/types/client/studio-view.d.ts +4 -0
  17. package/lib/types/client/tl/diagram-landing.d.ts +75 -0
  18. package/lib/types/client/tl/diagram-layout.d.ts +76 -0
  19. package/lib/types/client/tl/diagram-measure.d.ts +40 -0
  20. package/lib/types/config.d.ts +19 -2
  21. package/lib/types/diagram.d.ts +42 -0
  22. package/lib/types/openai-compatible.d.ts +3 -0
  23. package/lib/types/seedream.d.ts +7 -0
  24. package/lib/types/shared.d.ts +55 -4
  25. package/lib/types/studio-chat.d.ts +48 -0
  26. package/lib/types/studio.d.ts +3 -2
  27. package/lib/types/subscription/manager.d.ts +15 -0
  28. package/lib/types/subscription/vendors/antigravity.d.ts +10 -1
  29. package/lib/types/subscription/vendors/codex.d.ts +2 -0
  30. package/lib/types/subscription/vendors/grok.d.ts +2 -0
  31. package/lib/types/subscription.d.ts +7 -5
  32. package/package.json +11 -9
  33. package/skills/install-dsh-image-gen/SKILL.md +22 -22
  34. package/lib/types/client/inspiration-api.d.ts +0 -10
  35. package/lib/types/client/inspiration-detail.d.ts +0 -14
  36. package/lib/types/client/tldraw/generated/tldraw-assets.d.ts +0 -12
  37. package/lib/types/client/tldraw/generated/tldraw-css.d.ts +0 -1
  38. package/lib/types/client/tldraw/tldraw-style.d.ts +0 -1
  39. package/lib/types/client/tldraw/tldraw-workspace.d.ts +0 -1
  40. package/lib/types/inspiration/cache.d.ts +0 -20
  41. package/lib/types/inspiration/downloader.d.ts +0 -27
  42. package/lib/types/inspiration/routes.d.ts +0 -13
  43. package/lib/types/inspiration/sources.d.ts +0 -33
  44. package/lib/types/inspiration/types.d.ts +0 -65
  45. package/lib/types/inspiration/updater.d.ts +0 -7
@@ -28,6 +28,12 @@ interface ImageSettings {
28
28
  openaiCompatEditExtra?: Record<string, unknown>;
29
29
  seedreamBaseURL?: string;
30
30
  seedreamModel?: string;
31
+ /** Ark `output_format`; `png` is lossless and keeps an alpha channel. */
32
+ seedreamOutputFormat?: 'png' | 'jpeg';
33
+ /** Ark `watermark`; off removes the baked-in "AI generated" mark. */
34
+ seedreamWatermark?: boolean;
35
+ /** Ark `background`; `transparent` needs an alpha-bearing edit reference. */
36
+ seedreamBackground?: 'opaque' | 'transparent';
31
37
  dashscopeEndpoint?: string;
32
38
  dashscopeModel?: string;
33
39
  xaiBaseURL?: string;
@@ -81,7 +87,7 @@ interface ImageCardFace {
81
87
  locale?: LocaleService | undefined;
82
88
  promoted: boolean;
83
89
  }
84
- type SettingsCardProps = PropsRuntime<'settings.plugin.item'> & InjectFace<SettingsFace>;
90
+ type SettingsCardProps = PropsRuntime<'settings.plugins.tab'> & InjectFace<SettingsFace>;
85
91
  type ImageCardProps = PropsRuntime<'tool.call.toolview'> & InjectFace<ImageCardFace>;
86
92
  interface ImageResultNodeProps {
87
93
  node: {
@@ -1,4 +1,4 @@
1
- import type { CloudImageProvider, StudioProviderProfile } from '../shared.js';
1
+ import type { StudioProvider, StudioProviderProfile } from '../shared.js';
2
2
  export interface ComparisonTarget {
3
3
  profile: StudioProviderProfile;
4
4
  ratio: string;
@@ -6,6 +6,6 @@ export interface ComparisonTarget {
6
6
  adjusted: boolean;
7
7
  }
8
8
  /** Map one shared output intent to settings accepted by every target model. */
9
- export declare function buildComparisonTargets(profiles: readonly StudioProviderProfile[], selectedProviders: readonly CloudImageProvider[], ratio: string, quality: string): ComparisonTarget[];
9
+ export declare function buildComparisonTargets(profiles: readonly StudioProviderProfile[], selectedProviders: readonly StudioProvider[], ratio: string, quality: string): ComparisonTarget[];
10
10
  /** Start with two models, not every configured API, to avoid surprise spend. */
11
- export declare function initialComparisonProviders(profiles: readonly StudioProviderProfile[], activeProvider: CloudImageProvider): CloudImageProvider[];
11
+ export declare function initialComparisonProviders(profiles: readonly StudioProviderProfile[], activeProvider: StudioProvider): StudioProvider[];
@@ -45,5 +45,5 @@ export declare function pillModelOf(provider: ImageProvider, value: PillSettings
45
45
  /** One fixed-position provider menu anchored to the pill button. */
46
46
  export declare function ImageProviderPill(props: ProviderPillFace): import("react").JSX.Element | null;
47
47
  /** Styles for the pill and its fixed-position menu; injected by the client entry. */
48
- export declare const PROVIDER_PILL_STYLE = "\n.dsh-ig-pill-root{position:relative;display:inline-flex;align-items:center;height:26px}\n.dsh-ig-pill-button{display:inline-flex;align-items:center;gap:5px;height:26px;padding:0 8px 0 7px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:13px;background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,#4b5563);font:inherit;font-size:12px;line-height:1;cursor:pointer;transition:border-color .15s,background .15s,color .15s;-webkit-user-select:none;user-select:none}\n.dsh-ig-pill-button:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed,#9ca3af);color:var(--dsw-alias-label-primary,#111827)}\n.dsh-ig-pill-button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:1px}\n.dsh-ig-pill-button:disabled{opacity:.5;cursor:not-allowed}\n.dsh-ig-pill-button-open{border-color:var(--dsw-alias-brand-primary,#4c78ff);color:var(--dsw-alias-label-primary,#111827)}\n.dsh-ig-pill-icon{flex:none;color:var(--dsw-alias-brand-primary,#4c78ff)}\n.dsh-ig-pill-provider{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-ig-pill-caret{display:inline-flex;flex:none;transition:transform .15s}\n.dsh-ig-pill-caret-open{transform:rotate(180deg)}\n.dsh-ig-pill-menu{position:fixed;z-index:1000;min-width:264px;max-width:min(320px,calc(100vw - 24px));padding:6px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;background:var(--dsw-alias-bg-layer-3,#fff);box-shadow:0 12px 32px rgba(0,0,0,.16),0 2px 8px rgba(0,0,0,.08);max-height:min(320px,calc(100vh - 48px));overflow-y:auto}\n.dsh-ig-pill-menu-title{padding:6px 8px 4px;font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary,#6b7280)}\n.dsh-ig-pill-option{display:flex;width:100%;align-items:center;gap:9px;padding:7px 8px;border:0;border-radius:8px;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer}\n.dsh-ig-pill-option:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,#f3f4f6)}\n.dsh-ig-pill-option:disabled{opacity:.6;cursor:default}\n.dsh-ig-pill-option:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:-2px}\n.dsh-ig-pill-option-active{background:var(--dsw-alias-brand-primary-soft,rgba(76,120,255,.10))}\n.dsh-ig-pill-dot{flex:none;width:7px;height:7px;border-radius:50%}\n.dsh-ig-pill-dot-ok{background:#22c55e}\n.dsh-ig-pill-dot-missing{background:#9ca3af}\n.dsh-ig-pill-dot-neutral{background:#4c78ff}\n.dsh-ig-pill-option-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}\n.dsh-ig-pill-option-name{font-size:12.5px;font-weight:500;color:var(--dsw-alias-label-primary,#111827);line-height:1.2}\n.dsh-ig-pill-option-sub{font-size:11px;color:var(--dsw-alias-label-tertiary,#6b7280);line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-ig-pill-check{flex:none;color:var(--dsw-alias-brand-primary,#4c78ff)}\n.dsh-ig-pill-error{margin-top:4px;padding:6px 8px;border-radius:8px;background:rgba(239,68,68,.08);color:#ef4444;font-size:11.5px;line-height:1.4;word-break:break-all}\n";
48
+ export declare const PROVIDER_PILL_STYLE = "\n.dsh-ig-pill-root{position:relative;display:inline-flex;align-items:center;height:28px}\n.dsh-ig-pill-button{display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 9px 0 8px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:14px;background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,#4b5563);font:inherit;font-size:13px;line-height:20px;cursor:pointer;transition:border-color .15s,background .15s,color .15s;-webkit-user-select:none;user-select:none}\n.dsh-ig-pill-button:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed,#9ca3af);color:var(--dsw-alias-label-primary,#111827)}\n.dsh-ig-pill-button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:1px}\n.dsh-ig-pill-button:disabled{opacity:.5;cursor:not-allowed}\n.dsh-ig-pill-button-open{border-color:var(--dsw-alias-brand-primary,#4c78ff);color:var(--dsw-alias-label-primary,#111827)}\n.dsh-ig-pill-icon{flex:none;color:var(--dsw-alias-brand-primary,#4c78ff)}\n.dsh-ig-pill-provider{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-ig-pill-caret{display:inline-flex;flex:none;transition:transform .15s}\n.dsh-ig-pill-caret-open{transform:rotate(180deg)}\n@container (max-width:700px){\n .dsh-ig-pill-caret{display:none}\n .dsh-ig-pill-button{padding:0 7px 0 6px}\n}\n.dsh-ig-pill-menu{position:fixed;z-index:1000;min-width:264px;max-width:min(320px,calc(100vw - 24px));padding:6px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;background:var(--dsw-alias-bg-layer-3,#fff);box-shadow:0 12px 32px rgba(0,0,0,.16),0 2px 8px rgba(0,0,0,.08);max-height:min(320px,calc(100vh - 48px));overflow-y:auto}\n.dsh-ig-pill-menu-title{padding:6px 8px 4px;font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary,#6b7280)}\n.dsh-ig-pill-option{display:flex;width:100%;align-items:center;gap:9px;padding:7px 8px;border:0;border-radius:8px;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer}\n.dsh-ig-pill-option:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,#f3f4f6)}\n.dsh-ig-pill-option:disabled{opacity:.6;cursor:default}\n.dsh-ig-pill-option:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:-2px}\n.dsh-ig-pill-option-active{background:var(--dsw-alias-brand-primary-soft,rgba(76,120,255,.10))}\n.dsh-ig-pill-dot{flex:none;width:7px;height:7px;border-radius:50%}\n.dsh-ig-pill-dot-ok{background:#22c55e}\n.dsh-ig-pill-dot-missing{background:#9ca3af}\n.dsh-ig-pill-dot-neutral{background:#4c78ff}\n.dsh-ig-pill-option-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}\n.dsh-ig-pill-option-name{font-size:12.5px;font-weight:500;color:var(--dsw-alias-label-primary,#111827);line-height:1.2}\n.dsh-ig-pill-option-sub{font-size:11px;color:var(--dsw-alias-label-tertiary,#6b7280);line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-ig-pill-check{flex:none;color:var(--dsw-alias-brand-primary,#4c78ff)}\n.dsh-ig-pill-error{margin-top:4px;padding:6px 8px;border-radius:8px;background:rgba(239,68,68,.08);color:#ef4444;font-size:11.5px;line-height:1.4;word-break:break-all}\n";
49
49
  export {};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Workbench chat panel: the right-side DSH conversation surface.
3
+ *
4
+ * A dedicated archived agent session lives on the host side (studio-chat.ts);
5
+ * this panel pulls its projected event feed through CHAT_ROUTE with adaptive
6
+ * polling (?since=<seq> increments; faster while a turn is running, slower
7
+ * when idle, paused while the webview is hidden) and submits user turns with
8
+ * POST. Tool-generated images are mirrored onto the tldraw canvas through the
9
+ * landing queue and upserted into the gallery (the recent list refreshes via
10
+ * its subscription). The panel is intentionally unmount-friendly: re-pulls
11
+ * from seq 0 on remount, and both landing and gallery writes are deduped by
12
+ * attachmentId, so tab switches are safe.
13
+ */
14
+ import { type FC } from 'react';
15
+ /** Workspace scoping mirrored onto gallery records; shape-compatible with StudioWorkspaceProps. */
16
+ export interface ChatWorkspaceScope {
17
+ workspaceId?: string | undefined;
18
+ path?: string | undefined;
19
+ }
20
+ export declare const StudioChatPanel: FC<{
21
+ lang: 'zh' | 'en';
22
+ workspace?: ChatWorkspaceScope | null | undefined;
23
+ }>;
@@ -15,6 +15,10 @@ export interface StudioWorkspaceProps {
15
15
  }
16
16
  export declare const StudioView: FC<{
17
17
  locale?: LocaleService | undefined;
18
+ /** Host credential-change notifier; re-reads provider sign-in state silently. */
19
+ credentialEvents?: {
20
+ listen(callback: () => void): () => void;
21
+ } | undefined;
18
22
  workspace?: StudioWorkspaceProps | null | undefined;
19
23
  initialPrompt?: string | undefined;
20
24
  /**
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Land one create_diagram result onto a tldraw page.
3
+ *
4
+ * Shapes and their arrow bindings are created in a single editor.run
5
+ * transaction, and a history stopping point is marked BEFORE the batch:
6
+ * tldraw's HistoryManager pops diffs until the next stop mark on undo, so
7
+ * without the mark two diagrams landing back-to-back would undo together.
8
+ * With it, each diagram is one independent undo step (undo/redo verified
9
+ * against the HistoryManager source and on the real canvas).
10
+ *
11
+ * Arrows are ELBOW connectors with BOTH terminals bound. Each terminal's
12
+ * binding side is derived from dagre's polyline: the first/last segment's
13
+ * dominant axis says which node edge the route uses (back edges leave the
14
+ * source's top and re-enter the target's bottom through the corridor dagre
15
+ * reserved, instead of tldraw guessing a center-to-center route). tldraw
16
+ * then re-routes the middle segments itself from the bindings — the
17
+ * polyline is a per-terminal side hint, not a full path contract. Whether
18
+ * the final arrows avoid crossing nodes and whether labels sit clear of
19
+ * geometry is validated on the real canvas, not assumed here.
20
+ *
21
+ * Derived anchors are clamped to the middle band (0.2–0.8) of their edge:
22
+ * tldraw's getEdgeFromNormalizedAnchor resolves the side via |x-0.5| vs
23
+ * |y-0.5|, and a corner-ish anchor could resolve to the wrong side.
24
+ *
25
+ * Edge labels set labelPosition from dagre's arc-length ratio — a
26
+ * best-effort estimate, since tldraw applies the ratio to its own routed
27
+ * path.
28
+ *
29
+ * Self loops (empty dagre polyline) fall back to center bindings: tldraw
30
+ * draws bound self-loop arrows natively.
31
+ *
32
+ * Every created shape carries meta.diagramId, the same dedupe identity the
33
+ * landing reconcile uses for images' meta.galleryId.
34
+ */
35
+ import { type Editor } from 'tldraw';
36
+ import { type DiagramLayout, type DiagramLayoutEdge, type DiagramLayoutNode, type DiagramPoint } from './diagram-layout.js';
37
+ import type { TlDiagramLanding } from './tl-canvas-bridge.js';
38
+ /** Terminal binding plan: the precise anchor, or a center fallback. */
39
+ export interface TerminalPlan {
40
+ anchor: {
41
+ x: number;
42
+ y: number;
43
+ };
44
+ precise: boolean;
45
+ }
46
+ /**
47
+ * Derive one terminal's binding side + precise anchor from dagre's
48
+ * polyline. The boundary point sits ON the node outline (dagre guarantees
49
+ * this via its node-intersection pass), so the binding side is the OUTLINE
50
+ * EDGE CLOSEST TO THE BOUNDARY POINT — not the segment direction. The last
51
+ * segment often enters at an angle because dagre projects the corridor
52
+ * point onto the outline (e.g. a back edge entering the target's bottom
53
+ * with a final dx=57, dy=-48 segment), and direction-dominance would
54
+ * misread that as `right`. The segment direction is only used to break
55
+ * exact corner ties. The boundary point gives the cross-axis position,
56
+ * clamped to the anchor band.
57
+ */
58
+ export declare function terminalPlan(node: Pick<DiagramLayoutNode, 'x' | 'y' | 'w' | 'h'>, boundary: DiagramPoint, next: DiagramPoint): TerminalPlan;
59
+ /**
60
+ * Binding plans for one edge's two terminals. Self loops (no dagre
61
+ * polyline) get center plans: tldraw renders bound self loops natively.
62
+ */
63
+ export declare function edgeTerminalPlans(edge: DiagramLayoutEdge, fromNode: DiagramLayoutNode, toNode: DiagramLayoutNode): {
64
+ start: TerminalPlan;
65
+ end: TerminalPlan;
66
+ };
67
+ /**
68
+ * Land one diagram with its top-left at `origin`. The caller passes the
69
+ * precomputed layout (it needs the layout bounds to pick the origin, so the
70
+ * layout is computed once and shared). No-op on empty layouts.
71
+ */
72
+ export declare function landDiagram(editor: Editor, landing: TlDiagramLanding, layout: DiagramLayout, origin: {
73
+ x: number;
74
+ y: number;
75
+ }): void;
@@ -0,0 +1,76 @@
1
+ import type { DiagramNodeShape, DiagramSpec } from '../../shared.js';
2
+ /** One laid-out node: local id, label, outline, top-left position, size. */
3
+ export interface DiagramLayoutNode {
4
+ id: string;
5
+ label: string;
6
+ shape: DiagramNodeShape;
7
+ x: number;
8
+ y: number;
9
+ w: number;
10
+ h: number;
11
+ }
12
+ /** A point in graph space (same origin as the layout nodes). */
13
+ export interface DiagramPoint {
14
+ x: number;
15
+ y: number;
16
+ }
17
+ /** One laid-out edge between node local ids, with dagre's routing hint. */
18
+ export interface DiagramLayoutEdge {
19
+ from: string;
20
+ to: string;
21
+ label?: string;
22
+ /**
23
+ * dagre's polyline in graph space. points[0] lies on the source node's
24
+ * outline and points[last] on the target's. Self loops carry an empty
25
+ * array: dagre cannot route them, and the landing layer falls back to
26
+ * center bindings (tldraw draws bound self loops natively).
27
+ */
28
+ points: DiagramPoint[];
29
+ /**
30
+ * Where the label sits along the polyline, as an arc-length ratio in
31
+ * [0, 1] (tldraw's arrow labelPosition shares the ratio semantics). This
32
+ * is a best-effort initial estimate: tldraw applies the ratio to its own
33
+ * routed path, which may differ from dagre's polyline in the middle
34
+ * segments. The final label position is validated on the real canvas.
35
+ */
36
+ labelPosition?: number;
37
+ }
38
+ export interface DiagramLayout {
39
+ nodes: DiagramLayoutNode[];
40
+ edges: DiagramLayoutEdge[];
41
+ width: number;
42
+ height: number;
43
+ /** Growth direction of the layout, needed by the landing layer to pick
44
+ * binding anchors (TB connects bottom→top edges, LR right→left edges). */
45
+ direction: 'TB' | 'LR';
46
+ }
47
+ /** Node size in canvas units (top-left anchored, like tldraw shape props). */
48
+ export interface DiagramSize {
49
+ w: number;
50
+ h: number;
51
+ }
52
+ /** Measured sizes fed into the pure layout function. */
53
+ export interface DiagramMeasurements {
54
+ /** node id → measured node size. Missing entries fall back to the default. */
55
+ nodes: ReadonlyMap<string, DiagramSize>;
56
+ /**
57
+ * edge list index → measured label size. Only edges carrying a label are
58
+ * present; dagre reserves rank space for these labels.
59
+ */
60
+ edgeLabels?: ReadonlyMap<number, DiagramSize>;
61
+ }
62
+ /** Fallback size for nodes the caller did not measure (defensive only). */
63
+ export declare const DEFAULT_NODE_SIZE: DiagramSize;
64
+ /**
65
+ * Where a point sits along a polyline, as an arc-length ratio in [0, 1].
66
+ * The point is projected onto the nearest polyline segment. Degenerate
67
+ * polylines return 0.5.
68
+ */
69
+ export declare function arcRatioAlongPolyline(points: readonly DiagramPoint[], target: DiagramPoint): number;
70
+ /**
71
+ * Lay out a diagram spec with coordinates relative to (0, 0). The layout is
72
+ * deterministic: same spec + same measurements always produce the same
73
+ * coordinates (dagre is seeded by insertion order, which we keep stable by
74
+ * iterating the spec's arrays as given).
75
+ */
76
+ export declare function layoutDiagram(diagram: DiagramSpec, measurements: DiagramMeasurements): DiagramLayout;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Measure diagram node/edge-label sizes with tldraw's own DOM text measuring.
3
+ *
4
+ * This is the "real" half of the measurement/layout split: the editor's
5
+ * TextManager renders text with the same font family, size, line height and
6
+ * wrap width the landed geo shapes will use, so RECTANGLE node sizes track
7
+ * the rendered label 1:1 (no character-width heuristics).
8
+ *
9
+ * The measure parameters mirror tldraw's internal geo-shape constants for
10
+ * our landed shapes (font 'sans', size 'm'): theme.fontSize * 1.375,
11
+ * theme.lineHeight, label padding 16.
12
+ *
13
+ * Non-rectangular outlines are APPROXIMATE, not 1:1. tldraw re-wraps the
14
+ * label against the SHAPE's width (shape w - padding), and we size the
15
+ * shape from the text measured at the pre-inflation wrap width — so after
16
+ * inflation the label re-wraps into fewer, wider lines. For short labels
17
+ * (single line at the wrap width) the geometry below is exact. For long
18
+ * wrapped labels the re-wrapped block can grow past the outline's inscribed
19
+ * rectangle and crowd the diamond's slanted edges / the ellipse's arc:
20
+ * greedy text wrapping scales with shape width while the inscribed rectangle
21
+ * only halves it, so there is no closed-form fix. The create_diagram tool
22
+ * prompt steers long text to rectangles and keeps diamond labels short;
23
+ * whether a real label fits is ultimately a visual check on the real canvas
24
+ * (see the diagram-verify harness), not something this module can promise.
25
+ * - diamond: a single-line text rect (tw, th) fits exactly when
26
+ * tw/w + th/h <= 1, so doubling the text size (+ padding) is exact for
27
+ * unwrapped labels.
28
+ * - ellipse: a single-line corner point fits exactly when
29
+ * tw²/w² + th²/h² <= 1, so a √2 factor (+ padding) is exact for
30
+ * unwrapped labels.
31
+ */
32
+ import type { Editor } from 'tldraw';
33
+ import type { DiagramSpec } from '../../shared.js';
34
+ import type { DiagramMeasurements } from './diagram-layout.js';
35
+ /**
36
+ * Measure every node and edge label of a spec against the editor's live
37
+ * theme and fonts. Node sizes carry the outline inflation for diamond and
38
+ * ellipse; edge-label sizes let dagre reserve rank space for labels.
39
+ */
40
+ export declare function measureDiagram(editor: Editor, diagram: DiagramSpec): DiagramMeasurements;
@@ -1,7 +1,7 @@
1
1
  /** User-facing configuration for supported image providers. */
2
2
  import z from '@deepseek-ai/schemastery';
3
- import { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ComfyUIWorkflowEntry, type ImageProvider } from './shared.js';
4
- export { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ComfyUIWorkflowEntry, type ImageProvider, };
3
+ import { ARK_BACKGROUND_MODES, ARK_OUTPUT_FORMATS, DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ArkBackgroundMode, type ArkOutputFormat, type ArkOutputOptions, type ComfyUIWorkflowEntry, type ImageProvider } from './shared.js';
4
+ export { ARK_BACKGROUND_MODES, ARK_OUTPUT_FORMATS, DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ArkBackgroundMode, type ArkOutputFormat, type ArkOutputOptions, type ComfyUIWorkflowEntry, type ImageProvider, };
5
5
  /** Default workspace subfolder that receives generated image files. */
6
6
  export declare const DEFAULT_WORKSPACE_FOLDER = "dsh-image-gen";
7
7
  /** Google tool-level controls. */
@@ -34,6 +34,22 @@ export interface Config {
34
34
  openaiCompatEditExtra?: Record<string, unknown>;
35
35
  seedreamBaseURL?: string;
36
36
  seedreamModel?: string;
37
+ /**
38
+ * Ark `output_format`. Ark defaults to `jpeg`, which is lossy and cannot
39
+ * carry an alpha channel; `png` is lossless, so it survives later editing
40
+ * (e.g. background removal) without JPEG ringing around the subject.
41
+ */
42
+ seedreamOutputFormat?: ArkOutputFormat;
43
+ /**
44
+ * Ark `watermark`. Ark defaults to `true`, which bakes an "AI generated"
45
+ * mark into the bottom-right corner.
46
+ */
47
+ seedreamWatermark?: boolean;
48
+ /**
49
+ * Ark `background`. Only the edit path can honour `transparent`, and only
50
+ * when every reference image already carries an alpha channel.
51
+ */
52
+ seedreamBackground?: ArkBackgroundMode;
37
53
  dashscopeEndpoint?: string;
38
54
  dashscopeModel?: string;
39
55
  xaiBaseURL?: string;
@@ -85,6 +101,7 @@ export declare function resolveProvider(config: Config): {
85
101
  model: string;
86
102
  baseURL: string;
87
103
  imageSize: string;
104
+ arkOptions: ArkOutputOptions;
88
105
  } | {
89
106
  provider: 'dashscope';
90
107
  apiKeyEnv: string;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * create_diagram: a structure-only tool whose results land on the workbench
3
+ * infinite canvas.
4
+ *
5
+ * The model outputs a declarative DSL (nodes + edges with local ids, never
6
+ * coordinates). The tool call succeeds immediately — exactly like image
7
+ * generation — and the diagram rides the same landing bus: an open canvas
8
+ * renders it at once, a closed one renders it the moment it opens. The canvas
9
+ * computes the layered layout, creates geo shapes, and binds every arrow to
10
+ * its endpoints so the user can drag nodes around with arrows following.
11
+ */
12
+ import type { Context } from '@deepseek-ai/cordis';
13
+ import { type DiagramDirection, type DiagramEdgeSpec, type DiagramNodeSpec } from './shared.js';
14
+ /** Value returned by create_diagram and echoed into the tool-result schema. */
15
+ export interface CreateDiagramValue {
16
+ diagramId: string;
17
+ title: string;
18
+ direction: DiagramDirection;
19
+ nodeCount: number;
20
+ edgeCount: number;
21
+ }
22
+ /** Untrusted create_diagram arguments as they arrive from the model. */
23
+ export interface CreateDiagramArgs {
24
+ title?: unknown;
25
+ direction?: unknown;
26
+ nodes?: unknown;
27
+ edges?: unknown;
28
+ }
29
+ /** Register the create_diagram tool on a host context. */
30
+ export declare function registerDiagramTool(ctx: Context): void;
31
+ /**
32
+ * Validate untrusted create_diagram arguments into a DiagramSpec. Returns
33
+ * undefined for anything structurally unusable (no nodes, duplicate ids,
34
+ * edges pointing at unknown nodes, over the caps) — the tool then fails with
35
+ * an actionable message and the model can retry with a corrected diagram.
36
+ */
37
+ export declare function diagramSpecFromArgs(args: CreateDiagramArgs): {
38
+ title?: string;
39
+ direction?: DiagramDirection;
40
+ nodes: DiagramNodeSpec[];
41
+ edges: DiagramEdgeSpec[];
42
+ } | undefined;
@@ -1,5 +1,6 @@
1
1
  /** OpenAI Images API and compatible response adapter. */
2
2
  import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
3
+ import { type ArkOutputOptions } from './shared.js';
3
4
  export interface GeneratedCompatibleImage {
4
5
  data: Uint8Array;
5
6
  mediaType: ImageMediaType;
@@ -17,6 +18,8 @@ export declare function generateOpenAICompatibleImage(input: {
17
18
  size: string;
18
19
  maxBytes: number;
19
20
  signal: AbortSignal;
21
+ /** Ark-only output controls; ignored by every other provider. */
22
+ arkOptions?: ArkOutputOptions;
20
23
  }): Promise<GeneratedCompatibleImage>;
21
24
  /** How the edits endpoint expects its request body (#41). */
22
25
  export type CompatEditFormat = 'multipart' | 'jsonImageUrlArray';
@@ -1,6 +1,7 @@
1
1
  /** Volcengine Ark Seedream image-editing adapter. */
2
2
  import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
3
3
  import type { GeneratedCompatibleImage } from './openai-compatible.js';
4
+ import { type ArkOutputOptions } from './shared.js';
4
5
  /** Edit one image through Ark ImageGenerations using a data-URL reference. */
5
6
  export declare function editSeedreamImage(input: {
6
7
  apiKey: string;
@@ -14,4 +15,10 @@ export declare function editSeedreamImage(input: {
14
15
  size?: string;
15
16
  maxBytes: number;
16
17
  signal: AbortSignal;
18
+ /**
19
+ * Ark output controls. The edit path is the only one Ark lets request a
20
+ * transparent background, and it requires every reference image to carry an
21
+ * alpha channel — see `arkOutputBody`.
22
+ */
23
+ arkOptions?: ArkOutputOptions;
17
24
  }): Promise<GeneratedCompatibleImage>;
@@ -117,6 +117,18 @@ export declare function isSubscriptionProvider(provider: ImageProvider): provide
117
117
  /** Providers supported by the first browser workbench release. */
118
118
  export declare const CLOUD_IMAGE_PROVIDERS: readonly ["google", "openai", "openai-compat", "seedream", "dashscope", "xai", "zhipu"];
119
119
  export type CloudImageProvider = typeof CLOUD_IMAGE_PROVIDERS[number];
120
+ /**
121
+ * Providers the browser workbench can drive: the BYOK cloud set plus the
122
+ * logged-in subscription channels. ComfyUI stays out; it has its own workflow
123
+ * pipeline and no shared request shape.
124
+ */
125
+ export declare const STUDIO_PROVIDERS: readonly ["google", "openai", "openai-compat", "seedream", "dashscope", "xai", "zhipu", "chatgpt-sub", "grok-sub", "google-sub"];
126
+ export type StudioProvider = CloudImageProvider | SubscriptionProvider;
127
+ /** True when the provider is selectable in the browser workbench. */
128
+ export declare function isStudioProvider(provider: ImageProvider): provider is StudioProvider;
129
+ /** Timeout for one subscription image call, shared by the tool path and the
130
+ * studio route so neither drifts from the other. */
131
+ export declare const SUBSCRIPTION_TIMEOUT_MS = 300000;
120
132
  /**
121
133
  * Credential references resolved through the DSH Credentials service (BYOK).
122
134
  * These are POSIX-style reference names, not environment variables: the host
@@ -155,7 +167,7 @@ export interface StudioOption {
155
167
  }
156
168
  /** Browser-safe provider description. Credentials and endpoints never cross this boundary. */
157
169
  export interface StudioProviderProfile {
158
- provider: CloudImageProvider;
170
+ provider: StudioProvider;
159
171
  label: string;
160
172
  model: string;
161
173
  configured: boolean;
@@ -175,7 +187,7 @@ export interface StudioWorkspaceInfo {
175
187
  /** Read model and capability state for the workbench without exposing secrets. */
176
188
  export interface StudioConfigResponse {
177
189
  providers: StudioProviderProfile[];
178
- activeProvider: CloudImageProvider;
190
+ activeProvider: StudioProvider;
179
191
  workspaceRoot?: string | undefined;
180
192
  workspaces?: StudioWorkspaceInfo[] | undefined;
181
193
  }
@@ -193,7 +205,7 @@ export type StudioReference = StudioEncodedReference | StudioAttachmentReference
193
205
  /** One browser workbench generation or editing request. */
194
206
  export interface StudioGenerateRequest {
195
207
  mode: 'generate' | 'edit';
196
- provider: CloudImageProvider;
208
+ provider: StudioProvider;
197
209
  model: string;
198
210
  prompt: string;
199
211
  ratio: string;
@@ -211,7 +223,7 @@ export interface StudioGeneratedItem {
211
223
  }
212
224
  /** One completed workbench request. */
213
225
  export interface StudioGenerateResponse extends StudioGeneratedItem {
214
- provider: CloudImageProvider;
226
+ provider: StudioProvider;
215
227
  model: string;
216
228
  prompt: string;
217
229
  createdAt: number;
@@ -235,6 +247,45 @@ export declare const DEFAULT_COMFYUI_BASE_URL = "http://127.0.0.1:8188";
235
247
  export declare const DEFAULT_COMFYUI_TIMEOUT_MS = 300000;
236
248
  export declare const DEFAULT_COMFYUI_WORKFLOW_LABEL = "API workflow";
237
249
  export declare const MAX_COMFYUI_WORKFLOW_BYTES: number;
250
+ /** Content types Ark's Seedream endpoint can return. */
251
+ export declare const ARK_OUTPUT_FORMATS: readonly ["png", "jpeg"];
252
+ /** Whether Ark stamps an "AI generated" watermark on the result. */
253
+ export declare const ARK_BACKGROUND_MODES: readonly ["opaque", "transparent"];
254
+ export type ArkOutputFormat = typeof ARK_OUTPUT_FORMATS[number];
255
+ export type ArkBackgroundMode = typeof ARK_BACKGROUND_MODES[number];
256
+ /**
257
+ * Ark (Seedream) output controls, shared by the generate and edit paths.
258
+ *
259
+ * Every field mirrors an Ark request-body field of the same meaning, and every
260
+ * default below reproduces Ark's own default — so an untouched configuration
261
+ * sends exactly what it sent before these options existed.
262
+ */
263
+ export interface ArkOutputOptions {
264
+ /** `output_format`. Ark defaults to `jpeg`; `png` is lossless and keeps an alpha channel. */
265
+ outputFormat?: ArkOutputFormat;
266
+ /** `watermark`. Ark defaults to `true`, which bakes an "AI generated" mark into the image. */
267
+ watermark?: boolean;
268
+ /** `background`. Ark defaults to `opaque`. */
269
+ background?: ArkBackgroundMode;
270
+ }
271
+ /**
272
+ * Map the Ark output controls onto request-body fields.
273
+ *
274
+ * `background` is opt-in per call site because Ark restricts `transparent` to
275
+ * image-to-image with a single alpha-bearing reference and rejects the whole
276
+ * request otherwise:
277
+ *
278
+ * text-to-image + transparent → 400 InvalidParameter
279
+ * "transparent background requires exactly one input image"
280
+ *
281
+ * So the generation endpoint must never carry it, and that caller passes
282
+ * `{ background: false }`. `background: opaque` is never emitted anywhere: it
283
+ * is already Ark's default, so sending it would change nothing while adding a
284
+ * field only the edit path can act on.
285
+ */
286
+ export declare function arkOutputBody(options: ArkOutputOptions | undefined, { background }?: {
287
+ background?: boolean;
288
+ }): Record<string, unknown>;
238
289
  /** Default model names. */
239
290
  export declare const DEFAULT_GOOGLE_MODEL = "gemini-3.1-flash-image";
240
291
  export declare const DEFAULT_OPENAI_MODEL = "gpt-image-2";
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Dedicated DSH agent session backing the workbench chat panel.
3
+ *
4
+ * The panel is a real DSH conversation driven from the plugin, not a parallel
5
+ * chat implementation: on first use the host creates an agent through
6
+ * ctx.agents.create (the same factory the sidebar uses), then archives the
7
+ * session through ctx.workspaceRegistry so it never appears in the sidebar
8
+ * history list while remaining fully usable. The plugin never calls
9
+ * sessions.open - archiving the selected session would clear the user's
10
+ * current selection - and drives turns purely through agent.followup().
11
+ *
12
+ * Session events are projected into a small lossless-enough StudioChatEvent
13
+ * feed (text turns, tool summaries, generated-image references) and served to
14
+ * the browser through CHAT_ROUTE. The browser pulls increments with
15
+ * ?since=<seq>; images land on the tldraw canvas from the browser side via
16
+ * the existing IMAGE_ROUTE + landing-queue path.
17
+ */
18
+ import type { IncomingMessage, ServerResponse } from 'node:http';
19
+ import type { Context } from '@deepseek-ai/cordis';
20
+ import { type StudioChatEvent } from './shared.js';
21
+ /** Wire responses for CHAT_ROUTE. */
22
+ export interface StudioChatStateResponse {
23
+ ok: true;
24
+ latestSeq: number;
25
+ events: StudioChatEvent[];
26
+ /** Why the backing agent is missing, when creation failed; absent otherwise. */
27
+ unavailable?: string;
28
+ }
29
+ export interface StudioChatSendResponse {
30
+ ok: true;
31
+ }
32
+ export interface StudioChatErrorResponse {
33
+ error: string;
34
+ }
35
+ export interface StudioChatDeps {
36
+ maxBodyBytes: number;
37
+ }
38
+ /**
39
+ * Install the studio chat: ensure the dedicated agent session, subscribe to
40
+ * its events, and return the CHAT_ROUTE handler plus a disposer. Creation
41
+ * failures never break the plugin load - the route reports the error and the
42
+ * panel shows it, so a host without agent services degrades visibly instead
43
+ * of fatally.
44
+ */
45
+ export declare function createStudioChat(ctx: Context, deps: StudioChatDeps): {
46
+ serve: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
47
+ dispose(): void;
48
+ };
@@ -1,9 +1,10 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import { type Config } from './config.js';
3
+ import { type SubscriptionManager } from './subscription.js';
3
4
  import { type CloudImageProvider, type StudioConfigResponse, type StudioGenerateRequest, type StudioGenerateResponse, type StudioProviderProfile } from './shared.js';
4
5
  /** Return only browser-safe capability data. */
5
- export declare function describeStudio(ctx: Context, config: Config): Promise<StudioConfigResponse>;
6
+ export declare function describeStudio(ctx: Context, config: Config, subscriptions?: SubscriptionManager | undefined): Promise<StudioConfigResponse>;
6
7
  /** Execute one validated browser workbench request using the existing provider adapters. */
7
- export declare function generateFromStudio(ctx: Context, config: Config, input: StudioGenerateRequest, signal: AbortSignal, fallbackWorkspaceRoot?: string | undefined): Promise<StudioGenerateResponse>;
8
+ export declare function generateFromStudio(ctx: Context, config: Config, input: StudioGenerateRequest, signal: AbortSignal, fallbackWorkspaceRoot?: string | undefined, subscriptions?: SubscriptionManager | undefined): Promise<StudioGenerateResponse>;
8
9
  export declare function runPool<T>(tasks: Array<() => Promise<T>>, concurrency?: number): Promise<PromiseSettledResult<T>[]>;
9
10
  export declare function studioProfile(config: Config, provider: CloudImageProvider, configured: boolean): StudioProviderProfile;
@@ -21,12 +21,26 @@ import { type SubscriptionBlob } from './blob.js';
21
21
  import { type SubscriptionProvider } from '../shared.js';
22
22
  /** Vendor ids used by the credential refs and the wire calls. */
23
23
  export type SubscriptionVendor = 'codex' | 'grok' | 'antigravity';
24
+ /**
25
+ * Reference image passed to edit calls. Structural so callers can pass their
26
+ * own resolved types without importing from the plugin root.
27
+ */
28
+ export interface SubscriptionReferenceImage {
29
+ data: Uint8Array;
30
+ mediaType: string;
31
+ }
24
32
  /** The vendor each dsh-image-gen subscription provider maps onto. */
25
33
  export declare function vendorOf(provider: SubscriptionProvider): SubscriptionVendor;
26
34
  /** Credential ref one vendor's OAuth blob is stored under (index fixed at 1). */
27
35
  export declare function subscriptionOauthRef(vendor: SubscriptionVendor): CredentialRef;
28
36
  /** Sizes both vendors understand. */
29
37
  export declare const SUBSCRIPTION_SIZES: readonly ["1024x1024", "1024x1536", "1536x1024", "auto"];
38
+ /**
39
+ * Reference images per edit call. Every subscription channel accepts at
40
+ * least this many (Codex edits up to 16, Grok up to 5, Antigravity up to 10),
41
+ * so 5 keeps one shared guard in line with the Studio UI's upload cap.
42
+ */
43
+ export declare const SUBSCRIPTION_MAX_REFERENCE_IMAGES = 5;
30
44
  /** Login status the settings card renders as a badge. */
31
45
  export type SubscriptionLoginStatus = {
32
46
  state: 'logged-in';
@@ -80,6 +94,7 @@ export declare class SubscriptionManager {
80
94
  prompt: string;
81
95
  size?: string;
82
96
  quality?: string;
97
+ referenceImages?: ReadonlyArray<SubscriptionReferenceImage>;
83
98
  signal?: AbortSignal;
84
99
  }): Promise<Array<{
85
100
  b64_json: string;
@@ -37,12 +37,17 @@ export declare function antigravityResolveProject(blob: SubscriptionBlob): Promi
37
37
  * Build the streamGenerateContent request body for one image generation.
38
38
  * Ported from the reference buildImageRequest + the wrapping envelope: no
39
39
  * tools, no systemInstruction, no thinkingConfig; responseModalities asks
40
- * for TEXT+IMAGE.
40
+ * for TEXT+IMAGE. Reference images (edits) ride along as inlineData parts
41
+ * before the text part, mirroring the reference implementation.
41
42
  */
42
43
  export declare function antigravityImageBody(options: {
43
44
  prompt: string;
44
45
  aspectRatio?: string;
45
46
  hd?: boolean;
47
+ referenceImages?: ReadonlyArray<{
48
+ data: Uint8Array;
49
+ mediaType: string;
50
+ }>;
46
51
  }): Record<string, unknown>;
47
52
  /** Wrap the inner request in the Antigravity agent envelope. */
48
53
  export declare function antigravityEnvelope(projectId: string, request: Record<string, unknown>): Record<string, unknown>;
@@ -62,5 +67,9 @@ export declare function antigravityGenerateImage(options: {
62
67
  prompt: string;
63
68
  aspectRatio?: string;
64
69
  hd?: boolean;
70
+ referenceImages?: ReadonlyArray<{
71
+ data: Uint8Array;
72
+ mediaType: string;
73
+ }>;
65
74
  signal?: AbortSignal;
66
75
  }): Promise<AntigravityImageResult>;
@@ -12,6 +12,8 @@ export declare const CODEX_AUTH = "https://auth.openai.com/oauth/authorize";
12
12
  export declare const CODEX_TOKEN = "https://auth.openai.com/oauth/token";
13
13
  /** Where the ChatGPT subscription image request goes. */
14
14
  export declare const CODEX_IMAGE_URL = "https://chatgpt.com/backend-api/codex/images/generations";
15
+ /** Where the ChatGPT subscription image edit request goes. */
16
+ export declare const CODEX_IMAGE_EDIT_URL = "https://chatgpt.com/backend-api/codex/images/edits";
15
17
  /** The model served by this endpoint (probed live: gpt-image-2.5-flare works
16
18
  * on the ChatGPT internal generations route as of 2026-09-14). */
17
19
  export declare const CODEX_IMAGE_MODEL = "gpt-image-2.5-flare";