forked from ChaiHao/BPOS-MVP
MVP底座⑥:工具箱四段卡片 —— 功能/LLM/人类/接入
三类工具并列不是编排,是「一件事能交给谁办」的全集:交给系统、交给模型、交给人。 导入表单走两审同门(端点真调);MCP 如实标未连接,不摆点不动的按钮。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -1,65 +1,397 @@
|
|||||||
/**
|
/**
|
||||||
* feature `gov-tool` —— 工具管理:注册、白名单、凭证绑定(只回键,永不回值)
|
* feature `gov-tool` —— 工具箱:**系统能对世界做什么**,一屏四段。
|
||||||
|
*
|
||||||
|
* 功能工具 · 已注册的调用契约(读类自由调,写类登记意向)
|
||||||
|
* LLM 工具 · 模型实例(活动只见逻辑名,不触厂商与密钥)
|
||||||
|
* 人类工具 · 工单两模式 + 对话卡三族(调人也是调工具,只是被调的是人)
|
||||||
|
* 接入 · 导入自定义工具(与第一方同门两审)/ 连接 MCP
|
||||||
|
*
|
||||||
|
* 三类工具并列不是编排:它是「一件事能交给谁办」的全集 ——
|
||||||
|
* 交给系统(功能工具)、交给模型(LLM)、交给人(人类工具)。少列一类,活动就以为自己没得选。
|
||||||
*
|
*
|
||||||
* 自 `~/coding/JCAI_PRD/governance/_components/Governance.tsx` 平移:
|
* 自 `~/coding/JCAI_PRD/governance/_components/Governance.tsx` 平移:
|
||||||
* DOM 结构、类名(`g-*` + 色调 `t-*`)与文案原样保留,mock 常量换成服务端投影(README 平移规则 1/2/4)。
|
* 类名(`g-*` + 色调 `t-*`)与文案沿用;设计台以**卡片**为基调(运营台才以列表为主)。
|
||||||
* 区首页只负责导航,治理动作一律落在下钻详情页的**就地确认带**(影响预览三必答)。
|
|
||||||
*/
|
*/
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { registerToolRoute } from '@contracts';
|
||||||
|
import { call } from '@web-shared/typed-fetch.ts';
|
||||||
import { Ico } from '@web-shared/Ico.tsx';
|
import { Ico } from '@web-shared/Ico.tsx';
|
||||||
import { Card, Chip, Clear, NList, NRow, Note, PageHead, QueryGate } from '@web-shared/gov/primitives.tsx';
|
|
||||||
import type { Nav } from '@web-shared/gov/gov-route.ts';
|
|
||||||
import {
|
import {
|
||||||
useGovTools,
|
Acts,
|
||||||
} from '@web-shared/gov/gov-api.ts';
|
Card,
|
||||||
|
Chip,
|
||||||
|
Clear,
|
||||||
|
Field,
|
||||||
|
ListEdit,
|
||||||
|
Note,
|
||||||
|
PageHead,
|
||||||
|
Prop,
|
||||||
|
QueryGate,
|
||||||
|
Sec,
|
||||||
|
Seg,
|
||||||
|
St,
|
||||||
|
} from '@web-shared/gov/primitives.tsx';
|
||||||
|
import type { Nav } from '@web-shared/gov/gov-route.ts';
|
||||||
|
import { useGovLlm, useGovTools } from '@web-shared/gov/gov-api.ts';
|
||||||
|
|
||||||
export type HomeProps = { tab: string; nav: Nav };
|
export type HomeProps = { tab: string; nav: Nav };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人类工具目录 —— 系统内置的五种形态(语义出处 `packages/contracts/src/card.ts`)。
|
||||||
|
* 它们不在工具目录里注册:调人的能力是基座给的,不是谁装上来的。
|
||||||
|
*/
|
||||||
|
const HUMAN_TOOLS = [
|
||||||
|
{
|
||||||
|
name: '执行工单',
|
||||||
|
mode: 'work-order · execution',
|
||||||
|
ico: 'clipboard-check',
|
||||||
|
desc: '作业指导书 + 空表单,请人把一步做完;落地失败卡是它的系统预置形态,不算第五种卡',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '验收工单',
|
||||||
|
mode: 'work-order · acceptance',
|
||||||
|
ico: 'shield-check',
|
||||||
|
desc: '请人验收产出:通过 / 驳回重做 / 驳回迭代 —— 终局唯放行',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '决策卡',
|
||||||
|
mode: 'chat-card · decision',
|
||||||
|
ico: 'git-branch',
|
||||||
|
desc: '分支条件选择表,含自定义收尾项 —— 决策是对话区的选择题,不进视图区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '补全卡',
|
||||||
|
mode: 'chat-card · elicitation',
|
||||||
|
ico: 'pen-line',
|
||||||
|
desc: '就地要几个小信息;「没法填」旁路与提交两条路必走其一,不许静默挂着',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '评价卡',
|
||||||
|
mode: 'chat-card · rating',
|
||||||
|
ico: 'star',
|
||||||
|
desc: '任务评价:评分 1–5 + 改进建议,回流度量与蒸馏',
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
export function ToolsHome({ nav }: HomeProps) {
|
export function ToolsHome({ nav }: HomeProps) {
|
||||||
const q = useGovTools();
|
const tools = useGovTools();
|
||||||
const tools = q.data?.tools ?? [];
|
const llm = useGovLlm();
|
||||||
const reads = tools.filter((t) => t.effect === 'read');
|
const rows = tools.data?.tools ?? [];
|
||||||
const writes = tools.filter((t) => t.effect === 'write');
|
|
||||||
return (
|
return (
|
||||||
<QueryGate query={q}>
|
<QueryGate query={tools}>
|
||||||
<>
|
<>
|
||||||
<Note>
|
<Note>
|
||||||
按<b>效应等级</b>分列:读类过程中自由调用;写类只登记<b>动作意向</b>,放行后统一落地。密钥只存治理台,不入包、不入活动。
|
一件事能交给谁办,全集在这里:交给<b>系统</b>(功能工具)、交给<b>模型</b>(LLM)、交给
|
||||||
|
<b>人</b>(人类工具)。工具承载权力,约束严于活动 —— 契约对活动、实现对系统、凭证只存治理台。
|
||||||
</Note>
|
</Note>
|
||||||
{[
|
|
||||||
{ label: '读类 · 过程中自由调用', items: reads, tone: 'brand', ico: 'search' },
|
<Sec ico="wrench" title="功能工具" extra={`${rows.length} 件 · 读类自由调用,写类登记意向、放行后落地`}>
|
||||||
{ label: '写类 · 登记意向,放行后落地', items: writes, tone: 'danger', ico: 'pen-line' },
|
{rows.length === 0 ? (
|
||||||
].map((group) => (
|
<Clear>目录里还没有工具 —— 从下面「接入」导入一件,或由第一方随系统装入。</Clear>
|
||||||
<div key={group.label} className="g-sec">
|
) : (
|
||||||
<div className="g-band">
|
<div className="g-shelf">
|
||||||
<Ico name={group.ico} s={13} />
|
{rows.map((t) => {
|
||||||
{group.label}
|
const write = t.effect === 'write';
|
||||||
<span className="x">{group.items.length}</span>
|
return (
|
||||||
</div>
|
<button
|
||||||
<NList>
|
|
||||||
{group.items.map((t) => (
|
|
||||||
<NRow
|
|
||||||
key={t.name}
|
key={t.name}
|
||||||
tone={group.tone}
|
className={'g-tile t-' + (write ? 'warn' : 'ok')}
|
||||||
ico="wrench"
|
|
||||||
title={t.name}
|
|
||||||
sub={t.description}
|
|
||||||
cols={[
|
|
||||||
{ k: '版本', v: <span className="g-mono">{t.version}</span> },
|
|
||||||
{ k: '连接配置键', v: <span className="g-mono">{t.connectionKeys.join(', ') || '—'}</span> },
|
|
||||||
]}
|
|
||||||
right={t.pure ? <Chip tone="ok">纯工具</Chip> : <Chip tone={group.tone}>{t.effect === 'read' ? '读' : '写'}</Chip>}
|
|
||||||
onClick={() => nav.push({ k: 'tool', id: t.name })}
|
onClick={() => nav.push({ k: 'tool', id: t.name })}
|
||||||
/>
|
>
|
||||||
|
<span className="g-tile-h">
|
||||||
|
<span className="g-tile-i">
|
||||||
|
<Ico name="wrench" s={16} />
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-t">
|
||||||
|
<b>{t.name}</b>
|
||||||
|
<em>v{t.version}</em>
|
||||||
|
</span>
|
||||||
|
<St tone={write ? 'warn' : 'ok'} ico={write ? 'pen-line' : 'search'}>
|
||||||
|
{write ? '写' : '读'}
|
||||||
|
</St>
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-m">
|
||||||
|
<span className="g-tile-d">{t.description}</span>
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-f">
|
||||||
|
{t.pure ? (
|
||||||
|
<Chip tone="ok" ico="lock">
|
||||||
|
纯工具 · 活动私有
|
||||||
|
</Chip>
|
||||||
|
) : (
|
||||||
|
<Chip ico="key">{t.connectionKeys.length === 0 ? '无需连接' : `连接 ${t.connectionKeys.join('/')}`}</Chip>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Sec>
|
||||||
|
|
||||||
|
<Sec ico="cpu" title="LLM 工具" extra="调模型经模型网关一缝 · 活动只见逻辑名,四元绑定在系统区">
|
||||||
|
<div className="g-shelf">
|
||||||
|
{(llm.data?.instances ?? []).map((m) => (
|
||||||
|
<button
|
||||||
|
key={m.id}
|
||||||
|
className={'g-tile t-' + (m.enabled ? 'auto' : 'mute')}
|
||||||
|
onClick={() => nav.jump('system', 'llm', { k: 'llm', id: m.id })}
|
||||||
|
>
|
||||||
|
<span className="g-tile-h">
|
||||||
|
<span className="g-tile-i">
|
||||||
|
<Ico name="cpu" s={16} />
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-t">
|
||||||
|
<b>{m.name}</b>
|
||||||
|
<em>{m.provider}</em>
|
||||||
|
</span>
|
||||||
|
<St tone={m.apiKeyBound ? 'ok' : 'danger'} ico={m.apiKeyBound ? 'circle-check' : 'alert-circle'}>
|
||||||
|
{m.apiKeyBound ? '已绑密钥' : '未绑密钥'}
|
||||||
|
</St>
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-m">
|
||||||
|
<span className="g-tile-d">型号 {m.model}</span>
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-f">
|
||||||
|
{m.systemUse && <Chip tone="brand">系统用途</Chip>}
|
||||||
|
<span className="r">{m.enabled ? '启用中' : '已停用'}</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
))}
|
))}
|
||||||
</NList>
|
{(llm.data?.instances ?? []).length === 0 && (
|
||||||
|
<Clear>还没有绑定模型 —— 去系统区加一个实例,活动才有模型可用。</Clear>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Sec>
|
||||||
|
|
||||||
|
<Sec ico="hand" title="人类工具" extra="调人也是调工具 · 打扰上限在契约授权边界,由 Harness 强制">
|
||||||
|
<div className="g-shelf">
|
||||||
|
{HUMAN_TOOLS.map((h) => (
|
||||||
|
<div key={h.name} className="g-tile t-collab">
|
||||||
|
<span className="g-tile-h">
|
||||||
|
<span className="g-tile-i">
|
||||||
|
<Ico name={h.ico} s={16} />
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-t">
|
||||||
|
<b>{h.name}</b>
|
||||||
|
<em>{h.mode}</em>
|
||||||
|
</span>
|
||||||
|
<St tone="ok" ico="circle-check">
|
||||||
|
内置
|
||||||
|
</St>
|
||||||
|
</span>
|
||||||
|
<span className="g-tile-m">
|
||||||
|
<span className="g-tile-d">{h.desc}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
|
</Sec>
|
||||||
|
|
||||||
|
<Sec ico="plus" title="接入" extra="自定义工具与第一方同门两审 · MCP 经工具调用一缝接入">
|
||||||
|
<ImportToolCard />
|
||||||
|
<McpCard />
|
||||||
|
</Sec>
|
||||||
</>
|
</>
|
||||||
</QueryGate>
|
</QueryGate>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- ⑦ 数据管理 ---------------- */
|
/* ---------------- 接入 · 导入自定义工具 ---------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入 = 交一份**调用契约** + 一个能调通的端点 + 至少一条样例。
|
||||||
|
* 两审当场跑:静态审读契约,试运行审真调那个端点 —— 调不通就不入目录。
|
||||||
|
*/
|
||||||
|
function ImportToolCard() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [name, setName] = useState('');
|
||||||
|
const [version, setVersion] = useState('1.0.0');
|
||||||
|
const [description, setDescription] = useState('');
|
||||||
|
const [effect, setEffect] = useState<'read' | 'write'>('read');
|
||||||
|
const [endpoint, setEndpoint] = useState('');
|
||||||
|
const [inputFields, setInputFields] = useState<string[]>([]);
|
||||||
|
const [sample, setSample] = useState('{}');
|
||||||
|
|
||||||
|
const importTool = useMutation({
|
||||||
|
mutationFn: () =>
|
||||||
|
call<{ accepted: boolean; findings: Array<{ message: string }>; trialRun: { failures: string[] } }>(
|
||||||
|
registerToolRoute,
|
||||||
|
{
|
||||||
|
body: {
|
||||||
|
contract: {
|
||||||
|
name: name.trim(),
|
||||||
|
version: version.trim(),
|
||||||
|
description: description.trim(),
|
||||||
|
effect,
|
||||||
|
input: {
|
||||||
|
type: 'object',
|
||||||
|
required: inputFields.map((f) => f.trim()).filter((f) => f !== ''),
|
||||||
|
properties: Object.fromEntries(
|
||||||
|
inputFields.map((f) => f.trim()).filter((f) => f !== '').map((f) => [f, { type: 'string' }]),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
output: { type: 'object' },
|
||||||
|
errors: [],
|
||||||
|
idempotent: true,
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
retries: 1,
|
||||||
|
connectionKeys: ['endpoint'],
|
||||||
|
},
|
||||||
|
connectionValues: { endpoint: endpoint.trim() },
|
||||||
|
samples: [{ input: parseSample(sample) }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
onSuccess: (out) => {
|
||||||
|
if (out.accepted) {
|
||||||
|
void queryClient.invalidateQueries({ queryKey: ['gov', 'tools'] });
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const verdict = importTool.data;
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
ico="plus"
|
||||||
|
title="导入自定义工具"
|
||||||
|
extra={
|
||||||
|
<button className="g-btn primary" onClick={() => setOpen(true)}>
|
||||||
|
开始导入
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Note>
|
||||||
|
交一份调用契约 + 一个能调通的端点,两审当场跑:静态审读契约,试运行审<b>真调那个端点</b>。
|
||||||
|
调不通就不入目录 —— 一件调不通的工具进了目录,活动用它时才失败,那才是真的坏。
|
||||||
|
</Note>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card ico="plus" title="导入自定义工具">
|
||||||
|
<Prop ico="tag" title="身份与说明">
|
||||||
|
<Field k="工具名" hint="小写点分标识,如 erp.stock-read">
|
||||||
|
<input className="g-input" value={name} onChange={(e) => setName(e.target.value)} placeholder="erp.stock-read" />
|
||||||
|
</Field>
|
||||||
|
<Field k="版本">
|
||||||
|
<input className="g-input" value={version} onChange={(e) => setVersion(e.target.value)} />
|
||||||
|
</Field>
|
||||||
|
<Field k="适用说明" hint="面向 AI 写:何时用、语义边界 —— 这段话决定模型会不会用错它">
|
||||||
|
<input
|
||||||
|
className="g-input"
|
||||||
|
value={description}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
placeholder="读取 ERP 现货库存:PN → 库存量与库龄,寻源前先看自有呆滞"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Prop>
|
||||||
|
|
||||||
|
<Prop ico="shield-check" title="效应与连接">
|
||||||
|
<Field k="效应等级" hint="读类过程中自由调用;写类只登记动作意向,放行后才触达世界">
|
||||||
|
<Seg
|
||||||
|
value={effect}
|
||||||
|
options={[
|
||||||
|
{ k: 'read', label: '读' },
|
||||||
|
{ k: 'write', label: '写' },
|
||||||
|
]}
|
||||||
|
onPick={(k) => setEffect(k === 'write' ? 'write' : 'read')}
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
<Field k="端点" hint="值只写不读:落库即密封,此后治理台也只回「是否已绑定」">
|
||||||
|
<input
|
||||||
|
className="g-input"
|
||||||
|
value={endpoint}
|
||||||
|
onChange={(e) => setEndpoint(e.target.value)}
|
||||||
|
placeholder="https://erp.internal/api/stock"
|
||||||
|
/>
|
||||||
|
</Field>
|
||||||
|
</Prop>
|
||||||
|
|
||||||
|
<Prop ico="arrow-left-right" title="入参与样例">
|
||||||
|
<Field k="必填入参" hint="一行一个字段名;类型按字符串收,细的形状由端点自己校">
|
||||||
|
<ListEdit items={inputFields} placeholder="pn" onChange={setInputFields} />
|
||||||
|
</Field>
|
||||||
|
<Field k="样例入参" hint="JSON —— 试运行拿它真调一次端点,没有样例就没有门">
|
||||||
|
<input className="g-input" value={sample} onChange={(e) => setSample(e.target.value)} />
|
||||||
|
</Field>
|
||||||
|
</Prop>
|
||||||
|
|
||||||
|
{verdict !== undefined && !verdict.accepted && (
|
||||||
|
<Note tone="warn">
|
||||||
|
两审未过,没有入目录:
|
||||||
|
{[...verdict.findings.map((f) => f.message), ...verdict.trialRun.failures].join(';') || '未知原因'}
|
||||||
|
</Note>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Acts
|
||||||
|
align="end"
|
||||||
|
items={[
|
||||||
|
{ label: '取消', ico: 'x', onClick: () => setOpen(false) },
|
||||||
|
{
|
||||||
|
label: importTool.isPending ? '两审中…' : '导入并送审',
|
||||||
|
ico: 'circle-check',
|
||||||
|
primary: true,
|
||||||
|
disabled: importTool.isPending || name.trim() === '' || endpoint.trim() === '',
|
||||||
|
ask: {
|
||||||
|
title: `导入工具:${name.trim()}`,
|
||||||
|
note: <Note>与第一方同一条门:静态审 + 试运行审。过了才入目录;入目录还不等于能用,要再给活动授白名单。</Note>,
|
||||||
|
impact: {
|
||||||
|
who: '仅工具目录;没进白名单的活动仍然调不到它',
|
||||||
|
undo: '可停用;契约演进只增不破坏,破坏性变更要换新工具名',
|
||||||
|
when: '确认后当场跑两审',
|
||||||
|
},
|
||||||
|
okLabel: '确认导入',
|
||||||
|
onOk: () => importTool.mutate(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 样例入参解析:写坏了就当空对象送审 —— 让试运行去报错,别在这里拦 */
|
||||||
|
function parseSample(text: string): Record<string, unknown> {
|
||||||
|
try {
|
||||||
|
const parsed: unknown = JSON.parse(text);
|
||||||
|
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
|
||||||
|
? (parsed as Record<string, unknown>)
|
||||||
|
: {};
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- 接入 · MCP ---------------- */
|
||||||
|
|
||||||
|
function McpCard() {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
ico="link"
|
||||||
|
title="连接 MCP 服务器"
|
||||||
|
extra={
|
||||||
|
<St tone="mute" ico="unplug">
|
||||||
|
未连接
|
||||||
|
</St>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Note>
|
||||||
|
MCP 服务器上的工具,接进来之后与自定义工具同等待遇:经<b>工具调用一缝</b>去调、过两审入目录、
|
||||||
|
按白名单授给活动。当前系统还没有 MCP 客户端 —— 这里如实标着未连接,不摆一个点不动的按钮。
|
||||||
|
</Note>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- 工具详情 ---------------- */
|
||||||
|
|
||||||
export function ToolPage({ id }: { id: string }) {
|
export function ToolPage({ id }: { id: string }) {
|
||||||
const q = useGovTools();
|
const q = useGovTools();
|
||||||
@@ -104,6 +436,3 @@ export function ToolPage({ id }: { id: string }) {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- 数据对象 ---------------- */
|
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ export const ZM: Readonly<Record<GovZone, { title: string; desc: string; accent:
|
|||||||
title: '工具箱',
|
title: '工具箱',
|
||||||
icon: 'wrench',
|
icon: 'wrench',
|
||||||
accent: 'linear-gradient(140deg,#7f3bf5,#5b21cf)',
|
accent: 'linear-gradient(140deg,#7f3bf5,#5b21cf)',
|
||||||
desc: '能力——系统能对世界做什么。功能工具按效应等级分列:读类过程中自由调用,写类只登记动作意向、放行后落地。密钥只存治理台。',
|
desc: '能力——系统能对世界做什么。一件事能交给谁办的全集:功能工具(交给系统)、LLM 工具(交给模型)、人类工具(交给人)。读类过程中自由调用,写类只登记动作意向、放行后落地;密钥只存治理台,不入包、不入活动。',
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
title: '数据域',
|
title: '数据域',
|
||||||
|
|||||||
@@ -60,3 +60,16 @@
|
|||||||
死信目前只以治理者消息要素送出(`deadLetters.report` → `message`),没有一个按 kind 计数的
|
死信目前只以治理者消息要素送出(`deadLetters.report` → `message`),没有一个按 kind 计数的
|
||||||
查询面 —— 要补这一卡,得给 system_message 加一条按 kind 聚合的治理路由。
|
查询面 —— 要补这一卡,得给 system_message 加一条按 kind 聚合的治理路由。
|
||||||
在那之前,驾驶舱不摆一个查不出数的卡位。
|
在那之前,驾驶舱不摆一个查不出数的卡位。
|
||||||
|
|
||||||
|
|
||||||
|
## 工具箱 · MCP 连接(2026-07-28)
|
||||||
|
|
||||||
|
工具箱「接入」段有两件:**导入自定义工具已实装**(与第一方同门两审,端点调不通就不入目录);
|
||||||
|
**MCP 连接仅呈现**。系统还没有 MCP 客户端 —— 接进来之后 MCP 的工具与自定义工具同等待遇:
|
||||||
|
经工具调用一缝去调、过两审入目录、按白名单授给活动。卡上如实标「未连接」,不摆点不动的按钮。
|
||||||
|
|
||||||
|
## 活动槽位未实现(2026-07-28)
|
||||||
|
|
||||||
|
六个槽位(rfq-intake / alt-selection / sourcing-inquiry / cost-pricing / quote-negotiation /
|
||||||
|
intel-archive)只有契约面,入口产物是抛「未实现」的占位。起单后任务会停在 A1,这是**诚实状态**,
|
||||||
|
不是缺陷 —— 底座备齐后按 A1→A7 顺序逐个开发,届时以新包版本经安装通道换入,槽位契约不动。
|
||||||
|
|||||||
Reference in New Issue
Block a user