@anionex/dsh-tool-search 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +4 -5
- package/README.zh.md +4 -5
- package/docs/benchmark-results.json +1 -1
- package/lib/client.js +3 -2
- package/lib/client.js.map +1 -1
- package/lib/shared.js +0 -1
- package/lib/shared.js.map +1 -1
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/shared.d.ts +1 -1
- package/lib/types/shared.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/profile-e2e.mjs +23 -10
- package/scripts/validate.mjs +1 -1
- package/src/client/index.tsx +5 -1
- package/src/shared.ts +0 -1
- package/tests/client.spec.tsx +10 -1
- package/tests/settings.spec.ts +1 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -29,13 +29,12 @@ The initial native schema surface contains:
|
|
|
29
29
|
- DSH core tools maintained in `DEFAULT_CORE_TOOLS`
|
|
30
30
|
- exact names added to `alwaysVisible`
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The default policy treats these names as core:
|
|
33
33
|
|
|
34
34
|
```text
|
|
35
|
-
apply_patch, ask_user_question, bash, create_goal,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
todo_write, update_goal, workflow
|
|
35
|
+
apply_patch, ask_user_question, bash, create_goal, exit_plan_mode, get_goal,
|
|
36
|
+
interrupt_agent, job_kill, job_list, job_output, list_agents, ralph, report,
|
|
37
|
+
send_message, skill, subagent, subagent_fork, todo_write, update_goal, workflow
|
|
39
38
|
```
|
|
40
39
|
|
|
41
40
|
Every other registered tool is searchable but initially omitted. `neverSearch` hides a name from both the initial surface and the search corpus; it wins a conflict with `alwaysVisible`. `tool_search` itself cannot be blacklisted, preventing a configuration dead end.
|
package/README.zh.md
CHANGED
|
@@ -29,13 +29,12 @@ dsh plugin --profile web add @anionex/dsh-tool-search
|
|
|
29
29
|
- `DEFAULT_CORE_TOOLS` 中维护的 DSH 核心工具
|
|
30
30
|
- `alwaysVisible` 中配置的精确名称
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
默认策略把以下名称视为核心工具:
|
|
33
33
|
|
|
34
34
|
```text
|
|
35
|
-
apply_patch, ask_user_question, bash, create_goal,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
todo_write, update_goal, workflow
|
|
35
|
+
apply_patch, ask_user_question, bash, create_goal, exit_plan_mode, get_goal,
|
|
36
|
+
interrupt_agent, job_kill, job_list, job_output, list_agents, ralph, report,
|
|
37
|
+
send_message, skill, subagent, subagent_fork, todo_write, update_goal, workflow
|
|
39
38
|
```
|
|
40
39
|
|
|
41
40
|
其他已注册工具都可搜索,但默认不显示。`neverSearch` 同时从初始集合和搜索语料中隐藏名称,并在与 `alwaysVisible` 冲突时优先。`tool_search` 自身不能被拉黑,避免配置后无工具可发现。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"packageVersion": "0.1.
|
|
3
|
+
"packageVersion": "0.1.1",
|
|
4
4
|
"tokenizer": "gpt-tokenizer 4.0.0 (o200k_base default encode)",
|
|
5
5
|
"fixture": {
|
|
6
6
|
"description": "Deterministic nested function schemas; full surface versus tool_search-only initial surface.",
|
package/lib/client.js
CHANGED
|
@@ -20,7 +20,6 @@ const DEFAULT_CORE_TOOLS = Object.freeze([
|
|
|
20
20
|
"ask_user_question",
|
|
21
21
|
"bash",
|
|
22
22
|
"create_goal",
|
|
23
|
-
"dsh_im_return_file",
|
|
24
23
|
"exit_plan_mode",
|
|
25
24
|
"get_goal",
|
|
26
25
|
"interrupt_agent",
|
|
@@ -60,6 +59,7 @@ const en = {
|
|
|
60
59
|
selected: "Live agents",
|
|
61
60
|
defaultPolicy: "Default",
|
|
62
61
|
alwaysPolicy: "Always",
|
|
62
|
+
deferredPolicy: "Deferred",
|
|
63
63
|
blockedPolicy: "Blocked",
|
|
64
64
|
loading: "Loading...",
|
|
65
65
|
empty: "No matching tools",
|
|
@@ -79,6 +79,7 @@ const zh = {
|
|
|
79
79
|
selected: "活跃 Agent",
|
|
80
80
|
defaultPolicy: "默认",
|
|
81
81
|
alwaysPolicy: "常驻",
|
|
82
|
+
deferredPolicy: "延迟",
|
|
82
83
|
blockedPolicy: "禁用",
|
|
83
84
|
loading: "加载中...",
|
|
84
85
|
empty: "没有匹配工具",
|
|
@@ -313,7 +314,7 @@ function ToolSearchSettingsSection({ scope, t }) {
|
|
|
313
314
|
children: [
|
|
314
315
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
315
316
|
value: "default",
|
|
316
|
-
children:
|
|
317
|
+
children: `${translate("defaultPolicy")} (${translate(core.has(tool.name) ? "alwaysPolicy" : "deferredPolicy")})`
|
|
317
318
|
}),
|
|
318
319
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
319
320
|
value: "always",
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useCallback","useState","useMemo"],"sources":["../src/shared.ts","../src/client/index.tsx"],"sourcesContent":["/** Values shared by the Host runtime and Web settings client. */\n\nexport const TOOL_SEARCH_NAME = 'tool_search'\nexport const TOOL_SEARCH_SETTINGS_NAMESPACE = 'tool-search'\nexport const TOOL_SEARCH_CATALOG_ROUTE = '/_dsh/tool-search/catalog'\nexport const DEFAULT_RESULT_LIMIT = 5\nexport const MAX_RESULT_LIMIT = 20\n\n/**\n * Stable bootstrap surface for current DSH releases. Unknown future first-party\n * names are deferred until this list or the user allowlist is updated because\n * ToolDefinition does not expose package provenance.\n */\nexport const DEFAULT_CORE_TOOLS = Object.freeze([\n 'apply_patch',\n 'ask_user_question',\n 'bash',\n 'create_goal',\n 'dsh_im_return_file',\n 'exit_plan_mode',\n 'get_goal',\n 'interrupt_agent',\n 'job_kill',\n 'job_list',\n 'job_output',\n 'list_agents',\n 'ralph',\n 'report',\n 'send_message',\n 'skill',\n 'subagent',\n 'subagent_fork',\n 'todo_write',\n 'update_goal',\n 'workflow',\n] as const)\n\nexport interface ToolSearchSettings {\n defaultLimit: number\n alwaysVisible: string[]\n neverSearch: string[]\n}\n\nexport const DEFAULT_SETTINGS: Readonly<ToolSearchSettings> = Object.freeze({\n defaultLimit: DEFAULT_RESULT_LIMIT,\n alwaysVisible: [],\n neverSearch: [],\n})\n\nexport type ToolPolicy = 'always' | 'deferred' | 'blocked'\n\nexport interface CatalogToolSummary {\n name: string\n description: string\n policy: ToolPolicy\n selectedBy: string[]\n}\n\nexport interface CatalogSnapshot {\n schemaVersion: 1\n generation: number\n tools: CatalogToolSummary[]\n}\n","/** DSH Web settings surface for deferred tool policy. */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react'\nimport {\n DEFAULT_CORE_TOOLS,\n DEFAULT_RESULT_LIMIT,\n MAX_RESULT_LIMIT,\n TOOL_SEARCH_CATALOG_ROUTE,\n TOOL_SEARCH_NAME,\n TOOL_SEARCH_SETTINGS_NAMESPACE,\n type CatalogSnapshot,\n type ToolPolicy,\n type ToolSearchSettings,\n} from '../shared.ts'\n\ninterface SettingsScopeSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n writable: boolean\n}\n\ninterface SettingsScope<T> {\n getSnapshot(): SettingsScopeSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n}\n\ntype Disposer = () => void\n\ninterface ClientContext {\n effect(setup: () => Disposer | void, label: string): void\n locale: {\n register(namespace: string, catalogs: Record<string, Record<string, string>>): Disposer\n bind(namespace: string): (key: string) => string\n }\n settingsScope: {\n bind<T>(options: { namespace: string }): SettingsScope<T>\n }\n slots: {\n inject(name: string, callback: () => Disposer): Disposer\n register<P>(\n options: {\n name: string\n id: string\n order: number\n label: () => string\n inject: () => P\n },\n component: (props: P) => ReactNode,\n ): Disposer\n }\n}\n\ntype Translate = (key: keyof typeof en) => string\n\nconst en = {\n nav: 'Tool Search',\n topK: 'Default results',\n alwaysVisible: 'Always visible',\n neverSearch: 'Never searchable',\n catalog: 'Tool catalog',\n filter: 'Filter tools',\n refresh: 'Refresh',\n tool: 'Tool',\n policy: 'Policy',\n selected: 'Live agents',\n defaultPolicy: 'Default',\n alwaysPolicy: 'Always',\n blockedPolicy: 'Blocked',\n loading: 'Loading...',\n empty: 'No matching tools',\n saved: 'Saved',\n onePerLine: 'One exact tool name per line',\n}\n\nconst zh: typeof en = {\n nav: '工具搜索',\n topK: '默认结果数',\n alwaysVisible: '常驻白名单',\n neverSearch: '搜索黑名单',\n catalog: '工具目录',\n filter: '筛选工具',\n refresh: '刷新',\n tool: '工具',\n policy: '策略',\n selected: '活跃 Agent',\n defaultPolicy: '默认',\n alwaysPolicy: '常驻',\n blockedPolicy: '禁用',\n loading: '加载中...',\n empty: '没有匹配工具',\n saved: '已保存',\n onePerLine: '每行一个精确工具名',\n}\n\nconst EMPTY_SETTINGS: SettingsScopeSnapshot<ToolSearchSettings> = {\n status: 'unavailable',\n value: undefined,\n writable: false,\n}\n\nconst styles = `\n.dts-settings{container-type:inline-size;display:flex;flex-direction:column;gap:20px;width:100%;min-width:0;color:var(--dsw-alias-label-primary)}\n.dts-toolbar{display:grid;grid-template-columns:minmax(160px,220px) minmax(220px,1fr) auto;align-items:end;gap:12px}\n.dts-field{display:flex;flex-direction:column;gap:6px;min-width:0}\n.dts-field>span,.dts-section-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}\n.dts-input,.dts-textarea,.dts-select{box-sizing:border-box;width:100%;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit}\n.dts-input,.dts-select{height:34px;padding:0 9px}.dts-textarea{min-height:104px;padding:8px 9px;resize:vertical;line-height:20px}\n.dts-input:focus,.dts-textarea:focus,.dts-select:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dts-lists{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}\n.dts-hint{font-size:11px;color:var(--dsw-alias-label-tertiary)}\n.dts-button{height:34px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer}\n.dts-button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dts-button:disabled{opacity:.5;cursor:not-allowed}\n.dts-status{min-height:18px;font-size:12px;color:var(--dsw-alias-label-secondary)}.dts-status[data-error=true]{color:var(--dsw-alias-state-error-primary)}\n.dts-table-wrap{min-width:0;overflow:auto;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2)}\n.dts-table{width:100%;min-width:620px;border-collapse:collapse;table-layout:fixed}\n.dts-table th,.dts-table td{box-sizing:border-box;padding:9px 10px;border-bottom:1px solid var(--dsw-alias-border-l1);text-align:left;vertical-align:middle;font-size:12px}\n.dts-table th{position:sticky;top:0;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-weight:600}\n.dts-table tr:last-child td{border-bottom:0}.dts-tool{width:52%}.dts-tool code{display:block;overflow:hidden;text-overflow:ellipsis;overflow-wrap:anywhere;white-space:nowrap;color:var(--dsw-alias-label-primary)}\n.dts-description{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary)}\n.dts-policy{width:26%}.dts-selected{width:22%;color:var(--dsw-alias-label-secondary)}\n@container(max-width:620px){.dts-toolbar{grid-template-columns:1fr auto}.dts-toolbar .dts-limit{grid-column:1/-1}.dts-lists{grid-template-columns:1fr}.dts-table{min-width:0}.dts-table thead{display:none}.dts-table tr{display:grid;grid-template-columns:minmax(0,1fr) 132px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border-l1)}.dts-table td{padding:4px 0;border:0}.dts-table .dts-tool,.dts-table .dts-policy{width:auto}.dts-table .dts-selected{grid-column:1/-1;width:auto;font-size:11px}.dts-table .dts-selected::before{content:attr(data-label) \": \";color:var(--dsw-alias-label-tertiary);font-weight:600}}\n`\n\nfunction namesFromText(value: string): string[] {\n return [...new Set(value.split(/\\r?\\n/u).map(name => name.trim()).filter(Boolean))].sort()\n}\n\nfunction overrideFor(name: string, settings: ToolSearchSettings): ToolPolicy | 'default' {\n if (settings.neverSearch.includes(name)) return 'blocked'\n if (settings.alwaysVisible.includes(name)) return 'always'\n return 'default'\n}\n\nfunction decodeCatalog(value: unknown): CatalogSnapshot {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('Invalid catalog response')\n const record = value as Record<string, unknown>\n if (record['schemaVersion'] !== 1 || !Array.isArray(record['tools']) || typeof record['generation'] !== 'number') {\n throw new Error('Invalid catalog response')\n }\n return value as CatalogSnapshot\n}\n\ntype SettingsProps = {\n scope?: SettingsScope<ToolSearchSettings>\n t?: Translate\n}\n\nexport function ToolSearchSettingsSection({ scope, t }: SettingsProps): ReactNode {\n const snapshot = useSyncExternalStore(\n useCallback((notify: () => void) => scope?.subscribe(notify) ?? (() => {}), [scope]),\n useCallback(() => scope?.getSnapshot() ?? EMPTY_SETTINGS, [scope]),\n )\n const [catalog, setCatalog] = useState<CatalogSnapshot>()\n const [filter, setFilter] = useState('')\n const [alwaysText, setAlwaysText] = useState('')\n const [blockedText, setBlockedText] = useState('')\n const [limitText, setLimitText] = useState(String(DEFAULT_RESULT_LIMIT))\n const [status, setStatus] = useState<{ text: string; error: boolean }>()\n const translate = t ?? ((key: keyof typeof en) => en[key])\n const settings = snapshot.value\n\n const refresh = useCallback(async (): Promise<void> => {\n try {\n const response = await fetch(TOOL_SEARCH_CATALOG_ROUTE, { cache: 'no-store' })\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n setCatalog(decodeCatalog(await response.json()))\n setStatus(undefined)\n } catch (error) {\n setStatus({ text: error instanceof Error ? error.message : String(error), error: true })\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n useEffect(() => {\n if (settings === undefined) return\n setAlwaysText(settings.alwaysVisible.join('\\n'))\n setBlockedText(settings.neverSearch.join('\\n'))\n setLimitText(String(settings.defaultLimit))\n }, [settings])\n\n const commit = useCallback((field: keyof ToolSearchSettings, value: unknown): void => {\n if (scope === undefined || !snapshot.writable) return\n setStatus(undefined)\n void scope.set(field, value).then(() => {\n setStatus({ text: translate('saved'), error: false })\n void refresh()\n }, error => {\n setStatus({ text: error instanceof Error ? error.message : String(error), error: true })\n })\n }, [refresh, scope, snapshot.writable, translate])\n\n const visibleTools = useMemo(() => {\n const query = filter.trim().toLowerCase()\n if (query.length === 0) return catalog?.tools ?? []\n return (catalog?.tools ?? []).filter(tool =>\n tool.name.toLowerCase().includes(query) || tool.description.toLowerCase().includes(query),\n )\n }, [catalog, filter])\n\n const changePolicy = (name: string, next: ToolPolicy | 'default'): void => {\n if (settings === undefined || name === TOOL_SEARCH_NAME) return\n const always = new Set(settings.alwaysVisible)\n const blocked = new Set(settings.neverSearch)\n always.delete(name)\n blocked.delete(name)\n if (next === 'always') always.add(name)\n if (next === 'blocked') blocked.add(name)\n commit('alwaysVisible', [...always].sort())\n commit('neverSearch', [...blocked].sort())\n }\n\n const core = new Set<string>(DEFAULT_CORE_TOOLS)\n return <div className=\"dts-settings\">\n <div className=\"dts-toolbar\">\n <label className=\"dts-field dts-limit\">\n <span>{translate('topK')}</span>\n <input\n className=\"dts-input\"\n type=\"number\"\n min={1}\n max={MAX_RESULT_LIMIT}\n value={limitText}\n disabled={!snapshot.writable}\n onChange={event => setLimitText(event.target.value)}\n onBlur={() => {\n const value = Number.parseInt(limitText, 10)\n if (Number.isSafeInteger(value) && value >= 1 && value <= MAX_RESULT_LIMIT) commit('defaultLimit', value)\n else setLimitText(String(settings?.defaultLimit ?? DEFAULT_RESULT_LIMIT))\n }}\n />\n </label>\n <label className=\"dts-field\">\n <span>{translate('filter')}</span>\n <input className=\"dts-input\" type=\"search\" value={filter} onChange={event => setFilter(event.target.value)} />\n </label>\n <button className=\"dts-button\" type=\"button\" onClick={() => { void refresh() }}>{translate('refresh')}</button>\n </div>\n\n <div className=\"dts-lists\">\n <label className=\"dts-field\">\n <span>{translate('alwaysVisible')}</span>\n <textarea\n className=\"dts-textarea\"\n value={alwaysText}\n disabled={!snapshot.writable}\n placeholder={translate('onePerLine')}\n onChange={event => setAlwaysText(event.target.value)}\n onBlur={() => commit('alwaysVisible', namesFromText(alwaysText))}\n />\n </label>\n <label className=\"dts-field\">\n <span>{translate('neverSearch')}</span>\n <textarea\n className=\"dts-textarea\"\n value={blockedText}\n disabled={!snapshot.writable}\n placeholder={translate('onePerLine')}\n onChange={event => setBlockedText(event.target.value)}\n onBlur={() => commit('neverSearch', namesFromText(blockedText).filter(name => name !== TOOL_SEARCH_NAME))}\n />\n </label>\n </div>\n\n <section className=\"dts-field\">\n <div className=\"dts-section-title\">{translate('catalog')}</div>\n <div className=\"dts-table-wrap\">\n <table className=\"dts-table\">\n <thead><tr>\n <th className=\"dts-tool\">{translate('tool')}</th>\n <th className=\"dts-policy\">{translate('policy')}</th>\n <th className=\"dts-selected\">{translate('selected')}</th>\n </tr></thead>\n <tbody>\n {visibleTools.map(tool => <tr key={tool.name}>\n <td className=\"dts-tool\">\n <code title={tool.name}>{tool.name}</code>\n {tool.description.length > 0 ? <span className=\"dts-description\" title={tool.description}>{tool.description}</span> : null}\n </td>\n <td className=\"dts-policy\">\n <select\n className=\"dts-select\"\n aria-label={`${translate('policy')}: ${tool.name}`}\n value={tool.name === TOOL_SEARCH_NAME ? 'always' : overrideFor(tool.name, settings ?? {\n defaultLimit: DEFAULT_RESULT_LIMIT,\n alwaysVisible: [],\n neverSearch: [],\n })}\n disabled={!snapshot.writable || tool.name === TOOL_SEARCH_NAME}\n onChange={event => changePolicy(tool.name, event.target.value as ToolPolicy | 'default')}\n >\n <option value=\"default\">{core.has(tool.name) ? `${translate('defaultPolicy')} (${translate('alwaysPolicy')})` : translate('defaultPolicy')}</option>\n <option value=\"always\">{translate('alwaysPolicy')}</option>\n <option value=\"blocked\">{translate('blockedPolicy')}</option>\n </select>\n </td>\n <td\n className=\"dts-selected\"\n data-label={translate('selected')}\n aria-label={`${translate('selected')}: ${tool.selectedBy.length}`}\n >{tool.selectedBy.length}</td>\n </tr>)}\n {catalog !== undefined && visibleTools.length === 0\n ? <tr><td colSpan={3}>{translate('empty')}</td></tr>\n : null}\n </tbody>\n </table>\n </div>\n <div className=\"dts-status\" data-error={status?.error || undefined}>\n {status?.text ?? (catalog === undefined ? translate('loading') : '')}\n </div>\n </section>\n </div>\n}\n\nexport const inject = ['slots', 'locale', 'settingsScope']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n if (document.querySelector('style[data-plugin-css=\"@anionex/dsh-tool-search\"]') !== null) return () => {}\n const tag = document.createElement('style')\n tag.dataset.pluginCss = '@anionex/dsh-tool-search'\n tag.textContent = styles\n document.head.append(tag)\n return () => tag.remove()\n }, 'dsh-tool-search: styles')\n ctx.effect(() => ctx.locale.register('settings.toolSearch', { en, zh }), 'dsh-tool-search: locale')\n const t = ctx.locale.bind('settings.toolSearch') as Translate\n const scope = ctx.settingsScope.bind<ToolSearchSettings>({ namespace: TOOL_SEARCH_SETTINGS_NAMESPACE })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'tool-search',\n order: 34,\n label: () => t('nav'),\n inject: () => ({ scope, t }),\n }, ToolSearchSettingsSection))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useSyncExternalStore","useCallback","useState","useMemo"],"sources":["../src/shared.ts","../src/client/index.tsx"],"sourcesContent":["/** Values shared by the Host runtime and Web settings client. */\n\nexport const TOOL_SEARCH_NAME = 'tool_search'\nexport const TOOL_SEARCH_SETTINGS_NAMESPACE = 'tool-search'\nexport const TOOL_SEARCH_CATALOG_ROUTE = '/_dsh/tool-search/catalog'\nexport const DEFAULT_RESULT_LIMIT = 5\nexport const MAX_RESULT_LIMIT = 20\n\n/**\n * Stable bootstrap surface for current DSH releases. Unknown future first-party\n * names are deferred until this list or the user allowlist is updated because\n * ToolDefinition does not expose package provenance.\n */\nexport const DEFAULT_CORE_TOOLS = Object.freeze([\n 'apply_patch',\n 'ask_user_question',\n 'bash',\n 'create_goal',\n 'exit_plan_mode',\n 'get_goal',\n 'interrupt_agent',\n 'job_kill',\n 'job_list',\n 'job_output',\n 'list_agents',\n 'ralph',\n 'report',\n 'send_message',\n 'skill',\n 'subagent',\n 'subagent_fork',\n 'todo_write',\n 'update_goal',\n 'workflow',\n] as const)\n\nexport interface ToolSearchSettings {\n defaultLimit: number\n alwaysVisible: string[]\n neverSearch: string[]\n}\n\nexport const DEFAULT_SETTINGS: Readonly<ToolSearchSettings> = Object.freeze({\n defaultLimit: DEFAULT_RESULT_LIMIT,\n alwaysVisible: [],\n neverSearch: [],\n})\n\nexport type ToolPolicy = 'always' | 'deferred' | 'blocked'\n\nexport interface CatalogToolSummary {\n name: string\n description: string\n policy: ToolPolicy\n selectedBy: string[]\n}\n\nexport interface CatalogSnapshot {\n schemaVersion: 1\n generation: number\n tools: CatalogToolSummary[]\n}\n","/** DSH Web settings surface for deferred tool policy. */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react'\nimport {\n DEFAULT_CORE_TOOLS,\n DEFAULT_RESULT_LIMIT,\n MAX_RESULT_LIMIT,\n TOOL_SEARCH_CATALOG_ROUTE,\n TOOL_SEARCH_NAME,\n TOOL_SEARCH_SETTINGS_NAMESPACE,\n type CatalogSnapshot,\n type ToolPolicy,\n type ToolSearchSettings,\n} from '../shared.ts'\n\ninterface SettingsScopeSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n writable: boolean\n}\n\ninterface SettingsScope<T> {\n getSnapshot(): SettingsScopeSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n}\n\ntype Disposer = () => void\n\ninterface ClientContext {\n effect(setup: () => Disposer | void, label: string): void\n locale: {\n register(namespace: string, catalogs: Record<string, Record<string, string>>): Disposer\n bind(namespace: string): (key: string) => string\n }\n settingsScope: {\n bind<T>(options: { namespace: string }): SettingsScope<T>\n }\n slots: {\n inject(name: string, callback: () => Disposer): Disposer\n register<P>(\n options: {\n name: string\n id: string\n order: number\n label: () => string\n inject: () => P\n },\n component: (props: P) => ReactNode,\n ): Disposer\n }\n}\n\ntype Translate = (key: keyof typeof en) => string\n\nconst en = {\n nav: 'Tool Search',\n topK: 'Default results',\n alwaysVisible: 'Always visible',\n neverSearch: 'Never searchable',\n catalog: 'Tool catalog',\n filter: 'Filter tools',\n refresh: 'Refresh',\n tool: 'Tool',\n policy: 'Policy',\n selected: 'Live agents',\n defaultPolicy: 'Default',\n alwaysPolicy: 'Always',\n deferredPolicy: 'Deferred',\n blockedPolicy: 'Blocked',\n loading: 'Loading...',\n empty: 'No matching tools',\n saved: 'Saved',\n onePerLine: 'One exact tool name per line',\n}\n\nconst zh: typeof en = {\n nav: '工具搜索',\n topK: '默认结果数',\n alwaysVisible: '常驻白名单',\n neverSearch: '搜索黑名单',\n catalog: '工具目录',\n filter: '筛选工具',\n refresh: '刷新',\n tool: '工具',\n policy: '策略',\n selected: '活跃 Agent',\n defaultPolicy: '默认',\n alwaysPolicy: '常驻',\n deferredPolicy: '延迟',\n blockedPolicy: '禁用',\n loading: '加载中...',\n empty: '没有匹配工具',\n saved: '已保存',\n onePerLine: '每行一个精确工具名',\n}\n\nconst EMPTY_SETTINGS: SettingsScopeSnapshot<ToolSearchSettings> = {\n status: 'unavailable',\n value: undefined,\n writable: false,\n}\n\nconst styles = `\n.dts-settings{container-type:inline-size;display:flex;flex-direction:column;gap:20px;width:100%;min-width:0;color:var(--dsw-alias-label-primary)}\n.dts-toolbar{display:grid;grid-template-columns:minmax(160px,220px) minmax(220px,1fr) auto;align-items:end;gap:12px}\n.dts-field{display:flex;flex-direction:column;gap:6px;min-width:0}\n.dts-field>span,.dts-section-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}\n.dts-input,.dts-textarea,.dts-select{box-sizing:border-box;width:100%;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit}\n.dts-input,.dts-select{height:34px;padding:0 9px}.dts-textarea{min-height:104px;padding:8px 9px;resize:vertical;line-height:20px}\n.dts-input:focus,.dts-textarea:focus,.dts-select:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dts-lists{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}\n.dts-hint{font-size:11px;color:var(--dsw-alias-label-tertiary)}\n.dts-button{height:34px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer}\n.dts-button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dts-button:disabled{opacity:.5;cursor:not-allowed}\n.dts-status{min-height:18px;font-size:12px;color:var(--dsw-alias-label-secondary)}.dts-status[data-error=true]{color:var(--dsw-alias-state-error-primary)}\n.dts-table-wrap{min-width:0;overflow:auto;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2)}\n.dts-table{width:100%;min-width:620px;border-collapse:collapse;table-layout:fixed}\n.dts-table th,.dts-table td{box-sizing:border-box;padding:9px 10px;border-bottom:1px solid var(--dsw-alias-border-l1);text-align:left;vertical-align:middle;font-size:12px}\n.dts-table th{position:sticky;top:0;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-weight:600}\n.dts-table tr:last-child td{border-bottom:0}.dts-tool{width:52%}.dts-tool code{display:block;overflow:hidden;text-overflow:ellipsis;overflow-wrap:anywhere;white-space:nowrap;color:var(--dsw-alias-label-primary)}\n.dts-description{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary)}\n.dts-policy{width:26%}.dts-selected{width:22%;color:var(--dsw-alias-label-secondary)}\n@container(max-width:620px){.dts-toolbar{grid-template-columns:1fr auto}.dts-toolbar .dts-limit{grid-column:1/-1}.dts-lists{grid-template-columns:1fr}.dts-table{min-width:0}.dts-table thead{display:none}.dts-table tr{display:grid;grid-template-columns:minmax(0,1fr) 132px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border-l1)}.dts-table td{padding:4px 0;border:0}.dts-table .dts-tool,.dts-table .dts-policy{width:auto}.dts-table .dts-selected{grid-column:1/-1;width:auto;font-size:11px}.dts-table .dts-selected::before{content:attr(data-label) \": \";color:var(--dsw-alias-label-tertiary);font-weight:600}}\n`\n\nfunction namesFromText(value: string): string[] {\n return [...new Set(value.split(/\\r?\\n/u).map(name => name.trim()).filter(Boolean))].sort()\n}\n\nfunction overrideFor(name: string, settings: ToolSearchSettings): ToolPolicy | 'default' {\n if (settings.neverSearch.includes(name)) return 'blocked'\n if (settings.alwaysVisible.includes(name)) return 'always'\n return 'default'\n}\n\nfunction decodeCatalog(value: unknown): CatalogSnapshot {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('Invalid catalog response')\n const record = value as Record<string, unknown>\n if (record['schemaVersion'] !== 1 || !Array.isArray(record['tools']) || typeof record['generation'] !== 'number') {\n throw new Error('Invalid catalog response')\n }\n return value as CatalogSnapshot\n}\n\ntype SettingsProps = {\n scope?: SettingsScope<ToolSearchSettings>\n t?: Translate\n}\n\nexport function ToolSearchSettingsSection({ scope, t }: SettingsProps): ReactNode {\n const snapshot = useSyncExternalStore(\n useCallback((notify: () => void) => scope?.subscribe(notify) ?? (() => {}), [scope]),\n useCallback(() => scope?.getSnapshot() ?? EMPTY_SETTINGS, [scope]),\n )\n const [catalog, setCatalog] = useState<CatalogSnapshot>()\n const [filter, setFilter] = useState('')\n const [alwaysText, setAlwaysText] = useState('')\n const [blockedText, setBlockedText] = useState('')\n const [limitText, setLimitText] = useState(String(DEFAULT_RESULT_LIMIT))\n const [status, setStatus] = useState<{ text: string; error: boolean }>()\n const translate = t ?? ((key: keyof typeof en) => en[key])\n const settings = snapshot.value\n\n const refresh = useCallback(async (): Promise<void> => {\n try {\n const response = await fetch(TOOL_SEARCH_CATALOG_ROUTE, { cache: 'no-store' })\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n setCatalog(decodeCatalog(await response.json()))\n setStatus(undefined)\n } catch (error) {\n setStatus({ text: error instanceof Error ? error.message : String(error), error: true })\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n useEffect(() => {\n if (settings === undefined) return\n setAlwaysText(settings.alwaysVisible.join('\\n'))\n setBlockedText(settings.neverSearch.join('\\n'))\n setLimitText(String(settings.defaultLimit))\n }, [settings])\n\n const commit = useCallback((field: keyof ToolSearchSettings, value: unknown): void => {\n if (scope === undefined || !snapshot.writable) return\n setStatus(undefined)\n void scope.set(field, value).then(() => {\n setStatus({ text: translate('saved'), error: false })\n void refresh()\n }, error => {\n setStatus({ text: error instanceof Error ? error.message : String(error), error: true })\n })\n }, [refresh, scope, snapshot.writable, translate])\n\n const visibleTools = useMemo(() => {\n const query = filter.trim().toLowerCase()\n if (query.length === 0) return catalog?.tools ?? []\n return (catalog?.tools ?? []).filter(tool =>\n tool.name.toLowerCase().includes(query) || tool.description.toLowerCase().includes(query),\n )\n }, [catalog, filter])\n\n const changePolicy = (name: string, next: ToolPolicy | 'default'): void => {\n if (settings === undefined || name === TOOL_SEARCH_NAME) return\n const always = new Set(settings.alwaysVisible)\n const blocked = new Set(settings.neverSearch)\n always.delete(name)\n blocked.delete(name)\n if (next === 'always') always.add(name)\n if (next === 'blocked') blocked.add(name)\n commit('alwaysVisible', [...always].sort())\n commit('neverSearch', [...blocked].sort())\n }\n\n const core = new Set<string>(DEFAULT_CORE_TOOLS)\n return <div className=\"dts-settings\">\n <div className=\"dts-toolbar\">\n <label className=\"dts-field dts-limit\">\n <span>{translate('topK')}</span>\n <input\n className=\"dts-input\"\n type=\"number\"\n min={1}\n max={MAX_RESULT_LIMIT}\n value={limitText}\n disabled={!snapshot.writable}\n onChange={event => setLimitText(event.target.value)}\n onBlur={() => {\n const value = Number.parseInt(limitText, 10)\n if (Number.isSafeInteger(value) && value >= 1 && value <= MAX_RESULT_LIMIT) commit('defaultLimit', value)\n else setLimitText(String(settings?.defaultLimit ?? DEFAULT_RESULT_LIMIT))\n }}\n />\n </label>\n <label className=\"dts-field\">\n <span>{translate('filter')}</span>\n <input className=\"dts-input\" type=\"search\" value={filter} onChange={event => setFilter(event.target.value)} />\n </label>\n <button className=\"dts-button\" type=\"button\" onClick={() => { void refresh() }}>{translate('refresh')}</button>\n </div>\n\n <div className=\"dts-lists\">\n <label className=\"dts-field\">\n <span>{translate('alwaysVisible')}</span>\n <textarea\n className=\"dts-textarea\"\n value={alwaysText}\n disabled={!snapshot.writable}\n placeholder={translate('onePerLine')}\n onChange={event => setAlwaysText(event.target.value)}\n onBlur={() => commit('alwaysVisible', namesFromText(alwaysText))}\n />\n </label>\n <label className=\"dts-field\">\n <span>{translate('neverSearch')}</span>\n <textarea\n className=\"dts-textarea\"\n value={blockedText}\n disabled={!snapshot.writable}\n placeholder={translate('onePerLine')}\n onChange={event => setBlockedText(event.target.value)}\n onBlur={() => commit('neverSearch', namesFromText(blockedText).filter(name => name !== TOOL_SEARCH_NAME))}\n />\n </label>\n </div>\n\n <section className=\"dts-field\">\n <div className=\"dts-section-title\">{translate('catalog')}</div>\n <div className=\"dts-table-wrap\">\n <table className=\"dts-table\">\n <thead><tr>\n <th className=\"dts-tool\">{translate('tool')}</th>\n <th className=\"dts-policy\">{translate('policy')}</th>\n <th className=\"dts-selected\">{translate('selected')}</th>\n </tr></thead>\n <tbody>\n {visibleTools.map(tool => <tr key={tool.name}>\n <td className=\"dts-tool\">\n <code title={tool.name}>{tool.name}</code>\n {tool.description.length > 0 ? <span className=\"dts-description\" title={tool.description}>{tool.description}</span> : null}\n </td>\n <td className=\"dts-policy\">\n <select\n className=\"dts-select\"\n aria-label={`${translate('policy')}: ${tool.name}`}\n value={tool.name === TOOL_SEARCH_NAME ? 'always' : overrideFor(tool.name, settings ?? {\n defaultLimit: DEFAULT_RESULT_LIMIT,\n alwaysVisible: [],\n neverSearch: [],\n })}\n disabled={!snapshot.writable || tool.name === TOOL_SEARCH_NAME}\n onChange={event => changePolicy(tool.name, event.target.value as ToolPolicy | 'default')}\n >\n <option value=\"default\">\n {`${translate('defaultPolicy')} (${translate(core.has(tool.name) ? 'alwaysPolicy' : 'deferredPolicy')})`}\n </option>\n <option value=\"always\">{translate('alwaysPolicy')}</option>\n <option value=\"blocked\">{translate('blockedPolicy')}</option>\n </select>\n </td>\n <td\n className=\"dts-selected\"\n data-label={translate('selected')}\n aria-label={`${translate('selected')}: ${tool.selectedBy.length}`}\n >{tool.selectedBy.length}</td>\n </tr>)}\n {catalog !== undefined && visibleTools.length === 0\n ? <tr><td colSpan={3}>{translate('empty')}</td></tr>\n : null}\n </tbody>\n </table>\n </div>\n <div className=\"dts-status\" data-error={status?.error || undefined}>\n {status?.text ?? (catalog === undefined ? translate('loading') : '')}\n </div>\n </section>\n </div>\n}\n\nexport const inject = ['slots', 'locale', 'settingsScope']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n if (document.querySelector('style[data-plugin-css=\"@anionex/dsh-tool-search\"]') !== null) return () => {}\n const tag = document.createElement('style')\n tag.dataset.pluginCss = '@anionex/dsh-tool-search'\n tag.textContent = styles\n document.head.append(tag)\n return () => tag.remove()\n }, 'dsh-tool-search: styles')\n ctx.effect(() => ctx.locale.register('settings.toolSearch', { en, zh }), 'dsh-tool-search: locale')\n const t = ctx.locale.bind('settings.toolSearch') as Translate\n const scope = ctx.settingsScope.bind<ToolSearchSettings>({ namespace: TOOL_SEARCH_SETTINGS_NAMESPACE })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'tool-search',\n order: 34,\n label: () => t('nav'),\n inject: () => ({ scope, t }),\n }, ToolSearchSettingsSection))\n}\n"],"mappings":"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"}
|
package/lib/shared.js
CHANGED
package/lib/shared.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAA;AAC7C,MAAM,CAAC,MAAM,8BAA8B,GAAG,aAAa,CAAA;AAC3D,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAA;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAA;AACrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9C,aAAa;IACb,mBAAmB;IACnB,MAAM;IACN,aAAa;IACb,
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAA;AAC7C,MAAM,CAAC,MAAM,8BAA8B,GAAG,aAAa,CAAA;AAC3D,MAAM,CAAC,MAAM,yBAAyB,GAAG,2BAA2B,CAAA;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAA;AACrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9C,aAAa;IACb,mBAAmB;IACnB,MAAM;IACN,aAAa;IACb,gBAAgB;IAChB,UAAU;IACV,iBAAiB;IACjB,UAAU;IACV,UAAU;IACV,YAAY;IACZ,aAAa;IACb,OAAO;IACP,QAAQ;IACR,cAAc;IACd,OAAO;IACP,UAAU;IACV,eAAe;IACf,YAAY;IACZ,aAAa;IACb,UAAU;CACF,CAAC,CAAA;AAQX,MAAM,CAAC,MAAM,gBAAgB,GAAiC,MAAM,CAAC,MAAM,CAAC;IAC1E,YAAY,EAAE,oBAAoB;IAClC,aAAa,EAAE,EAAE;IACjB,WAAW,EAAE,EAAE;CAChB,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAAA,yDAAyD;AAEzD,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,EASL,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAA;AAErB,UAAU,qBAAqB,CAAC,CAAC;IAC/B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,aAAa,CAAA;IAC3C,KAAK,EAAE,CAAC,GAAG,SAAS,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,UAAU,aAAa,CAAC,CAAC;IACvB,WAAW,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACvC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IAC3C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAED,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAE1B,UAAU,aAAa;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACzD,MAAM,EAAE;QACN,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAA;QACvF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;KACjD,CAAA;IACD,aAAa,EAAE;QACb,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE;YAAE,SAAS,EAAE,MAAM,CAAA;SAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;KAC1D,CAAA;IACD,KAAK,EAAE;QACL,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,GAAG,QAAQ,CAAA;QACxD,QAAQ,CAAC,CAAC,EACR,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAA;YACZ,EAAE,EAAE,MAAM,CAAA;YACV,KAAK,EAAE,MAAM,CAAA;YACb,KAAK,EAAE,MAAM,MAAM,CAAA;YACnB,MAAM,EAAE,MAAM,CAAC,CAAA;SAChB,EACD,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,SAAS,GACjC,QAAQ,CAAA;KACZ,CAAA;CACF;AAED,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,OAAO,EAAE,KAAK,MAAM,CAAA;AAEjD,QAAA,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAAA,yDAAyD;AAEzD,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,EASL,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAA;AAErB,UAAU,qBAAqB,CAAC,CAAC;IAC/B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,aAAa,CAAA;IAC3C,KAAK,EAAE,CAAC,GAAG,SAAS,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,UAAU,aAAa,CAAC,CAAC;IACvB,WAAW,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACvC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IAC3C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAED,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAA;AAE1B,UAAU,aAAa;IACrB,MAAM,CAAC,KAAK,EAAE,MAAM,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACzD,MAAM,EAAE;QACN,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAA;QACvF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;KACjD,CAAA;IACD,aAAa,EAAE;QACb,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE;YAAE,SAAS,EAAE,MAAM,CAAA;SAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;KAC1D,CAAA;IACD,KAAK,EAAE;QACL,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,GAAG,QAAQ,CAAA;QACxD,QAAQ,CAAC,CAAC,EACR,OAAO,EAAE;YACP,IAAI,EAAE,MAAM,CAAA;YACZ,EAAE,EAAE,MAAM,CAAA;YACV,KAAK,EAAE,MAAM,CAAA;YACb,KAAK,EAAE,MAAM,MAAM,CAAA;YACnB,MAAM,EAAE,MAAM,CAAC,CAAA;SAChB,EACD,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,SAAS,GACjC,QAAQ,CAAA;KACZ,CAAA;CACF;AAED,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,OAAO,EAAE,KAAK,MAAM,CAAA;AAEjD,QAAA,MAAM,EAAE;;;;;;;;;;;;;;;;;;;CAmBP,CAAA;AAuED,KAAK,aAAa,GAAG;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;IACzC,CAAC,CAAC,EAAE,SAAS,CAAA;CACd,CAAA;AAED,wBAAgB,yBAAyB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,aAAa,GAAG,SAAS,CAuKhF;AAED,eAAO,MAAM,MAAM,UAAuC,CAAA;AAE1D,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmB9C"}
|
package/lib/types/shared.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare const MAX_RESULT_LIMIT = 20;
|
|
|
9
9
|
* names are deferred until this list or the user allowlist is updated because
|
|
10
10
|
* ToolDefinition does not expose package provenance.
|
|
11
11
|
*/
|
|
12
|
-
export declare const DEFAULT_CORE_TOOLS: readonly ["apply_patch", "ask_user_question", "bash", "create_goal", "
|
|
12
|
+
export declare const DEFAULT_CORE_TOOLS: readonly ["apply_patch", "ask_user_question", "bash", "create_goal", "exit_plan_mode", "get_goal", "interrupt_agent", "job_kill", "job_list", "job_output", "list_agents", "ralph", "report", "send_message", "skill", "subagent", "subagent_fork", "todo_write", "update_goal", "workflow"];
|
|
13
13
|
export interface ToolSearchSettings {
|
|
14
14
|
defaultLimit: number;
|
|
15
15
|
alwaysVisible: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/shared.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,eAAO,MAAM,gBAAgB,gBAAgB,CAAA;AAC7C,eAAO,MAAM,8BAA8B,gBAAgB,CAAA;AAC3D,eAAO,MAAM,yBAAyB,8BAA8B,CAAA;AACpE,eAAO,MAAM,oBAAoB,IAAI,CAAA;AACrC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/shared.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAEjE,eAAO,MAAM,gBAAgB,gBAAgB,CAAA;AAC7C,eAAO,MAAM,8BAA8B,gBAAgB,CAAA;AAC3D,eAAO,MAAM,yBAAyB,8BAA8B,CAAA;AACpE,eAAO,MAAM,oBAAoB,IAAI,CAAA;AACrC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,8RAqBpB,CAAA;AAEX,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,kBAAkB,CAIxD,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAA;AAE1D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,UAAU,CAAA;IAClB,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,CAAC,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC5B"}
|
package/package.json
CHANGED
package/scripts/profile-e2e.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
|
-
import { access, mkdir, mkdtemp, realpath, rm, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { access, mkdir, mkdtemp, readFile, realpath, rm, writeFile } from 'node:fs/promises'
|
|
3
3
|
import { createServer } from 'node:http'
|
|
4
4
|
import { tmpdir } from 'node:os'
|
|
5
5
|
import { dirname, join } from 'node:path'
|
|
6
6
|
import { fileURLToPath } from 'node:url'
|
|
7
7
|
|
|
8
8
|
const root = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
9
|
+
const packageVersion = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')).version
|
|
9
10
|
const dsh = process.env.DSH_BIN ?? 'dsh'
|
|
10
11
|
const keepTemp = process.argv.includes('--keep-temp')
|
|
11
12
|
const timeoutMs = Number(process.env.DSH_TOOL_SEARCH_E2E_TIMEOUT_MS ?? 180_000)
|
|
@@ -88,14 +89,24 @@ async function fixturePackage(directory) {
|
|
|
88
89
|
' },',
|
|
89
90
|
' execute: args => Promise.resolve({ echo: args.value }),',
|
|
90
91
|
' }))',
|
|
92
|
+
' ctx.tools.register(defineTool({',
|
|
93
|
+
" name: 'dsh_im_return_file',",
|
|
94
|
+
" description: 'Send a readable file to the user through the conversation.',",
|
|
95
|
+
" parameters: { path: { type: 'string', required: true, description: 'Readable file path.' } },",
|
|
96
|
+
' output: {',
|
|
97
|
+
" schema: { type: 'object', additionalProperties: false, properties: { sent: { type: 'boolean', required: true } } },",
|
|
98
|
+
" render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }],",
|
|
99
|
+
' },',
|
|
100
|
+
' execute: () => Promise.resolve({ sent: true }),',
|
|
101
|
+
' }))',
|
|
91
102
|
'}',
|
|
92
103
|
'',
|
|
93
104
|
].join('\n'))
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
async function startLlm(script = [
|
|
97
|
-
{ kind: 'tool', name: 'tool_search', arguments: '{"query":"
|
|
98
|
-
{ kind: 'tool', name: '
|
|
108
|
+
{ kind: 'tool', name: 'tool_search', arguments: '{"query":"dsh_im_return_file","limit":1}' },
|
|
109
|
+
{ kind: 'tool', name: 'dsh_im_return_file', arguments: '{"path":"/tmp/tool-search-e2e.txt"}' },
|
|
99
110
|
{ kind: 'text', text: 'tool search e2e done' },
|
|
100
111
|
]) {
|
|
101
112
|
const requests = []
|
|
@@ -323,7 +334,7 @@ try {
|
|
|
323
334
|
const runResult = await runDsh([
|
|
324
335
|
'--profile', 'headless',
|
|
325
336
|
'--patch', patch,
|
|
326
|
-
'Find and call the
|
|
337
|
+
'Find and call the tool that returns a file through the conversation.',
|
|
327
338
|
], {
|
|
328
339
|
cwd: workspaceDirectory,
|
|
329
340
|
env: {
|
|
@@ -341,12 +352,14 @@ try {
|
|
|
341
352
|
const searchedNames = requestToolNames(llm.requests[1])
|
|
342
353
|
assert(initialNames.includes('tool_search'), 'initial model call omits tool_search')
|
|
343
354
|
assert(!initialNames.includes('fixture_echo'), 'initial model call exposes deferred fixture_echo')
|
|
344
|
-
assert(
|
|
355
|
+
assert(!initialNames.includes('dsh_im_return_file'), 'initial model call exposes plugin-provided dsh_im_return_file')
|
|
356
|
+
assert(!searchedNames.includes('fixture_echo'), 'searching dsh_im_return_file exposes unrelated fixture_echo')
|
|
357
|
+
assert(searchedNames.includes('dsh_im_return_file'), 'next model call omits selected dsh_im_return_file')
|
|
345
358
|
const searchResult = toolResultTexts(llm.requests[1]).at(-1) ?? ''
|
|
346
|
-
assert(searchResult.includes('
|
|
359
|
+
assert(searchResult.includes('dsh_im_return_file'), 'tool_search result omits dsh_im_return_file summary')
|
|
347
360
|
assert(!searchResult.includes('"parameters"'), 'tool_search result duplicates a full schema')
|
|
348
|
-
const
|
|
349
|
-
assert(
|
|
361
|
+
const returnFileResult = toolResultTexts(llm.requests[2]).at(-1) ?? ''
|
|
362
|
+
assert(returnFileResult.includes('"sent":true'), 'dsh_im_return_file did not execute through the real Agent loop')
|
|
350
363
|
|
|
351
364
|
process.stdout.write(`${JSON.stringify({
|
|
352
365
|
ok: true,
|
|
@@ -356,8 +369,8 @@ try {
|
|
|
356
369
|
modelCalls: llm.requests.length,
|
|
357
370
|
initialToolCount: initialNames.length,
|
|
358
371
|
selectedToolCount: searchedNames.length,
|
|
359
|
-
selectedOnNextCall: searchedNames.includes('
|
|
360
|
-
package:
|
|
372
|
+
selectedOnNextCall: searchedNames.includes('dsh_im_return_file'),
|
|
373
|
+
package: `@anionex/dsh-tool-search@${packageVersion}`,
|
|
361
374
|
temporaryHome: keepTemp ? home : undefined,
|
|
362
375
|
}, null, 2)}\n`)
|
|
363
376
|
} finally {
|
package/scripts/validate.mjs
CHANGED
|
@@ -24,7 +24,7 @@ async function exists(path) {
|
|
|
24
24
|
|
|
25
25
|
const pkg = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'))
|
|
26
26
|
check(pkg.name === '@anionex/dsh-tool-search', 'package name is incorrect')
|
|
27
|
-
check(pkg.version === '0.1.
|
|
27
|
+
check(pkg.version === '0.1.1', 'release version is incorrect')
|
|
28
28
|
check(pkg.main === './lib/index.js', 'main entrypoint is incorrect')
|
|
29
29
|
check(pkg.types === './lib/types/index.d.ts', 'types entrypoint is incorrect')
|
|
30
30
|
check(pkg.exports?.['./client']?.default === './lib/client.js', 'client export is incorrect')
|
package/src/client/index.tsx
CHANGED
|
@@ -73,6 +73,7 @@ const en = {
|
|
|
73
73
|
selected: 'Live agents',
|
|
74
74
|
defaultPolicy: 'Default',
|
|
75
75
|
alwaysPolicy: 'Always',
|
|
76
|
+
deferredPolicy: 'Deferred',
|
|
76
77
|
blockedPolicy: 'Blocked',
|
|
77
78
|
loading: 'Loading...',
|
|
78
79
|
empty: 'No matching tools',
|
|
@@ -93,6 +94,7 @@ const zh: typeof en = {
|
|
|
93
94
|
selected: '活跃 Agent',
|
|
94
95
|
defaultPolicy: '默认',
|
|
95
96
|
alwaysPolicy: '常驻',
|
|
97
|
+
deferredPolicy: '延迟',
|
|
96
98
|
blockedPolicy: '禁用',
|
|
97
99
|
loading: '加载中...',
|
|
98
100
|
empty: '没有匹配工具',
|
|
@@ -296,7 +298,9 @@ export function ToolSearchSettingsSection({ scope, t }: SettingsProps): ReactNod
|
|
|
296
298
|
disabled={!snapshot.writable || tool.name === TOOL_SEARCH_NAME}
|
|
297
299
|
onChange={event => changePolicy(tool.name, event.target.value as ToolPolicy | 'default')}
|
|
298
300
|
>
|
|
299
|
-
<option value="default">
|
|
301
|
+
<option value="default">
|
|
302
|
+
{`${translate('defaultPolicy')} (${translate(core.has(tool.name) ? 'alwaysPolicy' : 'deferredPolicy')})`}
|
|
303
|
+
</option>
|
|
300
304
|
<option value="always">{translate('alwaysPolicy')}</option>
|
|
301
305
|
<option value="blocked">{translate('blockedPolicy')}</option>
|
|
302
306
|
</select>
|
package/src/shared.ts
CHANGED
package/tests/client.spec.tsx
CHANGED
|
@@ -23,12 +23,21 @@ describe('Tool Search settings section', () => {
|
|
|
23
23
|
description: 'Capture a browser screenshot.',
|
|
24
24
|
policy: 'deferred',
|
|
25
25
|
selectedBy: [],
|
|
26
|
+
}, {
|
|
27
|
+
name: 'dsh_im_return_file',
|
|
28
|
+
description: 'Send a readable file to the user.',
|
|
29
|
+
policy: 'deferred',
|
|
30
|
+
selectedBy: [],
|
|
26
31
|
}],
|
|
27
32
|
}), { status: 200 }))))
|
|
28
33
|
|
|
29
34
|
render(<ToolSearchSettingsSection scope={scope} />)
|
|
30
35
|
expect(await screen.findByText('browser_take_screenshot')).toBeDefined()
|
|
31
|
-
|
|
36
|
+
const imPolicy = screen.getByLabelText('Policy: dsh_im_return_file') as HTMLSelectElement
|
|
37
|
+
expect(imPolicy.value).toBe('default')
|
|
38
|
+
expect(imPolicy.options[0]?.text).toBe('Default (Deferred)')
|
|
39
|
+
expect(screen.getAllByLabelText('Live agents: 0').map(element => element.getAttribute('data-label')))
|
|
40
|
+
.toEqual(['Live agents', 'Live agents'])
|
|
32
41
|
fireEvent.change(screen.getByLabelText('Policy: browser_take_screenshot'), { target: { value: 'always' } })
|
|
33
42
|
await waitFor(() => {
|
|
34
43
|
expect(set).toHaveBeenCalledWith('alwaysVisible', ['browser_take_screenshot'])
|
package/tests/settings.spec.ts
CHANGED
|
@@ -24,6 +24,7 @@ describe('tool exposure policy', () => {
|
|
|
24
24
|
expect(policy.classify(TOOL_SEARCH_NAME)).toBe('always')
|
|
25
25
|
expect(policy.classify('apply_patch')).toBe('always')
|
|
26
26
|
expect(policy.classify('report')).toBe('always')
|
|
27
|
+
expect(policy.classify('dsh_im_return_file')).toBe('deferred')
|
|
27
28
|
expect(policy.classify('bash')).toBe('blocked')
|
|
28
29
|
expect(policy.classify('custom_tool')).toBe('always')
|
|
29
30
|
expect(policy.classify('conflict_tool')).toBe('blocked')
|