experience-search-coordinate

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Search Coordinator

搜索协调器

Routes search requests to the correct sub-workflow — structured CMS content or media — and runs both when a request mixes the two.
A
→ Read
pointer below is a required action, not FYI
— open that file before continuing past that point; this skill has drifted before from steps followed off memory.
将搜索请求路由到正确的子工作流——结构化CMS内容或媒体——当请求混合两种类型时,会同时运行两者。
下方的
→ Read
标记是必填操作,而非仅供参考
——在继续之前请打开该文件;此前曾出现过凭记忆执行步骤导致Skill偏离要求的情况。

Scope

适用范围

This skill is for SEARCHING FOR existing content or media, not creating new content or images.
Use this skill when the user wants to:
  • Search for articles, blog posts, news, FAQs, events, products, or custom content
  • Search for images, logos, icons, photos, graphics, banners, hero images, audio clips, videos, or documents
  • Reuse existing assets instead of creating new ones, or any combination of the above in one request
DO NOT use this skill when the user wants to:
  • Generate new content (use
    experience-cms-content-generate
    )
  • Generate new images (use image generation tools)
  • Define content type schemas (use
    experience-cms-content-type-generate
    )
  • Apply brand guidelines (use
    experience-cms-brand-apply
    )
  • Create, edit, or publish content records
此Skill仅用于搜索现有内容或媒体,不用于创建新内容或图片。
当用户需要以下操作时使用此Skill:
  • 搜索文章、博客文章、新闻、常见问题、活动、产品或自定义内容
  • 搜索图片、标志、图标、照片、图形、横幅、首屏图、音频片段、视频或文档
  • 复用现有资产而非创建新资产,或在一个请求中组合上述任意操作
