import { IMAGE_GENERATION_MODE, resolveImageGenerationDecision, } from '../chat-intent-router.mjs'; export const WECHAT_PAGE_THUMBNAIL_MODE = { AUTO: 'auto', REQUIRED_FRESH: 'required_fresh', }; const INLINE_IMAGE_REQUIRED_PATTERNS = [ /(?:正文|内容|段落|章节).{0,12}(?:配图|插图|图片)/u, /(?:每段|每章|文中|文章中).{0,12}(?:配图|插图|图片)/u, /(?:多张|若干张|几张).{0,12}(?:配图|插图|图片)/u, ]; export function resolveWechatImageGenerationPolicy({ text, isPageGenerate = false, requireFreshPageThumbnail = false, } = {}) { const normalizedText = String(text ?? '').trim(); const requested = resolveImageGenerationDecision({ text: normalizedText }); const pageThumbnailMode = isPageGenerate && requireFreshPageThumbnail ? WECHAT_PAGE_THUMBNAIL_MODE.REQUIRED_FRESH : WECHAT_PAGE_THUMBNAIL_MODE.AUTO; const inlineImageMode = requested.mode === IMAGE_GENERATION_MODE.DISABLED ? IMAGE_GENERATION_MODE.DISABLED : INLINE_IMAGE_REQUIRED_PATTERNS.some((pattern) => pattern.test(normalizedText)) ? IMAGE_GENERATION_MODE.REQUIRED : IMAGE_GENERATION_MODE.AUTO; const standaloneImageMode = isPageGenerate ? IMAGE_GENERATION_MODE.AUTO : requested.mode; return { channel: 'wechat_mp', imageGenerationMode: pageThumbnailMode === WECHAT_PAGE_THUMBNAIL_MODE.REQUIRED_FRESH ? IMAGE_GENERATION_MODE.REQUIRED : standaloneImageMode, pageThumbnailMode, inlineImageMode, standaloneImageMode, requested, }; } export function buildWechatImageRunMetadata(policy) { if (!policy) return { channel: 'wechat_mp' }; return { channel: 'wechat_mp', imageGenerationMode: policy.imageGenerationMode, pageThumbnailMode: policy.pageThumbnailMode, inlineImageMode: policy.inlineImageMode, }; } export function buildWechatStandaloneImageInstruction(policy, { sourceMessageId = '' } = {}) { if (!policy || policy.standaloneImageMode === IMAGE_GENERATION_MODE.AUTO) return ''; if (policy.standaloneImageMode === IMAGE_GENERATION_MODE.DISABLED) { return '【图片策略】用户明确不要生成图片。本轮禁止调用 generate_image,只返回文字。'; } const idempotencyKey = sourceMessageId ? `wechat-${String(sourceMessageId).replace(/[^a-zA-Z0-9._-]+/g, '-').slice(0, 80)}-image` : ''; return [ '【微信服务号生图任务】用户明确要求生成一张新图片。', '必须先调用 `load_skill` → `image-generation`,再调用一次 `sandbox-fs__generate_image`,purpose=`inline_image`。', '必须使用本轮新返回的 PNG/JPEG/WebP 资产;禁止复用历史图片、SVG、CSS 绘图、占位图或网页图片。', idempotencyKey ? `调用 generate_image 时传入 idempotency_key=${idempotencyKey}。` : '', '成功后简短说明结果,不要输出内部工具步骤;失败时如实报告,禁止声称已经生成。', ].filter(Boolean).join('\n'); } export function buildWechatPageImageInstruction(policy, { sourceMessageId = '' } = {}) { if (policy?.pageThumbnailMode !== WECHAT_PAGE_THUMBNAIL_MODE.REQUIRED_FRESH) return ''; const keyPrefix = sourceMessageId ? `wechat-${String(sourceMessageId).replace(/[^a-zA-Z0-9._-]+/g, '-').slice(0, 72)}-page` : 'wechat-page'; const inlineInstruction = policy.inlineImageMode === IMAGE_GENERATION_MODE.DISABLED ? '用户明确不要正文图片:页面正文和 Hero 不展示图片,但缩略图源图仍必须生成并只写入 mindspace-cover.cover。' : policy.inlineImageMode === IMAGE_GENERATION_MODE.REQUIRED ? '用户明确要求正文配图:缩略图源图之外,只有正文确实需要不同画面时才可按需调用 inline_image。' : '正文独立插图按意图判断;没有明确必要时不要额外调用 inline_image。'; return [ '【服务号页面新缩略图硬要求】每个本轮交付给用户的正式内容页面都必须使用本轮新生成、与主题一致的位图作为缩略图源图。', '写 HTML 前先调用 `load_skill` → `image-generation`,再为每个正式内容页面各调用一次 `sandbox-fs__generate_image`,优先 purpose=`hero`。', `幂等键使用 ${keyPrefix}-<页面序号>-thumbnail;不同正式页面不得共用同一张图。`, '同一正式页面在 Agent 层只调用一次 generate_image;工具内部会完成语义重试。返回失败后禁止自行更换提示词并重复调用,交由服务号交付层统一重试。', '生成成功后,把返回的 asset.htmlSrc 原样写入对应页面的 mindspace-cover.cover。页面需要主视觉时复用同一张图作为 Hero,禁止再调用 card_cover/feed_cover。', '管理后台、密码查看、重定向、下载包装和错误辅助页不属于正式内容页面,不要求单独生图;这类页面必须在 head 写 `` 供交付守卫识别。', inlineInstruction, '当前轮没有新的成功 generate_image、没有新 jobId,或正式页面未引用本轮资产时,禁止交付页面链接或声称完成。', ].join('\n'); }