feat: render image in markdown
This commit is contained in:
@@ -24,15 +24,21 @@ import { buildSourceSignatures, type NodeLike, type EdgeLike } from '@/lib/graph
|
||||
import { getNodeDisplayStatus, type NodeDisplayStatus } from '@/lib/graph/state'
|
||||
import type { ConfigTypeId, SourceRenderingLogicContext } from '@/lib/graph/rendering'
|
||||
|
||||
export type OutputMode = 'image' | 'string'
|
||||
|
||||
export type RenderingNodeData = {
|
||||
viewportWidth?: number
|
||||
viewportHeight?: number
|
||||
updateMode?: 'auto' | 'manual'
|
||||
runTrigger?: number
|
||||
lastRunSourceSignature?: string
|
||||
/** Controls which view is shown and what the node emits to downstream (Image = markdown embed, String = resolved text). */
|
||||
outputMode?: OutputMode
|
||||
cachedRenderedContent?: string
|
||||
cachedResolvedContent?: string
|
||||
cachedReasoningContent?: string
|
||||
/** Value exposed to config/agent when they reference this node (e.g. {{ renderId }}). Set on pipeline completion. */
|
||||
cachedOutputValue?: string
|
||||
}
|
||||
|
||||
const DEFAULT_VIEWPORT_WIDTH = 1200
|
||||
@@ -96,6 +102,10 @@ export type RenderingNodeState = {
|
||||
|
||||
/** Source node type id (e.g. 'config', 'agent') for Output menu from descriptor. */
|
||||
sourceNodeType: string | null
|
||||
|
||||
/** Output mode (Image vs String); controls view and emitted cachedOutputValue. */
|
||||
outputMode: OutputMode
|
||||
setOutputMode: (mode: OutputMode) => void
|
||||
}
|
||||
|
||||
export function useRenderingNodeState(
|
||||
@@ -140,6 +150,11 @@ export function useRenderingNodeState(
|
||||
)
|
||||
const effectiveUpdateMode = (data?.updateMode ?? sourceLogic?.defaultUpdateMode ?? 'auto') as 'auto' | 'manual'
|
||||
const runTrigger = data?.runTrigger ?? 0
|
||||
const outputMode: OutputMode = (data?.outputMode ?? 'image') as OutputMode
|
||||
const setOutputMode = useCallback(
|
||||
(mode: OutputMode) => updateData({ outputMode: mode }),
|
||||
[updateData]
|
||||
)
|
||||
const isAgentSource = srcNode?.type === 'agent'
|
||||
const agentOutputMarkdown = isAgentSource
|
||||
? ((srcNode?.data as { outputMarkdown?: string })?.outputMarkdown ?? '')
|
||||
@@ -201,6 +216,8 @@ export function useRenderingNodeState(
|
||||
|
||||
const updateDataRef = useRef(updateData)
|
||||
updateDataRef.current = updateData
|
||||
const outputModeRef = useRef(outputMode)
|
||||
outputModeRef.current = outputMode
|
||||
const setNodesRef = useRef(setNodes)
|
||||
setNodesRef.current = setNodes
|
||||
const aiConnectionRef = useRef(aiConnection)
|
||||
@@ -294,6 +311,7 @@ export function useRenderingNodeState(
|
||||
cachedRenderedContent: undefined,
|
||||
cachedResolvedContent: undefined,
|
||||
cachedReasoningContent: undefined,
|
||||
cachedOutputValue: undefined,
|
||||
})
|
||||
try {
|
||||
// Pipeline: 1) Resolve (source) → 2) Render (output type) → 3) Cache
|
||||
@@ -324,10 +342,18 @@ export function useRenderingNodeState(
|
||||
if (thisRunId !== runIdRef.current) return
|
||||
setRenderedContent(htmlOrSvg)
|
||||
setError(null)
|
||||
const mode = outputModeRef.current
|
||||
const cachedOutputValue =
|
||||
mode === 'string'
|
||||
? resolved
|
||||
: mode === 'image' && htmlOrSvg?.trim() && /<svg[\s>]/i.test(htmlOrSvg.trim())
|
||||
? `data:image/svg+xml;charset=utf-8,${encodeURIComponent(htmlOrSvg)}`
|
||||
: ''
|
||||
updateDataRef.current({
|
||||
cachedRenderedContent: htmlOrSvg,
|
||||
cachedResolvedContent: resolved,
|
||||
cachedReasoningContent: reasoning ?? '',
|
||||
cachedOutputValue,
|
||||
...(isManualMode ? { lastRunSourceSignature: signatureForThisRun } : {}),
|
||||
})
|
||||
} catch (err: unknown) {
|
||||
@@ -546,5 +572,7 @@ export function useRenderingNodeState(
|
||||
emptyStateAction,
|
||||
sourceData,
|
||||
sourceNodeType,
|
||||
outputMode,
|
||||
setOutputMode,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user