当用户需要以下操作时请勿使用此Skill:
  • 生成新内容(使用
    experience-cms-content-generate
  • 生成新图片(使用图片生成工具)
  • 定义内容类型架构(使用
    experience-cms-content-type-generate
  • 应用品牌规范(使用
    experience-cms-brand-apply
  • 创建、编辑或发布内容记录

Step 1: Determine Channel Scope

步骤1:确定渠道范围

Mandatory on every request that reaches it — never skip straight to Step 2. No phrasing of the request ("just find me an article," a plain keyword search, etc.) skips this step's local-file scan. If you're about to call
search_metadata
in Step 2 without having scanned for
uiBundles/*/public/content-metadata.json
this turn, STOP and come back here first.
  1. Explicit
    channelId
    given
    — use it directly, skip discovery entirely, proceed to the scope rule below.
  2. Named uiBundle/app, no
    channelId
    — resolve that uiBundle's
    channelId
    ; if it doesn't resolve, fall through to point 3 as if nothing was named.
  3. Otherwise, discover from the local project — scan every
    uiBundles/*/public/content-metadata.json
    file (never gate this on server-side deployment status) and collect the
    channelId
    s found. Zero → public channels only. Exactly one → public plus that channel. More than one → ask the user which one via
    ask_followup_question
    .
→ Read
references/scope-resolution.md
§ "Step 1 points 1-3" for the full discovery mechanics before acting on points 1-3 above. Proceed to Step 2 once scope is determined.
Scope rule (applies whether the
channelId
was user-provided or discovered):
scope is always public channels (
contentAccessScope: "Public"
, no
channelIds
field) plus that one
channelId
(a separate call with
channelIds
set to it, no
contentAccessScope
field) — never resolve a separate ID to represent "public," and never send
contentAccessScope
and
channelIds
in the same call. This scope decides how many search calls Steps 3 and 4 make: no
channelId
in scope → one search call (public channels only). A
channelId
in scope → two search calls (public channels, then that specific
channelId
), with results merged before presenting.
**每个到达此步骤的请求都必须执行此操作——切勿直接跳至步骤2。**无论请求如何表述(例如“帮我找一篇文章”、纯关键词搜索等),都不能跳过此步骤的本地文件扫描。如果您打算在步骤2中调用
search_metadata
但尚未扫描
uiBundles/*/public/content-metadata.json
文件,请立即停止并返回此步骤。
  1. 明确提供
    channelId
    ——直接使用该ID,跳过所有发现流程,继续执行下方的范围规则。
  2. 指定了uiBundle/应用,但未提供
    channelId
    ——解析该uiBundle的
    channelId
    ;如果无法解析,则按第3点处理,如同未指定任何内容。
  3. 其他情况,从本地项目中发现——扫描所有
    uiBundles/*/public/content-metadata.json
    文件(切勿根据服务器端部署状态限制此操作),并收集找到的
    channelId
    。若无结果→仅使用公共渠道。若只有一个结果→使用公共渠道加上该渠道。若有多个结果→通过
    ask_followup_question
    询问用户选择哪一个。
→ 在执行上述1-3点之前,请阅读
references/scope-resolution.md
中“步骤1的1-3点”部分,了解完整的发现机制。确定范围后,继续执行步骤2。
**范围规则(无论
channelId
是用户提供还是发现的):范围始终包含公共渠道(
contentAccessScope: "Public"
,无
channelIds
字段)加上一个
channelId
(单独调用,设置
channelIds
为该ID,无
contentAccessScope
字段)——切勿解析单独的ID来代表“公共”,也切勿在同一调用中同时发送
contentAccessScope
channelIds
。**此范围决定了步骤3和4需要执行多少次搜索调用:范围中无
channelId
→一次搜索调用(仅公共渠道)。范围中有
channelId
→两次搜索调用(公共渠道,然后是特定的
channelId
),结果合并后再呈现。

Step 2: Determine Content Type and Route

步骤2:确定内容类型并路由

Precondition: Step 1 must have already run in this turn (its channel-scope result is what point 5 below carries into Step 3/4). Step 1 runs unconditionally — even for a plain keyword search with no obvious channel angle, not only when the request names a channel or app.
  1. Identify one or more distinct search intents in the request (e.g. "find a press release about our launch and a hero image for the page" is two intents). Run the rest of this step once per intent.
    If intents span both routes, sequence the routes — never interleave or merge them: run the Media Route (Step 4) to full completion for every media intent first, then the Content Route (Step 3) for every content intent. See Step 5.
  2. Call
    search_metadata
    on the
    metadata-grounding
    MCP server using the intent itself as the query. No
    filters
    array support
    metadataType
    is the only narrowing parameter, passed top-level:
    javascript
    search_metadata({ query: "<the user's intent>", metadataType: "ContentTypeBundle", limit: 100 })
Each candidate already includes a full composite identifier (e.g.
00DVW00000CfBQP2A3::0T1VW000008sow60AA::ContentTypeBundle
) — use it as returned; never reconstruct it.
Check the outcome before doing anything else:
  • metadata-grounding
    is unavailable (the call errors/times out)
    — you MUST call
    get_content_types_for_workspace
    (the workspace content-type fallback) before any Step 3/4 search tool; do not attempt
    query_metadata
    , there's nothing to look up, and do not skip straight to a search tool on an assumed FQN.
  • Zero candidates returned — ask the user one clarifying question to narrow the intent (
    ask_followup_question
    , same question/options as the "intent itself is ambiguous" case at the end of this step), then retry
    search_metadata
    once with the clarified query:
    • Still zero candidates after that one retry — apply the workspace content-type fallback. Do not ask a second clarifying question.
    • One or more candidates on the retry — continue to point 3.
  • One or more candidates on the first call — continue to point 3.
Fallback chain when
search_metadata
doesn't produce a usable candidate list
→ Read
references/content-type-discovery.md
before running it: "Workspace content-type fallback" first, then "Wording fallback" as a last resort.
  1. Call
    query_metadata
    with each candidate's identifier from point 2 (cap at top 5, batched into one
    metadataIdentifiers
    array):
    javascript
    query_metadata({ metadataIdentifiers: ["00DVW00000CfBQP2A3::0T1VW000008sow60AA::ContentTypeBundle"] })
    Read each entry's
    typeDetails[].properties
    mixins
    ,
    typeClasses
    , and
    apiName
    live there, not in the
    search_metadata
    response.
  2. Filter for supported types first, THEN decide the route among survivors — do not conflate the two:
    • Discard any candidate whose
      properties.mixins
      lacks
      sfdc_cms:deliveryApiEnabled
      — only delivery-API-enabled types are searchable.
    • Of the remainder, discard any whose
      properties.typeClasses
      lacks
      sfdc_cms__structured
      .
      This is the single "supported for search" gate, not a content/media split —
      sfdc_cms__structured
      appears on both structured-content types and media types, so it only separates searchable types from unsearchable ones (e.g.
      sfdc_cms__email
      carries
      sfdc_cms__content
      but not
      sfdc_cms__structured
      , and must be discarded).
    • Zero survive — tell the user which types were found but aren't supported, then stop (don't guess a route). Some, but not all, survive — tell the user which got filtered out (plain statement, not a question), then continue with survivors. All survive — no message needed. → Read
      references/content-type-discovery.md
      § "Filter-result messages" for exact wording.
    • Route on the top-ranked survivor's
      properties.typeClasses
      (order returned by
      search_metadata
      ): contains
      sfdc_cms__media
      → Media Route (Step 4); otherwise → Content Route (Step 3).
    • Collect the FQN(s) — the top-ranked survivor's
      properties.apiName
      . Add other surviving candidates' FQNs too if clearly relevant to the same intent and sharing the same classification, passing all as one comma-separated
      contentTypeFqn
      value rather than searching per type.
  3. Carry the scope from Step 1 (public channels only, or public channels plus a
    channelId
    ) into whichever route is invoked — see the
    channelIds
    field in each route below.
If intent itself is ambiguous (e.g. "find me some content" with no hint of type or subject) → Read
references/content-type-discovery.md
§ "Intent itself is ambiguous" for the exact question/options before calling
search_metadata
. Do not guess.
前置条件:步骤1必须已在当前请求中执行(其渠道范围结果将带入步骤3/4的第5点)。步骤1必须无条件执行——即使是无明显渠道指向的纯关键词搜索,而不仅仅是当请求指定渠道或应用时。
  1. 识别请求中的一个或多个不同搜索意图(例如“找一篇关于我们发布会的新闻稿,以及页面用的首屏图”包含两个意图)。对每个意图执行此步骤的其余部分。
    **如果意图跨越两个路由,请按顺序执行路由——切勿交错或合并:**先针对所有媒体意图完整执行媒体路由(步骤4),再针对所有内容意图执行内容路由(步骤3)。详见步骤5。
  2. 调用
    search_metadata
    :在
    metadata-grounding
    MCP服务器上,将意图本身作为查询参数调用该工具。不支持
    filters
    数组
    ——仅可通过顶级参数
    metadataType
    来缩小范围:
    javascript
    search_metadata({ query: "<the user's intent>", metadataType: "ContentTypeBundle", limit: 100 })
每个候选结果已包含完整的复合标识符(例如
00DVW00000CfBQP2A3::0T1VW000008sow60AA::ContentTypeBundle
)——直接使用返回值;切勿自行重构。
在执行其他操作前先检查结果:
  • metadata-grounding
    不可用(调用出错/超时)
    ——必须在调用步骤3/4的搜索工具前调用
    get_content_types_for_workspace
    (工作区内容类型备选方案);不要尝试
    query_metadata
    ,因为没有可查询的内容,也不要假设FQN直接跳转到搜索工具。
  • 未返回候选结果——向用户提出一个澄清问题以缩小意图范围(使用
    ask_followup_question
    ,与本步骤末尾“意图本身不明确”场景使用相同的问题/选项),然后使用澄清后的查询重试一次
    search_metadata
    • 重试后仍无结果——应用工作区内容类型备选方案。请勿提出第二个澄清问题。
    • 重试后返回一个或多个候选结果——继续执行第3点。
  • 首次调用返回一个或多个候选结果——继续执行第3点。
search_metadata
无法生成可用候选列表时的备选流程
→ 在执行前请阅读
references/content-type-discovery.md
:优先使用“工作区内容类型备选方案”,最后使用“措辞备选方案”。
  1. 调用
    query_metadata
    :传入第2点中每个候选结果的标识符(最多取前5个,批量放入
    metadataIdentifiers
    数组):
    javascript
    query_metadata({ metadataIdentifiers: ["00DVW00000CfBQP2A3::0T1VW000008sow60AA::ContentTypeBundle"] })
    读取每个条目的
    typeDetails[].properties
    ——
    mixins
    typeClasses
    apiName
    存储在此处,而非
    search_metadata
    的响应中。
  2. 先筛选支持的类型,再从剩余类型中决定路由——切勿混淆这两个步骤:
    • 剔除
      properties.mixins
      中缺少
      sfdc_cms:deliveryApiEnabled
      的候选结果——仅启用交付API的类型可被搜索。
    • 在剩余结果中,剔除
      properties.typeClasses
      中缺少
      sfdc_cms__structured
      的候选结果。这是唯一的“支持搜索”筛选条件,而非内容/媒体的拆分条件——
      sfdc_cms__structured
      同时出现在结构化内容类型和媒体类型中,因此它仅区分可搜索类型与不可搜索类型(例如
      sfdc_cms__email
      包含
      sfdc_cms__content
      但不包含
      sfdc_cms__structured
      ,必须被剔除)。
    • 无剩余结果——告知用户找到的类型均不支持,然后停止操作(不要猜测路由)。部分剩余——告知用户哪些类型被筛选掉(直接陈述,而非提问),然后继续处理剩余结果。全部剩余——无需发送消息。→ 请阅读
      references/content-type-discovery.md
      中的“筛选结果消息”部分,获取准确措辞。
    • 根据排名最高的剩余结果的
      properties.typeClasses
      决定路由
      (按
      search_metadata
      返回的顺序):包含
      sfdc_cms__media
      →媒体路由(步骤4);否则→内容路由(步骤3)。
    • 收集FQN——排名最高的剩余结果的
      properties.apiName
      。如果其他剩余候选结果与同一意图明显相关且属于同一分类,也添加其FQN,将所有FQN作为逗号分隔的
      contentTypeFqn
      值传入,而非按类型分别搜索。
  3. 将步骤1的范围(仅公共渠道,或公共渠道加一个
    channelId
    )带入调用的路由——详见下方每个路由中的
    channelIds
    字段。
如果意图本身不明确(例如“帮我找一些内容”,未提及类型或主题)→ 在调用
search_metadata
前,请阅读
references/content-type-discovery.md
中的“意图本身不明确”部分,获取准确的问题/选项。切勿猜测。

Step 3: Content Route

步骤3:内容路由

Follow this sequence for each intent Step 2 routed here. The content type FQN(s) are already known from Step 2.
  1. Build the search query:
    • Extract keywords — concrete nouns and named subjects that would appear in the content's title or body. Use domain-specific synonyms, max 10 terms, joined with
      OR
      . E.g. "blog posts about sustainable business practices" →
      sustainable OR sustainability OR business OR environmental
      .
    • Extract taxonomies — descriptive qualities, categories, or topical tags only (adjectives, categories, attributes — not concrete nouns). Stringify as
      {"OR": ["term1", "term2"]}
      , or
      "{}"
      if none apply. E.g. "sustainable business practices and environmental responsibility" →
      {"OR": ["Business", "Corporate", "Environment", "Responsibility"]}
      ; "FAQs about password resets" →
      "{}"
      (no descriptive/categorical terms).
    • Load
      assets/search-payload-template.json
      for the request payload structure. Set
      contentTypeFqn
      to the comma-separated FQN list collected in Step 2.
      contentAccessScope
      and
      channelIds
      are mutually exclusive — never send both in the same call — so they're set per-call in point 3 below, not here.
  2. Confirm with the user — required two-message pattern (labeled-parameters chat message, then
    ask_followup_question
    with
    Yes - search now
    /
    Edit search
    /
    Cancel
    ). Never put the labeled list inside
    ask_followup_question
    's text — it strips formatting. → Read
    references/content-route.md
    § "Confirming the query before searching" for templates.
  3. Execute the search call(s) per the scope from Step 1 — one call for public-only scope, two (public + channel-scoped) when a
    channelId
    is in scope. → Read
    references/content-route.md
    § "Executing the search call(s)" before parsing results — array/merge rules.
  4. Present up to 5 unique results total (de-duplicated by
    managedContentKey
    for display only — an item found under more than one channel still appears once here), grouped by content type, with a
    Load More
    option if more remain. Each item shows its Channel as a per-item field — never the grouping key:
    text
    I found 3 content items:
    
    Editorial (c__Editorial):
    1. <title> — Channel: Public
    2. <title> — Channel: <uiBundle>
    
    Blog (sfdc_cms__blog):
    3. <title> — Channel: Public
    Only one content type FQN in scope → the heading may be omitted (still one group); the per-item Channel field is always shown. If an item exists under multiple channels, show its first/primary channel here — the choice between channels happens after selection (point 5), not at presentation time.
  5. User selects one, several, or all items. For each selected item whose delivery-details array has more than one entry, ask which channel's copy to use — one
    ask_followup_question
    option per entry, named from
    managedContentChannelDetails.name
    — before displaying its details; items with zero or one entry go straight to display. Show
    managedContentId
    ,
    managedContentKey
    ,
    language
    , channel, and — only for a
    PUBLIC_UNAUTHENTICATED
    /
    COMMUNITY
    entry with a
    contentUrl
    , never a
    WEB_APP
    one — the full Unauthenticated URL (all query parameters). → Read
    references/content-route.md
    § "Disambiguating channel at selection" before asking — pass the channel names as
    ask_followup_question
    's
    options
    array, never inline them in the question text.
  6. If the channelId in scope came from uiBundle discovery (skip entirely for public-only scope or a user-supplied
    channelId
    with no uiBundle), offer the
    experience-cms-content-render
    hand-off using the same two-message pattern, passing each item's
    title
    , content type FQN, its chosen entry's
    managedContentChannelDetails.id
    (channel ID) only when it has a delivery entry — omit for a zero-entry item, never a placeholder, and either its Unauthenticated URL or, if absent, its
    managedContentKey
    as
    contentKey
    (the receiving skill's field name). → Read
    references/content-route.md
    § "Offering the render hand-off" for the full procedure.
→ Read
references/content-route.md
for the complete end-to-end worked example.
对步骤2路由至此的每个意图执行以下流程。内容类型FQN已从步骤2中获取。
  1. 构建搜索查询:
    • 提取关键词——内容标题或正文中会出现的具体名词和指定主题。使用领域特定同义词,最多10个术语,用
      OR
      连接。例如“关于可持续商业实践的博客文章”→
      sustainable OR sustainability OR business OR environmental
    • 提取分类法——仅提取描述性特质、类别或主题标签(形容词、类别、属性——非具体名词)。格式化为
      {"OR": ["term1", "term2"]}
      ,若无则为
      "{}"
      。例如“可持续商业实践与环境责任”→
      {"OR": ["Business", "Corporate", "Environment", "Responsibility"]}
      ;“关于密码重置的常见问题”→
      "{}"
      (无描述性/分类术语)。
    • 加载
      assets/search-payload-template.json
      获取请求负载结构。将
      contentTypeFqn
      设置为步骤2中收集的逗号分隔FQN列表。
      contentAccessScope
      channelIds
      互斥——切勿在同一调用中同时发送两者,因此它们将在下方第3点中按调用设置,而非在此处设置。
  2. 与用户确认——必须使用两步消息模式(带标签参数的聊天消息,然后是带有
    Yes - search now
    /
    Edit search
    /
    Cancel
    选项的
    ask_followup_question
    )。切勿将标签列表放入
    ask_followup_question
    的文本中——它会移除格式。→ 请阅读
    references/content-route.md
    中的“搜索前确认查询”部分,获取模板。
  3. 根据步骤1的范围执行搜索调用——仅公共范围执行一次调用,范围包含
    channelId
    时执行两次调用(公共+渠道范围)。→ 在解析结果前,请阅读
    references/content-route.md
    中的“执行搜索调用”部分——了解数组/合并规则。
  4. 最多展示5条唯一结果(仅在展示时按
    managedContentKey
    去重——在多个渠道下找到的同一项目仍仅显示一次),按内容类型分组,若有更多结果则提供
    Load More
    选项。每个项目需显示其渠道作为单独字段——切勿将渠道作为分组键:
    text
    我找到了3个内容项目:
    
    Editorial (c__Editorial):
    1. <标题> — 渠道:Public
    2. <标题> — 渠道:<uiBundle>
    
    Blog (sfdc_cms__blog):
    3. <标题> — 渠道:Public
    范围中仅有一种内容类型FQN→可省略标题(仍为一组);每个项目的渠道字段始终显示。如果一个项目存在于多个渠道中,此处显示其首个/主渠道——渠道选择在选择项目后进行(第5点),而非展示时。
  5. 用户选择一个、多个或全部项目。对于每个交付详情数组包含多个条目的选中项目,询问用户使用哪个渠道的副本——每个条目对应
    ask_followup_question
    的一个选项,选项名称来自
    managedContentChannelDetails.name
    ——然后再展示详情;交付详情数组为0或1条的项目直接展示详情。展示
    managedContentId
    managedContentKey
    language
    、渠道,以及——仅当条目为
    PUBLIC_UNAUTHENTICATED
    /
    COMMUNITY
    且包含
    contentUrl
    时,
    WEB_APP
    条目除外——完整的未认证URL(所有查询参数)。→ 在提问前,请阅读
    references/content-route.md
    中的“选择时明确渠道”部分——将渠道名称作为
    ask_followup_question
    options
    数组传入,切勿嵌入问题文本中。
  6. 如果范围中的channelId来自uiBundle发现(仅公共范围或用户提供的无uiBundle的
    channelId
    需跳过此步骤),使用相同的两步消息模式提供
    experience-cms-content-render
    交接,传入每个项目的
    title
    、内容类型FQN、所选条目的
    managedContentChannelDetails.id
    (渠道ID)仅当该项目有交付条目时——无交付条目的项目省略该字段,切勿使用占位符,以及其未认证URL(若存在),否则传入其
    managedContentKey
    作为
    contentKey
    (接收Skill的字段名)。→ 请阅读
    references/content-route.md
    中的“提供渲染交接”部分,获取完整流程。
→ 请阅读
references/content-route.md
获取完整的端到端示例。

Step 4: Media Route

步骤4:媒体路由

Follow this sequence for each intent Step 2 routed here. The media content type FQN (e.g.
sfdc_cms__image
,
sfdc_cms__audio
,
sfdc_cms__video
,
sfdc_cms__document
) is already known from Step 2 — never assume it's an image; use whatever FQN Step 2 discovered for this intent.
  1. Present available search sources via
    ask_followup_question
    — no other tool calls yet.
    Only the sources whose tools you actually have (via introspection), plus "Other", each as its own option. Wait for the user's selection before any tool call. → Read
    references/media-route.md
    § "Presenting available search sources" for the full template.
  2. Build the query, then confirm with the user before searching — required two-message pattern, in the same turn:
    • Search using keywords (
      search_media_cms_channels
      ): extract keywords (concrete nouns, max 10 terms) and taxonomies (descriptive/style/mood/category terms — extract every one the query actually contains; don't default to empty just because keywords were found). E.g. "luxury apartment with river view" → keywords
      apartment OR villa OR penthouse OR residence
      , taxonomies
      {"OR": ["Luxury", "Premium", "Waterfront", "Riverside"]}
      ; "car" → taxonomies
      "{}"
      (no descriptive terms). Build the payload with
      contentTypeFqn
      set to the FQN(s) from Step 2,
      searchLanguage
      set to a locale (
      en_US
      ,
      es_MX
      , ... — default
      en_US
      ; required, never null/omitted),
      searchLimit: 5
      . → Read
      references/media-route.md
      for full worked examples.
    • Search using Data 360 hybrid search (
      search_electronic_media
      ) — pass the user's query as-is to
      searchQuery
      , no extraction needed.
    • Other — ask for a direct URL, asset library path, or specific system to check (no confirmation step, since no tool is called).
    → Read
    references/media-route.md
    § "Confirming the query before searching" for the confirmation message templates (labeled-parameters chat message, then
    ask_followup_question
    with
    Yes - search now
    /
    Edit search
    /
    Cancel
    ).
  3. Execute the search call(s) per the scope from Step 1 — one call for public-only scope, two (public + channel-scoped) when a
    channelId
    is in scope; Data 360 hybrid search ignores channel scope entirely. → Read
    references/media-route.md
    § "Executing the search call(s)" before parsing results — array/merge rules.
  4. Present all unique results via
    ask_followup_question
    , grouped by content type
    — one option per result (de-duplicated by unique identifier for display only — an item found under more than one channel still appears once here), labeled with title, content type, and channel (e.g.
    Product Launch Hero Banner (sfdc_cms__image) — Public
    ). Mirrors the Content Route: content type is the grouping key, channel is a per-item field. Never auto-select.
  5. User selects an item. If its delivery-details array has more than one entry, ask which channel's copy to use — one option per entry, named from
    managedContentChannelDetails.name
    — before displaying details. Show Content Name, Content Type, channel, and — only for a
    PUBLIC_UNAUTHENTICATED
    /
    COMMUNITY
    entry with a
    contentUrl
    , never a
    WEB_APP
    one — the full Unauthenticated URL (all query parameters). → Read
    references/media-route.md
    § "Disambiguating channel at selection" before asking — pass the channel names as
    ask_followup_question
    's
    options
    array, never inline them in the question text.
  6. Offer the render hand-off — always, with no uiBundle gating (unlike the Content Route's offer, which only appears when a uiBundle channel was in scope). Same two-message pattern: plain-text mention of the item, then
    ask_followup_question
    with
    Yes
    /
    No
    . On
    Yes
    , dispatch via
    mcp__skill_bridge__load_skill("experience-cms-content-render")
    — never the built-in Skill tool (separate registry, returns
    Unknown skill
    ) — passing the selected item's
    title
    , content type FQN, the chosen entry's
    managedContentChannelDetails.id
    (channel ID) only when it has a delivery entry — this route explicitly supports zero-entry items, so omit the channel ID for those rather than reading
    .id
    off nothing
    , and either its Unauthenticated URL or, if absent, its
    managedContentKey
    as
    contentKey
    (the receiving skill's field name). If the load call fails, tell the user the hand-off failed and stop. On
    No
    , stop — the search is complete; do not apply the URL yourself as a fallback.
→ Read
references/media-route.md
for the complete worked example.
对步骤2路由至此的每个意图执行以下流程。媒体内容类型FQN(例如
sfdc_cms__image
sfdc_cms__audio
sfdc_cms__video
sfdc_cms__document
)已从步骤2中获取——切勿假设是图片;使用步骤2为此意图发现的任意FQN。
  1. **通过
    ask_followup_question
    展示可用搜索来源——暂不调用其他工具。**仅展示您实际拥有的来源(通过自省),加上“其他”,每个来源作为一个选项。等待用户选择后再调用工具。→ 请阅读
    references/media-route.md
    中的“展示可用搜索来源”部分,获取完整模板。
  2. 构建查询,然后在搜索前与用户确认——必须使用两步消息模式,在同一请求中完成:
    • 使用关键词搜索
      search_media_cms_channels
      ):提取关键词(具体名词,最多10个术语)和分类法(描述性/风格/情绪/类别术语——提取查询中实际包含的所有术语;不要因为找到关键词就默认分类法为空)。例如“带河景的豪华公寓”→ 关键词
      apartment OR villa OR penthouse OR residence
      ,分类法
      {"OR": ["Luxury", "Premium", "Waterfront", "Riverside"]}
      ;“汽车”→ 分类法
      "{}"
      (无描述性术语)。构建负载时,将
      contentTypeFqn
      设置为步骤2中的FQN,
      searchLanguage
      设置为区域设置(
      en_US
      es_MX
      ……默认
      en_US
      必填,切勿留空/省略),
      searchLimit: 5
      。→ 请阅读
      references/media-route.md
      获取完整示例。
    • 使用Data 360混合搜索
      search_electronic_media
      )——直接将用户查询传入
      searchQuery
      ,无需提取。
    • 其他——请求用户提供直接URL、资产库路径或要检查的特定系统(无需确认步骤,因为不调用工具)。
    → 请阅读
    references/media-route.md
    中的“搜索前确认查询”部分,获取确认消息模板(带标签参数的聊天消息,然后是带有
    Yes - search now
    /
    Edit search
    /
    Cancel
    选项的
    ask_followup_question
    )。
  3. 根据步骤1的范围执行搜索调用——仅公共范围执行一次调用,范围包含
    channelId
    时执行两次调用(公共+渠道范围);Data 360混合搜索完全忽略渠道范围。→ 在解析结果前,请阅读
    references/media-route.md
    中的“执行搜索调用”部分——了解数组/合并规则。
  4. 通过
    ask_followup_question
    展示所有唯一结果,按内容类型分组
    ——每个结果对应一个选项(仅在展示时按唯一标识符去重——在多个渠道下找到的同一项目仍仅显示一次),标注标题、内容类型和渠道(例如
    Product Launch Hero Banner (sfdc_cms__image) — Public
    )。与内容路由一致:内容类型为分组键,渠道为每个项目的字段。切勿自动选择。
  5. 用户选择一个项目。如果其交付详情数组包含多个条目,询问用户使用哪个渠道的副本——每个条目对应一个选项,选项名称来自
    managedContentChannelDetails.name
    ——然后再展示详情。展示内容名称、内容类型、渠道,以及——仅当条目为
    PUBLIC_UNAUTHENTICATED
    /
    COMMUNITY
    且包含
    contentUrl
    时,
    WEB_APP
    条目除外——完整的未认证URL(所有查询参数)。→ 在提问前,请阅读
    references/media-route.md
    中的“选择时明确渠道”部分——将渠道名称作为
    ask_followup_question
    options
    数组传入,切勿嵌入问题文本中。
  6. 提供渲染交接——始终提供,无uiBundle限制(与内容路由的交接不同,内容路由仅当范围包含uiBundle渠道时才提供)。使用相同的两步消息模式:提及项目的纯文本消息,然后是带有
    Yes
    /
    No
    选项的
    ask_followup_question
    。用户选择
    Yes
    时,通过
    mcp__skill_bridge__load_skill("experience-cms-content-render")
    调度——切勿使用内置Skill工具(单独注册表,会返回
    Unknown skill
    )——传入选中项目的
    title
    、内容类型FQN、所选条目的
    managedContentChannelDetails.id
    (渠道ID)仅当该项目有交付条目时——此路由明确支持无交付条目的项目,因此此类项目省略渠道ID,切勿从空值中读取
    .id
    ,以及其未认证URL(若存在),否则传入其
    managedContentKey
    作为
    contentKey
    (接收Skill的字段名)。如果加载调用失败,告知用户交接失败并停止操作。用户选择
    No
    时,停止操作——搜索完成;切勿自行使用URL作为备选方案。
→ 请阅读
references/media-route.md
获取完整示例。

Step 5: Present Combined Results

步骤5:展示合并结果

When a request mixes media and content intents, run the two routes sequentially, each to full completion, not interleaved and not merged into one combined presentation:
  1. Media Route first — for every media intent, run Step 4 in full: present sources, build/confirm the query, search, present results, let the user select, and (point 6) offer the
    experience-cms-content-render
    hand-off (Yes/No). Finish this entire route — including the offer — before starting the Content Route.
  2. Content Route second — for every content intent, run Step 3 in full: build/confirm the query, search, present results grouped by content type (channel shown per-item), let the user select, and (point 6) offer the
    experience-cms-content-render
    hand-off if a uiBundle channel is in scope.
Each route's results are labeled and presented on their own (e.g. "Images:" for the Media Route's output, then "Articles:" for the Content Route's) — never merge the two into one undifferentiated list, and never hold Media Route's results back to present alongside Content Route's.
当请求混合媒体和内容意图时,按顺序执行两个路由,每个路由完整执行,切勿交错或合并为一个展示
  1. 先执行媒体路由——针对所有媒体意图,完整执行步骤4:展示来源、构建/确认查询、搜索、展示结果、让用户选择,以及(第6点)提供
    experience-cms-content-render
    交接(是/否)。完成整个路由(包括交接)后,再开始执行内容路由。
  2. 再执行内容路由——针对所有内容意图,完整执行步骤3:构建/确认查询、搜索、按内容类型分组展示结果(每个项目显示渠道)、让用户选择,以及(第6点)如果范围包含uiBundle渠道,则提供
    experience-cms-content-render
    交接。
每个路由的结果需单独标注并展示(例如媒体路由输出标注为“图片:”,内容路由输出标注为“文章:”)——切勿将两者合并为一个无差别的列表,也切勿保留媒体路由的结果与内容路由结果一起展示。

Error Handling

错误处理

ErrorResponse
No
search_content_cms_channels
/
search_media_cms_channels
tools found via introspection
"No content search connection is configured. Please connect a content-readonly MCP server."
Neither media tool available"No automated media search sources are currently configured. Please provide a direct URL or asset library path."
metadata-grounding
unavailable or no content types match
Apply the fallback chain in
references/content-type-discovery.md
— do not block or ask for an FQN
No search results (either route)"No [content/media] found. Try broader keywords, removing descriptive terms, or a different [content type/source]."
Invalid user selectionRe-display options and ask again
Tool returns error (invalid input, missing argument, or otherwise)Show error message, offer retry with corrected parameters on that same tool — never fall through to the other route's search tool as a workaround (see Key Principle 3)
Search tool on the connected server returns a server error (5xx, timeout, connection failure — not "no results")Fail the call — do NOT silently retry against a different server. Tell the user to check that server's connection/session and wait before retrying.
Never silently fail on a route the user asked for. If one route in a mixed request comes up empty, still present the other route's results and say so explicitly. This does not mean substituting a different server when the connected one errors — see the server-error row above.
错误响应
通过自省未找到
search_content_cms_channels
/
search_media_cms_channels
工具
"未配置内容搜索连接。请连接一个内容只读MCP服务器。"
无可用媒体工具"当前未配置自动化媒体搜索来源。请提供直接URL或资产库路径。"
metadata-grounding
不可用或无匹配内容类型
应用
references/content-type-discovery.md
中的备选流程——切勿阻塞或请求FQN
无搜索结果(任一路由)"未找到[内容/媒体]。尝试更宽泛的关键词、移除描述性术语或更换[内容类型/来源]。"
用户选择无效重新展示选项并再次询问
工具返回错误(无效输入、缺少参数或其他错误)展示错误消息,提供使用修正后的参数重试该工具的选项**——切勿作为备选方案切换到另一路由的搜索工具**(参见关键原则3)
关联服务器上的搜索工具返回服务器错误(5xx、超时、连接失败——而非“无结果”)**终止调用——切勿静默重试其他服务器。**告知用户检查该服务器的连接/会话,等待后再重试。
**切勿静默终止用户请求的路由。**如果混合请求中的一个路由无结果,仍需展示另一路由的结果并明确告知。这并不意味着当关联服务器出错时切换到其他服务器——参见上述服务器错误行。

Key Principles

关键原则

  1. Resolve channel scope first — determine channel scope (Step 1) before any content-type discovery or search
  2. Search first, route second
    search_metadata
    +
    query_metadata
    decide the route; fall back to
    get_content_types_for_workspace
    , then intent wording, only when that comes up empty (Step 2)
  3. Never cross-route, including on failure — content requests never hit media search tools and vice versa; if a route's search tool errors for any reason, fix and retry that same tool or stop and report the error — never fall through to the other route's tool as a workaround
  4. Metadata grounding is mandatory for content — discover content type FQNs dynamically, never hardcode them
  5. Media route starts text-only — present sources and wait before any tool call
  6. Confirm before searching (both routes) — user approves query parameters before execution
  7. Never auto-select — always wait for user choice, across channel scope and both routes
  8. Run mixed requests sequentially, Media Route first — complete it fully (including the render offer) before starting the Content Route; present each route's results as its own labeled set, never merged
  9. Handle errors gracefully — clear feedback and alternatives, per route
  10. Offer to render, don't assume — both routes require Yes/No confirmation before the hand-off; only the gating differs — Content Route offers it only when a uiBundle channel was actually in scope, Media Route always offers it
  11. Never fail over to a different server on a server error — fail the call and tell the user to check that server's session; don't silently retry elsewhere
  12. Group by content type, never by channel — in both routes, channel is always a per-item field, never the group heading
  13. Disambiguate channel at selection, not before — an item is shown once at presentation regardless of its delivery-details array length; only after selection do you ask which channel's copy to use, one option per entry by
    managedContentChannelDetails.name
    , in both routes
  14. Unauthenticated URL is public-channel-only
    PUBLIC_UNAUTHENTICATED
    /
    COMMUNITY
    entries only; never a
    WEB_APP
    (uiBundle) entry's
    contentUrl
    , in either route
  1. 先解析渠道范围——在任何内容类型发现或搜索前,确定渠道范围(步骤1)
  2. 先搜索,后路由——
    search_metadata
    +
    query_metadata
    决定路由;仅当无结果时,才依次使用
    get_content_types_for_workspace
    和意图措辞作为备选(步骤2)
  3. 切勿跨路由,包括出错时——内容请求永远不会调用媒体搜索工具,反之亦然;如果某路由的搜索工具因任何原因出错,修复并重试该工具或终止操作并报告错误——切勿作为备选方案切换到另一路由的工具
  4. 内容必须使用元数据关联——动态发现内容类型FQN,切勿硬编码
  5. 媒体路由从纯文本开始——先展示来源并等待用户选择,再调用工具
  6. 搜索前确认(两个路由)——用户在执行前需批准查询参数
  7. 切勿自动选择——在渠道范围和两个路由中,始终等待用户选择
  8. 混合请求按顺序执行,先媒体路由——完整执行媒体路由(包括渲染交接)后再开始内容路由;每个路由的结果单独标注展示,切勿合并
  9. 优雅处理错误——每个路由提供清晰的反馈和备选方案
  10. 提供渲染选项,勿假设——两个路由在交接前都需要用户确认是/否;仅限制条件不同——内容路由仅当范围包含uiBundle渠道时提供,媒体路由始终提供
  11. 服务器出错时切勿切换到其他服务器——终止调用并告知用户检查服务器会话;切勿静默重试其他服务器
  12. 按内容类型分组,切勿按渠道——在两个路由中,渠道始终是每个项目的字段,而非分组标题
  13. 选择时明确渠道,而非之前——展示时,无论项目的交付详情数组长度如何,均仅显示一次;仅在用户选择后,才询问使用哪个渠道的副本,每个选项对应
    managedContentChannelDetails.name
    ,两个路由均如此
  14. 未认证URL仅适用于公共渠道——仅
    PUBLIC_UNAUTHENTICATED
    /
    COMMUNITY
    条目;两个路由中均不使用
    WEB_APP
    (uiBundle)条目的
    contentUrl
    ",