feat(experimental): invite to plugin cards only from the accepted call's result
The model sometimes wrote the skill's invitation sentence without calling propose_action, so users read "click below" with no card. The plugin kind now registers its invitation, which only an accepted call's result carries: "Card shown below your answer. Do not restate it. End with at most one short invitation in the user’s language to click Enable below; do not say the plugin is already on." The skill drops its invitation sentence and says the call's result tells how to end the answer. A test runs a real turn and checks that the accepted result carries the invitation and a refused call does not; the plugin Web fixture is refreshed for the new skill and result text.
This commit is contained in:
1 parent
d9b95adf93
commit
b62dfa2d63
9 files changed
+41
-15
No files matched your search
@@ -33,11 +33,11 @@
|
||||
en: 79e932b35e50619a
|
||||
zh: 821b4d95d6ce1d22
|
||||
/deepseek-ai-dsh-experimental-plugin-recommendations/model-experience/official-plugin-recommendations/what-the-model-sees:
|
||||
en: 1e9e93dfa9a1942a
|
||||
zh: 00e45f4b412739e4
|
||||
en: 5526f467498a8458
|
||||
zh: 9495ede65dbc6771
|
||||
/deepseek-ai-dsh-experimental-plugin-recommendations/model-experience/official-plugin-recommendations/token-effect:
|
||||
en: d3214d1493ea2b18
|
||||
zh: ecf588cca37ef007
|
||||
en: 9849eee72560906e
|
||||
zh: d64a2f5b1e33f249
|
||||
/deepseek-ai-dsh-experimental-plugin-recommendations/model-experience/official-plugin-recommendations/kv-cache-effect:
|
||||
en: e6575a3adcaa7d1c
|
||||
zh: e5323a4571ecc8aa
|
||||
|
||||
@@ -69,11 +69,11 @@ Concurrent actions on one card share one operation, and disposal stops local fol
|
||||
|
||||
#### What the model sees
|
||||
|
||||
The existing `skill` tool loads `official-plugins` when the user asks how to do or use something in DSH, asks whether DSH can do something, or says a capability is missing or should change, such as tools, input, displayed thinking or titles, session search, terminals, worktrees, agent teams, desktop control, automation, access, approval prompts, output badges or signatures, and plugins or plugin sources. The catalog entry tells the Agent that such a question is not a request to develop DSH and to load the skill before reading files or source. Loading returns matching policy, the submission rule and the current catalog with names, localized titles, descriptions and enabled state. An enabled match gets usage guidance without a card; a partial match states its limit. Ordinary tasks, quoted wishes, discussion-only and declined requests get no card. The proposal is one [`propose_action`](../action-cards/README.md#model-experience) call in the same Turn as the skill load, with `action: "enable_official_plugin"`, the plugin's catalog `title`, a one-sentence `brief` in the user's language and `details` holding the catalog `name`; the call itself is the submission, and nothing changes until the user clicks Enable. The next request after a click carries the shared status notice with this kind's guidance: a fact, not a request for more work, and enabling authorizes nothing beyond that plugin.
|
||||
The existing `skill` tool loads `official-plugins` when the user asks how to do or use something in DSH, asks whether DSH can do something, or says a capability is missing or should change, such as tools, input, displayed thinking or titles, session search, terminals, worktrees, agent teams, desktop control, automation, access, approval prompts, output badges or signatures, and plugins or plugin sources. The catalog entry tells the Agent that such a question is not a request to develop DSH and to load the skill before reading files or source. Loading returns matching policy, the submission rule and the current catalog with names, localized titles, descriptions and enabled state. An enabled match gets usage guidance without a card; a partial match states its limit. Ordinary tasks, quoted wishes, discussion-only and declined requests get no card. The proposal is one [`propose_action`](../action-cards/README.md#model-experience) call in the same Turn as the skill load, with `action: "enable_official_plugin"`, the plugin's catalog `title`, a one-sentence `brief` in the user's language and `details` holding the catalog `name`; the call itself is the submission, and nothing changes until the user clicks Enable. Only an accepted call's result says how to end the answer: `Card shown below your answer. Do not restate it. End with at most one short invitation in the user’s language to click Enable below; do not say the plugin is already on.` A refused call carries no invitation, so the Agent invites the user only to a card that exists. The next request after a click carries the shared status notice with this kind's guidance: a fact, not a request for more work, and enabling authorizes nothing beyond that plugin.
|
||||
|
||||
#### Token effect
|
||||
|
||||
While enabled, requests carry only the 495-character catalog entry, within the skill catalog's 500-character limit; the shared card tool is declared only after a card skill loads. A skill load appends about 8.6K characters: a 2.8K-character policy plus the catalog, about 5.5K characters for 15 eligible plugins and growing with their number. A recommendation needs one skill load and one `propose_action` call before the final answer. A changed card appends one short status notice to the next request.
|
||||
While enabled, requests carry only the 495-character catalog entry, within the skill catalog's 500-character limit; the shared card tool is declared only after a card skill loads. A skill load appends about 8.5K characters: a 2.7K-character policy plus the catalog, about 5.5K characters for 15 eligible plugins and growing with their number. A recommendation needs one skill load and one `propose_action` call before the final answer; the accepted call's result is 169 characters, about 42 tokens at four characters per token. A changed card appends one short status notice to the next request.
|
||||
|
||||
#### KV Cache effect
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@ Host 入口是函数插件。它的 `apply` 通过 `ctx.plugin` 组装内部的
|
||||
|
||||
#### 模型可见内容
|
||||
|
||||
用户问 DSH 里某件事怎么做或怎么用、DSH 能不能做某件事,或者说缺少某种能力、希望它换一种工作方式时,例如工具、输入方式、思考内容或标题的显示、搜索会话、终端、工作树、多智能体协作、桌面操作、自动化、访问权限、授权确认、输出徽章或签名、插件及插件源,现有的 `skill` 工具会加载 `official-plugins`。目录条目告诉 Agent 这类问题不是要开发 DSH,并要求在读取文件或源码之前先加载它。加载结果包含匹配规则、提交方式,以及当前目录中的名称、本地化标题、描述和启用状态。已启用的插件只说明用法、不出卡;只覆盖部分需求时说明限制。普通任务、引用中的愿望、只讨论和明确不要推荐的请求不出卡。提案是在加载 skill 的同一轮里调用一次 [`propose_action`](../action-cards/README.zh.md#model-experience):`action: "enable_official_plugin"`、插件在目录中的 `title`、一句用户语言的 `brief`,以及带目录 `name` 的 `details`;调用本身就是提交,用户点击启用前什么都不会改变。点击后的下一次请求会带共享的状态通知和本种类的说明:它是事实,不是继续工作的要求,启用一个插件也不授权该插件之外的任何事。
|
||||
用户问 DSH 里某件事怎么做或怎么用、DSH 能不能做某件事,或者说缺少某种能力、希望它换一种工作方式时,例如工具、输入方式、思考内容或标题的显示、搜索会话、终端、工作树、多智能体协作、桌面操作、自动化、访问权限、授权确认、输出徽章或签名、插件及插件源,现有的 `skill` 工具会加载 `official-plugins`。目录条目告诉 Agent 这类问题不是要开发 DSH,并要求在读取文件或源码之前先加载它。加载结果包含匹配规则、提交方式,以及当前目录中的名称、本地化标题、描述和启用状态。已启用的插件只说明用法、不出卡;只覆盖部分需求时说明限制。普通任务、引用中的愿望、只讨论和明确不要推荐的请求不出卡。提案是在加载 skill 的同一轮里调用一次 [`propose_action`](../action-cards/README.zh.md#model-experience):`action: "enable_official_plugin"`、插件在目录中的 `title`、一句用户语言的 `brief`,以及带目录 `name` 的 `details`;调用本身就是提交,用户点击启用前什么都不会改变。只有被接受的调用结果会说明回答怎样结尾:`Card shown below your answer. Do not restate it. End with at most one short invitation in the user’s language to click Enable below; do not say the plugin is already on.`。被拒绝的调用不带邀请说明,所以 Agent 只会邀请用户点击已经出现的卡片。点击后的下一次请求会带共享的状态通知和本种类的说明:它是事实,不是继续工作的要求,启用一个插件也不授权该插件之外的任何事。
|
||||
|
||||
#### Token 影响
|
||||
|
||||
启用期间,每次请求只多一条 495 字符的目录条目(在 skill 目录 500 字符的上限内);共享的卡片工具只在加载过卡片 skill 之后才声明。一次 skill 加载追加约 8.6K 字符:2.8K 字符的规则,加上目录;15 个可推荐插件时目录约 5.5K 字符,并随插件数量增长。一次推荐需要加载一次 skill,并在最终回答前调用一次 `propose_action`。状态变化的卡片会在下一次请求追加一条简短通知。
|
||||
启用期间,每次请求只多一条 495 字符的目录条目(在 skill 目录 500 字符的上限内);共享的卡片工具只在加载过卡片 skill 之后才声明。一次 skill 加载追加约 8.5K 字符:2.7K 字符的规则,加上目录;15 个可推荐插件时目录约 5.5K 字符,并随插件数量增长。一次推荐需要加载一次 skill,并在最终回答前调用一次 `propose_action`;被接受的调用结果 169 字符,按每 4 字符 1 个 token 计约 42 个 token。状态变化的卡片会在下一次请求追加一条简短通知。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@ A turn shows at most one card across every card skill. When the user asks for se
|
||||
|
||||
## Offer without enabling
|
||||
|
||||
To offer, call `propose_action` once, in the same turn as loading this skill, with `action: "enable_official_plugin"`, `title` set to the plugin's catalog title in the user's language, `brief` set to one sentence in the user's language that ties the plugin to their need, and `details` holding `name`, the exact catalog name. The call is the submission: the card appears below your answer; a refused call creates no card, and its error says why. Then write your final answer: answer any direct question and add at most one short invitation such as “点击下方启用即可。”; never write the invitation without an accepted call. Do not narrate the call, repeat the catalog description, add setup steps the catalog does not state, claim the plugin is enabled, or ask the user to report back. The card opens the plugin's details; enabling applies to every conversation and can be undone there. The user's choice reaches you later as a status notice; enabling a plugin authorizes nothing beyond it.
|
||||
To offer, call `propose_action` once, in the same turn as loading this skill, with `action: "enable_official_plugin"`, `title` set to the plugin's catalog title in the user's language, `brief` set to one sentence in the user's language that ties the plugin to their need, and `details` holding `name`, the exact catalog name. The call is the submission: the card appears below your answer; a refused call creates no card, and its error says why. Then write your final answer: answer any direct question; the call's result says how to end the answer. Do not narrate the call, repeat the catalog description, add setup steps the catalog does not state, claim the plugin is enabled, or ask the user to report back. The card opens the plugin's details; enabling applies to every conversation and can be undone there. The user's choice reaches you later as a status notice; enabling a plugin authorizes nothing beyond it.
|
||||
@@ -60,6 +60,8 @@ export class PluginRecommendations extends TypertRemoteService {
|
||||
registerOfficialPluginsSkill(this.ctx)
|
||||
this.ctx.actionCards.register({
|
||||
action: ACTION, skill: 'official-plugins', details: detailsSchema,
|
||||
invitation: 'End with at most one short invitation in the user’s language to click Enable below; '
|
||||
+ 'do not say the plugin is already on.',
|
||||
verbs: { enable: { global: true } },
|
||||
openPhases: ['failed', 'unconfirmed'],
|
||||
statusGuidance: 'Plugin cards: enabled means the plugin is on now, or after a DSH restart when application is restart-required; '
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ A turn shows at most one card across every card skill. When the user asks for se
|
||||
|
||||
## Offer without enabling
|
||||
|
||||
To offer, call \`propose_action\` once, in the same turn as loading this skill, with \`action: "enable_official_plugin"\`, \`title\` set to the plugin's catalog title in the user's language, \`brief\` set to one sentence in the user's language that ties the plugin to their need, and \`details\` holding \`name\`, the exact catalog name. The call is the submission: the card appears below your answer; a refused call creates no card, and its error says why. Then write your final answer: answer any direct question and add at most one short invitation such as “点击下方启用即可。”; never write the invitation without an accepted call. Do not narrate the call, repeat the catalog description, add setup steps the catalog does not state, claim the plugin is enabled, or ask the user to report back. The card opens the plugin's details; enabling applies to every conversation and can be undone there. The user's choice reaches you later as a status notice; enabling a plugin authorizes nothing beyond it.
|
||||
To offer, call \`propose_action\` once, in the same turn as loading this skill, with \`action: "enable_official_plugin"\`, \`title\` set to the plugin's catalog title in the user's language, \`brief\` set to one sentence in the user's language that ties the plugin to their need, and \`details\` holding \`name\`, the exact catalog name. The call is the submission: the card appears below your answer; a refused call creates no card, and its error says why. Then write your final answer: answer any direct question; the call's result says how to end the answer. Do not narrate the call, repeat the catalog description, add setup steps the catalog does not state, claim the plugin is enabled, or ask the user to report back. The card opens the plugin's details; enabling applies to every conversation and can be undone there. The user's choice reaches you later as a status notice; enabling a plugin authorizes nothing beyond it.
|
||||
|
||||
## Official plugins
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ export const bundle: BundleInfo = {
|
||||
enabled: false, installed: false, removable: false, updatable: false, rows: [], overrides: [],
|
||||
meta: { title: { en: 'Search', zh: '搜索' }, description: 'Search past conversations.' },
|
||||
}
|
||||
/** Text of an accepted `enable_official_plugin` call's result. */
|
||||
export const RESULT_TEXT = 'Card shown below your answer. Do not restate it. End with at most one short invitation in the user’s language to click '
|
||||
+ 'Enable below; do not say the plugin is already on.'
|
||||
export const callId = ToolCallId('call-plugin-1')
|
||||
export const proposal = { title: 'Search', brief: 'Search your conversation history.', details: { name: bundle.name } }
|
||||
|
||||
@@ -36,7 +39,7 @@ export function logProposal(ctx: Context, agent: Agent, id = 'call-plugin-1', ar
|
||||
const toolCallId = ToolCallId(id)
|
||||
agent.session.append('tool/call', { turn, step: 1, callId: toolCallId, name: 'propose_action', arguments: JSON.stringify({ action, ...args }) })
|
||||
agent.session.append('tool/result', { turn, step: 1, message: createToolResultMessage({ callId: toolCallId,
|
||||
content: [{ type: 'text', text: 'Card shown below your answer.' }], isError: false }) }, { surfaceOp: 'append' })
|
||||
content: [{ type: 'text', text: RESULT_TEXT }], isError: false }) }, { surfaceOp: 'append' })
|
||||
return toolCallId
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, expect, it, onTestFinished, vi } from 'vitest'
|
||||
import { ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
import { createUserMessage, ToolCallId } from '@deepseek-ai/dsh-llm'
|
||||
import { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import { executeToolFixture } from '@deepseek-ai/dsh-tool-testkit'
|
||||
import type { BundleInfo, ChangeResult } from '@deepseek-ai/dsh-plugin-manager/types'
|
||||
import { MockAdapter, textResponse, toolCallResponse } from '../../../core/agent-loop/tests/mock-adapter.ts'
|
||||
import * as PluginRecommendations from '../src/index.ts'
|
||||
import { ACTION, bundle, callId, fixture, logProposal, proposal } from './fixture.ts'
|
||||
import { ACTION, bundle, callId, fixture, logProposal, proposal, RESULT_TEXT } from './fixture.ts'
|
||||
|
||||
describe('official recommendations', () => {
|
||||
it('offers the live catalog through a skill, adds no tools of its own, and withdraws the skill and card kind on unload', async () => {
|
||||
@@ -40,6 +42,25 @@ describe('official recommendations', () => {
|
||||
expect(f.manager.setBundleEnabled).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('ends an accepted card call with the invitation to click Enable, and a refused call without it', async () => {
|
||||
const f = await fixture()
|
||||
const adapter = new MockAdapter([
|
||||
toolCallResponse('call-skill', 'skill', { name: 'official-plugins' }),
|
||||
toolCallResponse('call-card', 'propose_action', { action: ACTION, ...proposal }),
|
||||
toolCallResponse('call-again', 'propose_action', { action: ACTION, ...proposal }),
|
||||
textResponse('Search is one click away.'),
|
||||
])
|
||||
f.ctx.llm.registerAdapter(['mock'], adapter)
|
||||
const agent = await f.ctx.agentLoop.create(SessionId('invitation'), { provider: 'mock', model: 'mock' })
|
||||
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'Can DSH search my old conversations?' }], source: { kind: 'user' } }))
|
||||
await agent.whenIdle()
|
||||
const results = agent.session.snapshotEvents().flatMap(event => event.type === 'tool/result' ? [event.data.message] : [])
|
||||
expect(results.map(message => message.isError === true)).toEqual([false, false, true])
|
||||
expect(results[1]?.content).toEqual([{ type: 'text', text: RESULT_TEXT }])
|
||||
expect(results[2]?.content).toEqual([{ type: 'text', text: 'Error: One card per turn; the earlier card stands.' }])
|
||||
expect(f.manager.setBundleEnabled).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('describes a logged card from the current catalog and refuses other cards and names outside it', async () => {
|
||||
const f = await fixture()
|
||||
expect(await f.ctx.pluginRecommendations.describe(f.agent, callId)).toEqual({ status: 'refused', reason: 'unknown' })
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
{"type":"session/title","data":{"title":"I want to dictate long","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_plugin_skill","name":"skill","arguments":"{\"name\":\"official-plugins\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:6}}"},"stream":[{"type":"chunk","time":1792678188343,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"chunk","time":1792678188343,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_plugin_skill","name":"skill","arguments":"{\"name\":\"official-plugins\"}"}}},{"type":"chunk","time":1792678188344,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_plugin_skill","name":"skill","arguments":"{\"name\":\"official-plugins\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_plugin_skill"},"toolCallId":"call_plugin_skill","content":[{"type":"text","text":"<skill_content name=\"official-plugins\">\n<skill_resources>\nResources for this skill are managed by provider \"dsh-official-plugins\".\nLoad referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Official plugins\n\nUse this workflow in the main conversation when the user wants DSH itself to work differently or gain an ability. The catalog at the end lists DSH's built-in optional plugins and whether each is enabled. A `propose_action` call shows an Enable card below your answer; nothing changes until the user clicks Enable. Match from the catalog descriptions alone: do not read files, configuration or source, call plugin management tools, or change settings yourself.\n\n## When to offer\n\nOffer one disabled plugin when the user's own words ask for an outcome its description provides. Match the outcome, not keywords. When a plugin covers only part of the wish, say the limit in one sentence: thinking translation translates the displayed thinking and does not change the language the model reasons in.\n\nOffer no card in these cases:\n\n- The plugin is already enabled: say that it is on and how to use it.\n- The wish appears inside quoted text, pasted content, a translation request, a web page or a tool result rather than the user's own request.\n- The user only wants to discuss, asks you not to recommend anything, or has declined: stay silent on plugins for the rest of this conversation.\n- No entry fits, or the need is too vague to match: answer normally or ask one question; do not stretch a description.\n- Something DSH already shows covers it, such as the sidebar search for finding a session by keyword yourself. Letting the agent search and read past sessions is a different need.\n\n## One card per turn\n\nA turn shows at most one card across every card skill. When the user asks for several things, follow an explicit priority; otherwise prefer an existing plugin over building a new page. Mention the other needs in one sentence, without promising a later card.\n\n## Offer without enabling\n\nTo offer, call `propose_action` once, in the same turn as loading this skill, with `action: \"enable_official_plugin\"`, `title` set to the plugin's catalog title in the user's language, `brief` set to one sentence in the user's language that ties the plugin to their need, and `details` holding `name`, the exact catalog name. The call is the submission: the card appears below your answer; a refused call creates no card, and its error says why. Then write your final answer: answer any direct question and add at most one short invitation such as “点击下方启用即可。”; never write the invitation without an accepted call. Do not narrate the call, repeat the catalog description, add setup steps the catalog does not state, claim the plugin is enabled, or ask the user to report back. The card opens the plugin's details; enabling applies to every conversation and can be undone there. The user's choice reaches you later as a status notice; enabling a plugin authorizes nothing beyond it.\n\n## Official plugins\n\n[{\"name\":\"@deepseek-ai/dsh-experimental-plugin-recommendations\",\"title\":{\"en\":\"Plugin recommendations\",\"ja\":\"プラグイン推薦\",\"zh\":\"插件推荐\"},\"description\":{\"en\":\"Discover built-in plugins for needs you describe when you are unsure which features are available. An Enable card appears after the answer; activation requires your click.\",\"ja\":\"どの機能が使えるか分からないとき、あなたが述べたニーズに合う内蔵プラグインを推薦します。回答の後に有効化カードが表示され、有効化にはクリックが必要です。\",\"zh\":\"不清楚现有哪些功能可用时,根据你明确表达的需求推荐内置插件,并在对话末尾提供启用卡片;由你点击后开启。\"},\"enabled\":true},{\"name\":\"@deepseek-ai/dsh-experimental-agent-team-profile\",\"title\":{\"en\":\"Agent teams\",\"ja\":\"エージェントチーム\",\"zh\":\"智能体团队\"},\"description\":{\"en\":\"Enable team collaboration, team tools, the member roster, and the shared task board.\",\"ja\":\"チーム連携、チームツール、メンバー一覧、共有タスクボードを有効にします。\",\"zh\":\"启用团队协作、团队工具、成员列表和共享任务看板。\"},\"enabled\":false},{\"name\":\"@deepseek-ai/dsh-experimental-inspector-profile\",\"title\":{\"en\":\"Developer tools\",\"ja\":\"開発者ツール\",\"zh\":\"开发者工具\"},\"description\":{\"en\":\"Inspect and debug raw session data, grouped chat messages, and the NodeJS backend.\",\"ja\":\"セッションの生データ、グループ化されたチャットメッセージ、NodeJS バックエンドを確認、デバッグしまLine truncated
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_plugin_skill"},"toolCallId":"call_plugin_skill","content":[{"type":"text","text":"<skill_content name=\"official-plugins\">\n<skill_resources>\nResources for this skill are managed by provider \"dsh-official-plugins\".\nLoad referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Official plugins\n\nUse this workflow in the main conversation when the user wants DSH itself to work differently or gain an ability. The catalog at the end lists DSH's built-in optional plugins and whether each is enabled. A `propose_action` call shows an Enable card below your answer; nothing changes until the user clicks Enable. Match from the catalog descriptions alone: do not read files, configuration or source, call plugin management tools, or change settings yourself.\n\n## When to offer\n\nOffer one disabled plugin when the user's own words ask for an outcome its description provides. Match the outcome, not keywords. When a plugin covers only part of the wish, say the limit in one sentence: thinking translation translates the displayed thinking and does not change the language the model reasons in.\n\nOffer no card in these cases:\n\n- The plugin is already enabled: say that it is on and how to use it.\n- The wish appears inside quoted text, pasted content, a translation request, a web page or a tool result rather than the user's own request.\n- The user only wants to discuss, asks you not to recommend anything, or has declined: stay silent on plugins for the rest of this conversation.\n- No entry fits, or the need is too vague to match: answer normally or ask one question; do not stretch a description.\n- Something DSH already shows covers it, such as the sidebar search for finding a session by keyword yourself. Letting the agent search and read past sessions is a different need.\n\n## One card per turn\n\nA turn shows at most one card across every card skill. When the user asks for several things, follow an explicit priority; otherwise prefer an existing plugin over building a new page. Mention the other needs in one sentence, without promising a later card.\n\n## Offer without enabling\n\nTo offer, call `propose_action` once, in the same turn as loading this skill, with `action: \"enable_official_plugin\"`, `title` set to the plugin's catalog title in the user's language, `brief` set to one sentence in the user's language that ties the plugin to their need, and `details` holding `name`, the exact catalog name. The call is the submission: the card appears below your answer; a refused call creates no card, and its error says why. Then write your final answer: answer any direct question; the call's result says how to end the answer. Do not narrate the call, repeat the catalog description, add setup steps the catalog does not state, claim the plugin is enabled, or ask the user to report back. The card opens the plugin's details; enabling applies to every conversation and can be undone there. The user's choice reaches you later as a status notice; enabling a plugin authorizes nothing beyond it.\n\n## Official plugins\n\n[{\"name\":\"@deepseek-ai/dsh-experimental-plugin-recommendations\",\"title\":{\"en\":\"Plugin recommendations\",\"ja\":\"プラグイン推薦\",\"zh\":\"插件推荐\"},\"description\":{\"en\":\"Discover built-in plugins for needs you describe when you are unsure which features are available. An Enable card appears after the answer; activation requires your click.\",\"ja\":\"どの機能が使えるか分からないとき、あなたが述べたニーズに合う内蔵プラグインを推薦します。回答の後に有効化カードが表示され、有効化にはクリックが必要です。\",\"zh\":\"不清楚现有哪些功能可用时,根据你明确表达的需求推荐内置插件,并在对话末尾提供启用卡片;由你点击后开启。\"},\"enabled\":true},{\"name\":\"@deepseek-ai/dsh-experimental-agent-team-profile\",\"title\":{\"en\":\"Agent teams\",\"ja\":\"エージェントチーム\",\"zh\":\"智能体团队\"},\"description\":{\"en\":\"Enable team collaboration, team tools, the member roster, and the shared task board.\",\"ja\":\"チーム連携、チームツール、メンバー一覧、共有タスクボードを有効にします。\",\"zh\":\"启用团队协作、团队工具、成员列表和共享任务看板。\"},\"enabled\":false},{\"name\":\"@deepseek-ai/dsh-experimental-inspector-profile\",\"title\":{\"en\":\"Developer tools\",\"ja\":\"開発者ツール\",\"zh\":\"开发者工具\"},\"description\":{\"en\":\"Inspect and debug raw session data, grouped chat messages, and the NodeJS backend.\",\"ja\":\"セッションの生データ、グループ化されたチャットメッセージ、NodeJS バックエンドを確認、デバッグします。\",\"zh\":\"查看调试会话原始数据、聊天消息分组数据,以及Line truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":["ask_user_question","bash","create_goal","edit","get_goal","glob","grep","interrupt_agent","job_kill","job_list","job_output","list_agents","list_subagent_models","plugin_manager","present","propose_action","read","read_image","schedule_create","schedule_delete","schedule_list","schedule_update","send_message","skill","subagent","subagent_fork","todo_write","update_goal","web_fetch","web_search","workflow","working_directory","write"]},"reason":"change"}}
|
||||
{"type":"developer/message","data":{"turn":1,"step":2,"message":{"source":{"kind":"tool-registry"},"content":[{"type":"tool-addition","toolName":"propose_action"}],"role":"developer","id":"{{message:8}}"},"headerSeq":20},"surfaceOp":"append"}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_plugin_card","name":"propose_action","arguments":"{\"action\":\"enable_official_plugin\",\"title\":\"Voice input\",\"brief\":\"Speak long requests instead of typing them; transcription runs on this computer.\",\"details\":{\"name\":\"@deepseek-ai/dsh-experimental-voice-input-bundle\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:9}}"},"stream":[{"type":"chunk","time":1792678188573,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"chunk","time":1792678188573,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_plugin_card","name":"propose_action","arguments":"{\"action\":\"enable_official_plugin\",\"title\":\"Voice input\",\"brief\":\"Speak long requests instead of typing them; transcription runs on this computer.\",\"details\":{\"name\":\"@deepseek-ai/dsh-experimental-voice-input-bundle\"}}"}}},{"type":"chunk","time":1792678188573,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"call_plugin_card","name":"propose_action","arguments":"{\"action\":\"enable_official_plugin\",\"title\":\"Voice input\",\"brief\":\"Speak long requests instead of typing them; transcription runs on this computer.\",\"details\":{\"name\":\"@deepseek-ai/dsh-experimental-voice-input-bundle\"}}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_plugin_card"},"toolCallId":"call_plugin_card","content":[{"type":"text","text":"Card shown below your answer. Do not restate it; end with one short invitation."}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[23],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"role":"tool","source":{"kind":"tool","callId":"call_plugin_card"},"toolCallId":"call_plugin_card","content":[{"type":"text","text":"Card shown below your answer. Do not restate it. End with at most one short invitation in the user’s language to click Enable below; do not say the plugin is already on."}],"isError":false,"id":"{{message:10}}"}},"sourceEventSeqs":[23],"surfaceOp":"append"}
|
||||
{"type":"step/end","data":{"turn":1,"step":2}}
|
||||
{"type":"step/start","data":{"turn":1,"step":3}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"text","text":"Voice input transcribes your recordings locally into the composer. You can enable it below."}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:11}}"},"stream":[{"type":"chunk","time":1792678188601,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1792678188601,"index":0,"dt":[],"texts":["Voice input transcribes your recordings locally into the composer. You can enable it below."]},{"type":"chunk","time":1792678188601,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"Voice input transcribes your recordings locally into the composer. You can enable it below."}}},{"type":"chunk","time":1792678188601,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
|
||||
Reference in new issue
Block a user