docs/developer/prompt-garden-integration.md
本文档描述当前代码中已经落地的 Prompt Garden 外部导入行为,目标是让 Garden 侧和 Prompt Optimizer 侧按同一套实际契约对接。
设计目标:
VITE_PROMPT_GARDEN_BASE_URL 拉取内容,不接受 URL 参数覆盖Prompt Optimizer 在应用初始 session 恢复完成后检查当前路由 query。
importCode,则触发一次导入importCode(必填)
NB-001NB-001@ex-2GET /api/prompt-source/NB-001,并把 ex-2 当作本次导入的示例选择subModeKey(可选)
optimizerTarget.subModeKeybasic-systemexampleId(可选)
importCode 同时带 @exampleId 后缀,显式 URL 参数 exampleId 优先assets.examples[0]saveToFavorites(可选)
1 / true / auto -> 自动保存到收藏confirm / dialog / manual -> 打开“保存收藏”对话框,并带预填数据saveToFavorites,本次导入只处理收藏,不写入或覆盖当前工作区subModeKey 支持值basic-systembasic-userpro-multipro-variableimage-text2imageimage-image2image导入到 basic-system:
https://prompt.example.com/#/basic/system?importCode=NB-001导入到 pro-multi,并显式指定示例:
https://prompt.example.com/#/pro/multi?importCode=NB-001&exampleId=ex-2导入到 pro-multi,并通过导入码后缀指定示例:
https://prompt.example.com/#/pro/multi?importCode=NB-001@ex-2从 image-image2image 类型的 Garden 提示词导入为收藏,并弹出保存收藏对话框:
https://prompt.example.com/#/image/image2image?importCode=NB-001&saveToFavorites=confirm若希望 query 明确覆盖目标工作区:
https://prompt.example.com/#/basic/system?importCode=NB-001&subModeKey=basic-system说明:
subModeKeysaveToFavorites 时,subModeKey 用于决定写入哪个工作区saveToFavorites 时,subModeKey 只用于收藏的模式预填充,不会触发工作区写入Prompt Optimizer 会调用:
GET {gardenBaseUrl}/api/prompt-source/{encodeURIComponent(importCode)}
其中:
gardenBaseUrl 固定来自 Prompt Optimizer 的环境变量 VITE_PROMPT_GARDEN_BASE_URLAccept: application/jsonfetchcredentials如果 Garden API 需要登录态、Cookie 或额外鉴权,当前 Web/Extension 导入链路通常需要额外的同源部署或服务端代理支持。
当前实现只接受 v1 schema:
schema 必须为 prompt-garden.prompt.v1schemaVersion 必须为 1不兼容旧版 { content, title } 回退协议。
{
"schema": "prompt-garden.prompt.v1",
"schemaVersion": 1,
"importCode": "NB-001",
"optimizerTarget": {
"subModeKey": "pro-variable"
},
"prompt": {
"format": "text",
"text": "Write a launch post for {{product_name}} aimed at {{audience}}."
},
"variables": [
{
"name": "product_name",
"defaultValue": "Prompt Optimizer",
"description": "产品名称",
"type": "string",
"required": true
},
{
"name": "audience",
"defaultValue": "indie hackers",
"type": "enum",
"options": ["indie hackers", "founders", "designers"]
}
],
"assets": {
"cover": {
"url": "/prompt-assets/nb-001/cover.png"
},
"showcases": [
{
"id": "showcase-1",
"images": ["/prompt-assets/nb-001/showcase-1.png"],
"description": "封面图"
}
],
"examples": [
{
"id": "ex-1",
"parameters": {
"product_name": "Prompt Optimizer",
"audience": "founders"
}
}
]
},
"meta": {
"title": "Launch Post Writer",
"description": "用于生成发布帖的变量化提示词",
"tags": ["marketing", "launch"],
"categoryKey": "marketing"
}
}
schema:必填,固定为 prompt-garden.prompt.v1schemaVersion:必填,固定为 1optimizerTarget:必填
optimizerTarget.subModeKey:必填,且应始终返回合法值(见 1.2)prompt:必填variables:必填,允许为空数组 []importCode:可选但推荐返回
importCodeassets:可选
meta:可选
prompt 字段与子模式支持矩阵prompt 定义prompt 为对象:
{
"format": "text",
"text": "..."
}
或:
{
"format": "messages",
"messages": [
{
"id": "msg-1",
"role": "system",
"content": "..."
}
]
}
字段约束:
prompt.format:必填,可选值为 text / messagesformat=text 时,prompt.text 必须是非空字符串format=messages 时,prompt.messages 必须是非空数组虽然 schema 允许 text 和 messages 两种格式,但当前代码不是所有子模式都同等支持:
pro-multi
messagestext,会被包装成一条 system 消息basic-system
textbasic-user
textpro-variable
textimage-text2image
textimage-image2image
text强烈建议:
pro-multi 时才返回 format=messagesformat=text如果向非 pro-multi 子模式返回 messages,当前实现会在写入工作区时报错。
prompt.messages 项定义prompt.messages 每项为:
{
"id": "optional-but-recommended",
"role": "system",
"content": "...",
"originalContent": "optional"
}
字段约束:
role:必填,可选值为 system / user / assistant / toolcontent:必填,非空字符串id:建议提供,便于导入后稳定选中消息originalContent:可选;若未提供,会回退为 contentvariables 字段variables 为数组,每项为:
{
"name": "variable_name",
"defaultValue": "optional",
"description": "optional",
"type": "string",
"required": true,
"options": ["a", "b"],
"source": "optional"
}
字段约束:
name:必填,必须符合 Prompt Optimizer 的变量命名规则
[a-zA-Z_][a-zA-Z0-9_]*defaultValue:可选,字符串description:可选,字符串type:可选,支持 string / number / boolean / enumrequired:可选,布尔值options:可选,字符串数组source:可选,字符串当前实现行为:
variables 在 API 中是必填字段,即使没有变量也要返回 []pro-multipro-variableimage-text2imageimage-image2imagebasic-system 和 basic-user 不会接收 temporary variables当前实现会先把 temporary variables 重置为 Garden 返回的变量列表,但对“同名变量”的值使用保留策略:
defaultValue[],则会清空该子模式当前的 temporary variablesassets 与 meta 扩展字段assets 和 meta 不是工作区 prompt 写入的必需字段,但当前实现已经支持它们,并会在“保存到收藏”场景中使用。
assets 结构{
"assets": {
"cover": {
"url": "/prompt-assets/nb-001/cover.png"
},
"showcases": [
{
"id": "showcase-1",
"url": "/prompt-assets/nb-001/showcase-1.png",
"images": ["/prompt-assets/nb-001/showcase-1.png"],
"description": "optional"
}
],
"examples": [
{
"id": "ex-1",
"parameters": {
"var_name": "value"
},
"inputImages": ["/prompt-assets/nb-001/input-1.png"],
"description": "optional"
}
]
}
}
当前实现支持的含义:
assets.cover
assets.showcases
assets.examples
image-image2image,还可用于示例输入图回填素材 URL 可以是绝对地址,也可以是相对地址。
gardenBaseUrl 归一化为绝对 URLmeta 结构meta 中当前有实际用途的字段包括:
title
description
tags
categoryKey
categorycategory
categoryKey 的回退如果 meta.title 缺失,Prompt Optimizer 会退回到 prompt 内容首行生成收藏标题。
exampleId 行为导入时,Prompt Optimizer 会从 assets.examples 中选择一个示例:
exampleId,优先按 id 精确匹配当选中的示例包含 parameters 时:
variables 中声明过”的变量赋值image-image2image 的输入图行为当前实现和旧文档不同:
image-image2imageinputImagesinputImages[0],并加载为当前工作区的输入图如果图片读取失败:
因此,若要支持 image2image 的“可复现实例导入”,Garden 不仅要开放 /api/prompt-source/*,也要开放示例图片地址。
saveToFavorites)当 saveToFavorites=1|true|auto 时:
meta 和 assets 会作为 gardenSnapshot 一起写入收藏 metadata当 saveToFavorites=confirm|dialog|manual 时:
gardenSnapshotGarden 联动保存收藏时,不按收藏内容去重,而按下面的组合键做 upsert:
gardenSnapshot.importCodegardenSnapshot.gardenBaseUrl这意味着:
importCode 相同,也会被视为不同来源当 URL 不带 saveToFavorites 时,导入成功后 Prompt Optimizer 不只是更新 prompt,还会清理与旧工作区状态绑定的内容。
例如:
basic-system / basic-user
pro-multi
pro-variable
image-text2image
image-image2image
Prompt Optimizer 仅支持 Mustache 风格变量占位符:
{{variable_name}}{{ variable_name }}不支持:
{variable_name}约束:
prompt.text 和 prompt.messages[].content 中出现的变量占位符都必须使用 {{...}}{var} 风格占位符建议 Garden 使用以下语义:
400:importCode 非法404:importCode 不存在500:服务端错误对 Prompt Optimizer 而言:
以下情况会直接失败:
VITE_PROMPT_GARDEN_BASE_URLschema 不是 prompt-garden.prompt.v1schemaVersion 不是 1optimizerTarget.subModeKeyprompt.formatformat=text 但 prompt.text 为空format=messages 但 prompt.messages 为空variables由于 Prompt Optimizer(Web/Extension)是纯前端应用,Garden 侧必须正确配置跨域。
至少需要覆盖两类资源:
/api/prompt-source/*assets.cover.url、assets.showcases[*].url/images[*]、assets.examples[*].images[*]、assets.examples[*].inputImages[*] 指向的静态资源地址建议:
/api/prompt-source/* 返回:
Access-Control-Allow-Origin: https://prompt.example.com,或你的实际部署域名Access-Control-Allow-Origin* 联调如果 image2image 示例输入图需要可用,inputImages 的 URL 也必须允许被浏览器跨域 fetch。
Prompt Optimizer 侧:
VITE_ENABLE_PROMPT_GARDEN_IMPORT=1 或 true
1VITE_PROMPT_GARDEN_BASE_URL=https://garden.always200.com
说明:
window.runtime_config 推荐使用无前缀键:ENABLE_PROMPT_GARDEN_IMPORT、PROMPT_GARDEN_BASE_URLVITE_ENABLE_PROMPT_GARDEN_IMPORT、VITE_PROMPT_GARDEN_BASE_URLPrompt Optimizer 使用“可选集成”机制来实现低入侵扩展:
packages/ui/src/integrations/*.integration.tsintegration 对象,并通过 envFlag 控制是否启用registerOptionalIntegrations(...)Prompt Garden 相关文件:
packages/ui/src/integrations/prompt-garden.integration.tspackages/ui/src/integrations/prompt-garden.favorite-preview.tsPrompt Optimizer 侧核心实现:
packages/ui/src/composables/app/useAppPromptGardenImport.tspackages/ui/src/components/PromptGardenFavoritePreviewPanel.vuepackages/ui/src/utils/garden-snapshot-preview.ts主要测试:
packages/ui/tests/unit/composables/useAppPromptGardenImport.spec.tspackages/ui/tests/unit/components/GardenSnapshotPreview.spec.tspackages/ui/tests/unit/utils/garden-snapshot-preview.spec.ts