openxiangda 2.31.4 → 2.31.5
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/dist/agent-card.d.ts +34 -0
- package/dist/agent-card.d.ts.map +1 -0
- package/dist/agent-card.js +85 -0
- package/dist/agent-card.js.map +1 -0
- package/documentation/agent-cards.md +52 -0
- package/documentation/backend.md +1 -1
- package/documentation/declarations-cheatsheet.md +1 -0
- package/documentation/getting-started.md +7 -7
- package/documentation/manifest.json +10 -4
- package/package.json +25 -21
- package/releases/2.31.5.json +33 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +5 -4
- package/skills/openxiangda-v2/references/agent-cards.md +52 -0
- package/skills/openxiangda-v2/references/backend.md +1 -1
- package/skills/openxiangda-v2/references/declarations-cheatsheet.md +1 -0
- package/skills/openxiangda-v2/references/getting-started.md +7 -7
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Browser-only bridge for an application card inside the platform's isolated iframe. */
|
|
2
|
+
export declare const AGENT_CARD_PROTOCOL = "openxiangda.agent-card/v1";
|
|
3
|
+
export interface AgentCardField {
|
|
4
|
+
path: string;
|
|
5
|
+
label: string;
|
|
6
|
+
control: 'text' | 'textarea' | 'select';
|
|
7
|
+
help?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AgentCardState {
|
|
10
|
+
mode: 'input' | 'result';
|
|
11
|
+
title: string;
|
|
12
|
+
appName: string;
|
|
13
|
+
fields?: AgentCardField[];
|
|
14
|
+
partialInput?: Record<string, string>;
|
|
15
|
+
resultFields?: {
|
|
16
|
+
label: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}[];
|
|
19
|
+
status?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function connectAgentCard(onState: (state: AgentCardState) => void): {
|
|
22
|
+
options: (field: string, keyword?: string) => Promise<{
|
|
23
|
+
items: {
|
|
24
|
+
value: string;
|
|
25
|
+
label: string;
|
|
26
|
+
}[];
|
|
27
|
+
}>;
|
|
28
|
+
submit: (input: Record<string, string>) => Promise<{
|
|
29
|
+
accepted: boolean;
|
|
30
|
+
}>;
|
|
31
|
+
resize: () => void;
|
|
32
|
+
disconnect: () => void;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=agent-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-card.d.ts","sourceRoot":"","sources":["../src/agent-card.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAiBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI;qBAoDpD,MAAM,uBAA6D,OAAO,CAAC;QAAE,KAAK,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;oBAC1H,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAqC,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;;;EAY5G"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Browser-only bridge for an application card inside the platform's isolated iframe. */
|
|
2
|
+
export const AGENT_CARD_PROTOCOL = 'openxiangda.agent-card/v1';
|
|
3
|
+
function isMessage(value) {
|
|
4
|
+
return Boolean(value && typeof value === 'object' &&
|
|
5
|
+
value.protocol === AGENT_CARD_PROTOCOL);
|
|
6
|
+
}
|
|
7
|
+
export function connectAgentCard(onState) {
|
|
8
|
+
if (window.parent === window)
|
|
9
|
+
throw new Error('AGENT_CARD_HOST_REQUIRED');
|
|
10
|
+
let instanceId = '';
|
|
11
|
+
let mode = '';
|
|
12
|
+
let sequence = 0;
|
|
13
|
+
const pending = new Map();
|
|
14
|
+
const send = (message) => window.parent.postMessage(message, '*');
|
|
15
|
+
const resize = () => {
|
|
16
|
+
if (!instanceId)
|
|
17
|
+
return;
|
|
18
|
+
send({ protocol: AGENT_CARD_PROTOCOL, type: 'resize', instanceId,
|
|
19
|
+
payload: { height: Math.ceil(document.documentElement.scrollHeight) } });
|
|
20
|
+
};
|
|
21
|
+
const onMessage = (event) => {
|
|
22
|
+
if (event.source !== window.parent || !isMessage(event.data))
|
|
23
|
+
return;
|
|
24
|
+
const message = event.data;
|
|
25
|
+
if (message.type === 'state') {
|
|
26
|
+
if (!message.instanceId || (instanceId && message.instanceId !== instanceId))
|
|
27
|
+
return;
|
|
28
|
+
const state = message.payload;
|
|
29
|
+
if (!state || !['input', 'result'].includes(state.mode))
|
|
30
|
+
return;
|
|
31
|
+
instanceId = message.instanceId;
|
|
32
|
+
mode = state.mode;
|
|
33
|
+
onState(state);
|
|
34
|
+
requestAnimationFrame(resize);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (message.type !== 'response' || message.instanceId !== instanceId || !message.requestId)
|
|
38
|
+
return;
|
|
39
|
+
const task = pending.get(message.requestId);
|
|
40
|
+
if (!task)
|
|
41
|
+
return;
|
|
42
|
+
pending.delete(message.requestId);
|
|
43
|
+
window.clearTimeout(task.timer);
|
|
44
|
+
if (message.error)
|
|
45
|
+
task.reject(new Error(message.error));
|
|
46
|
+
else
|
|
47
|
+
task.resolve(message.payload);
|
|
48
|
+
};
|
|
49
|
+
window.addEventListener('message', onMessage);
|
|
50
|
+
const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(resize);
|
|
51
|
+
observer?.observe(document.documentElement);
|
|
52
|
+
send({ protocol: AGENT_CARD_PROTOCOL, type: 'ready' });
|
|
53
|
+
const request = (method, payload) => {
|
|
54
|
+
if (!instanceId)
|
|
55
|
+
return Promise.reject(new Error('AGENT_CARD_NOT_READY'));
|
|
56
|
+
if (method === 'submit' && mode !== 'input')
|
|
57
|
+
return Promise.reject(new Error('AGENT_CARD_READ_ONLY'));
|
|
58
|
+
if (pending.size >= 4)
|
|
59
|
+
return Promise.reject(new Error('AGENT_CARD_BUSY'));
|
|
60
|
+
const requestId = `${Date.now().toString(36)}-${++sequence}`;
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const timer = window.setTimeout(() => {
|
|
63
|
+
pending.delete(requestId);
|
|
64
|
+
reject(new Error('AGENT_CARD_TIMEOUT'));
|
|
65
|
+
}, 15000);
|
|
66
|
+
pending.set(requestId, { resolve, reject, timer });
|
|
67
|
+
send({ protocol: AGENT_CARD_PROTOCOL, type: 'request', instanceId, requestId, method, payload });
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
options: (field, keyword = '') => request('options', { field, keyword }),
|
|
72
|
+
submit: (input) => request('submit', { input }),
|
|
73
|
+
resize,
|
|
74
|
+
disconnect: () => {
|
|
75
|
+
window.removeEventListener('message', onMessage);
|
|
76
|
+
observer?.disconnect();
|
|
77
|
+
for (const task of pending.values()) {
|
|
78
|
+
window.clearTimeout(task.timer);
|
|
79
|
+
task.reject(new Error('AGENT_CARD_DISCONNECTED'));
|
|
80
|
+
}
|
|
81
|
+
pending.clear();
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=agent-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-card.js","sourceRoot":"","sources":["../src/agent-card.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AA6B/D,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,OAAO,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAC9C,KAAqB,CAAC,QAAQ,KAAK,mBAAmB,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAwC;IACvE,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC1E,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,IAAI,GAAgC,EAAE,CAAC;IAC3C,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgG,CAAC;IACxH,MAAM,IAAI,GAAG,CAAC,OAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,IAAI,CAAC,EAAE,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU;YAC9D,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;QACxC,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO;QACrE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC;QAC3B,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,UAAU,CAAC;gBAAE,OAAO;YACrF,MAAM,KAAK,GAAG,OAAO,CAAC,OAAyB,CAAC;YAChD,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,OAAO;YAChE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YAChC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,CAAC;YACf,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS;YAAE,OAAO;QACnG,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;;YACpD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,OAAO,cAAc,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAC3F,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,CAAC,MAA4B,EAAE,OAAgB,EAAE,EAAE;QACjE,IAAI,CAAC,UAAU;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAC1E,IAAI,MAAM,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACtG,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC7D,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE;gBACnC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAC1B,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC1C,CAAC,EAAE,KAAK,CAAC,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACnD,IAAI,CAAC,EAAE,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACnG,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,OAAO;QACL,OAAO,EAAE,CAAC,KAAa,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAA2D;QAC1I,MAAM,EAAE,CAAC,KAA6B,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAmC;QACzG,MAAM;QACN,UAAU,EAAE,GAAG,EAAE;YACf,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACjD,QAAQ,EAAE,UAAU,EAAE,CAAC;YACvB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;gBACpC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAChC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 应用 Agent 自定义卡片
|
|
2
|
+
|
|
3
|
+
应用先定义完整业务 operation、当前用户权限、只读参数查询和结果字段,再按需为 `ai.agent.inputCard` 或 `resultCard` 加 `resource`。例如两种卡片都使用同一个脚本:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
inputCard: { title: '补全报修', resource: 'agent-cards/repair.js', fields: [
|
|
7
|
+
{ path: 'locationId', label: '报修地点', control: 'select' },
|
|
8
|
+
{ path: 'description', label: '故障描述', control: 'textarea' },
|
|
9
|
+
] },
|
|
10
|
+
resultCard: { title: '报修已提交', resource: 'agent-cards/repair.js', fields: [
|
|
11
|
+
{ path: 'ticketNo', label: '单号' }, { path: 'locationName', label: '地点' },
|
|
12
|
+
] },
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`resource` 只能是 `agent-cards/*.js` 的相对路径,不能写外部 URL、整站入口或自由 HTML。应用前端构建必须将相同路径放入 `dist/`,`openxiangda deploy` 会核验它确实进入发布包。资源随前端制品摘要与环境 Head 固定,发布/回滚时和业务声明一起切换。标准卡片声明仍是必需的可靠回退路径。
|
|
16
|
+
|
|
17
|
+
卡片脚本用 `openxiangda/agent-card` 的 `connectAgentCard` SDK 与平台通信:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { connectAgentCard, type AgentCardState } from 'openxiangda/agent-card';
|
|
21
|
+
|
|
22
|
+
const bridge = connectAgentCard((state: AgentCardState) => {
|
|
23
|
+
if (state.mode === 'result') {
|
|
24
|
+
// 只读展示 state.resultFields。不能调用 submit。
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// 显示 state.fields、state.partialInput;select 预填仅是搜索线索。
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const found = await bridge.options('locationId', '教学楼');
|
|
31
|
+
// 展示 found.items[].label;用户明确选择后提交对应 value。
|
|
32
|
+
await bridge.submit({ locationId: found.items[0].value, description: '空调不制冷' });
|
|
33
|
+
// 卸载时 bridge.disconnect()。
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
例如使用 Vite 的独立 lib 配置打包成单文件 IIFE,不复用应用 Shell:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// apps/web/vite.agent-card.config.ts
|
|
40
|
+
import { defineConfig } from 'vite';
|
|
41
|
+
export default defineConfig({
|
|
42
|
+
build: { outDir: 'dist', emptyOutDir: false, cssCodeSplit: false,
|
|
43
|
+
lib: { entry: 'src/agent-card.tsx', name: 'OpenXiangdaRepairCard', formats: ['iife'], fileName: () => 'agent-cards/repair.js' },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
在普通前端构建之后运行 `vite build --config vite.agent-card.config.ts`。卡片样式可由脚本注入在自己的 iframe 内,不应依赖应用全局 CSS、路由、Cookie、登录或平台页面的 DOM。Host 使用无同源权限的 sandbox 和 CSP,只开放 `options` 与 `submit`;SDK 的请求先由 Host 检查卡片实例、声明字段、候选值,再由 Agent 服务端重验用户、应用权限、AppVersion、请求 Schema、Interaction revision 和幂等键。业务 handler 必须再次校验地点等稳定引用。结果卡只收到声明字段的只读投影。
|
|
49
|
+
|
|
50
|
+
卡片在 8 秒内无法握手、资源缺失或版本变化时,平台显示标准卡片。卡片消息不会修改 Codex 原生 SSE 文本流。这个桥采用与 MCP Apps 相同的资源/宿主调用思路,但首版不是官方 MCP Apps 线级协议;不要在应用里自行实现新工具网关或把 UI 脚本注入平台主页面。
|
|
51
|
+
|
|
52
|
+
预发验收至少包括:模糊地点出现两个中文候选、明确选中后提交、刷新恢复、双击/双标签只写一次、只读/非成员拒绝、资源缺失降级、结果卡与业务单号回读。普通问答成功或本地构建通过不能替代这些证据。
|
package/documentation/backend.md
CHANGED
|
@@ -308,7 +308,7 @@ const enroll = {
|
|
|
308
308
|
|
|
309
309
|
`inputCard` 是平台标准填写卡片,只能用于 `customAction` 任务。字段必须是同一请求 Schema 的顶层字符串,所有必填字段必须包含在卡片中;首版控件为 `text`、`textarea`、`select`,最多 12 项。`select` 必须绑定 `inputLookups`,辅助 GET 操作接受可选 `keyword`,返回最多 20 项 `{items:[{value,label}],nextCursor:null|string}`。`label` 面向用户,`value` 是稳定引用,业务 handler 仍须校验该引用。模型只创建等待卡并预填已确定的值;刷新后从会话快照恢复,提交后平台以当前用户身份和固定任务创建后台 Run,不再次请求模型。提交检查权限、AppVersion/目录摘要、完整请求 Schema 和幂等键;旧卡、权限撤销、版本变化和未知结果均不能静默重放。
|
|
310
310
|
|
|
311
|
-
`resultCard` 是已完成任务的只读结果卡片:只允许引用 `responseSchema.properties` 中明确声明的顶层字符串、数字或布尔字段,最多 8
|
|
311
|
+
`resultCard` 是已完成任务的只读结果卡片:只允许引用 `responseSchema.properties` 中明确声明的顶层字符串、数字或布尔字段,最多 8 项。应用须确保这些字段可向当前用户显示。填写卡与结果卡可选声明 `resource: 'agent-cards/repair.js'` 使用隔离的应用自定义 UI;未声明或加载失败时保留标准卡片。资源必须是同一前端制品中的单文件 IIFE,`deploy` 会拒绝声明了却未打包的资源。开发 SDK、构建配置和 Host 消息边界见 [应用 Agent 卡片](agent-cards.md)。本声明不改变既有 MCP Facade 的写入确认协议。
|
|
312
312
|
|
|
313
313
|
业务规则必须在后端操作中验证;提示词、卡片预填和前端校验不能取代权限与业务校验。完整输入、缺失输入、同名地点、权限不足、重复提交和结果未知都应有应用测试与回执核对。任务声明随 AppVersion 的 AI Catalog 一起发布,不能另建手工目录。
|
|
314
314
|
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
| 任务输入需要地点、人员等业务选择时,绑定同应用的只读辅助操作,用户不填内部编码 | `agent: { visibility: 'task', supportOperations: ['repair.locations'], inputLookups: { location: 'repair.locations' } }`;被引用的 GET 操作须有 `agent: { visibility: 'support' }`,`location` 须是请求 Schema 字段 |
|
|
61
61
|
| 缺少字段或选项歧义时在对话中续填 | `agent.inputCard: { title: '补全报修', fields: [{ path: 'location', label: '地点', control: 'select' }, { path: 'description', label: '故障描述', control: 'textarea' }] }`;包含全部请求必填字段,单选字段绑定只读 `inputLookups`,辅助操作响应须为有界 `items[{value,label}]` |
|
|
62
62
|
| 任务完成后显示业务结果卡片 | `agent.resultCard: { title: '报修已提交', fields: [{ path: 'ticketNo', label: '单号' }] }`;`ticketNo` 必须是该操作响应 Schema 中的顶层标量字段,最多 8 项 |
|
|
63
|
+
| 应用自定义卡片必须随同一版本发布 | `inputCard` / `resultCard` 可加 `resource: 'agent-cards/repair.js'`;将单文件 IIFE 放进前端 `dist/agent-cards/`,平台隔离加载、失败回退标准卡,详见 `docs agent-cards` |
|
|
63
64
|
| controller 路由必须绑定 `@OpenXiangdaOperation(appOperations.<code>)`,普通 CRUD 不写 controller | check 门禁会拒绝未绑定路由 |
|
|
64
65
|
| 事务守卫 `errorCode` 必须匹配 `^OPENXIANGDA_[A-Z0-9_]{1,96}$` | `errorCode: 'OPENXIANGDA_REPAIR_REQUEST_NOT_PENDING'` |
|
|
65
66
|
|
|
@@ -68,10 +68,10 @@ MCP 服务随项目根包一起安装,AI 客户端的 stdio 连接仍需配置
|
|
|
68
68
|
以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
|
-
pnpm dlx openxiangda@2.31.
|
|
72
|
-
pnpm dlx openxiangda@2.31.
|
|
73
|
-
pnpm dlx openxiangda@2.31.
|
|
74
|
-
pnpm dlx openxiangda@2.31.
|
|
71
|
+
pnpm dlx openxiangda@2.31.5 skill install --force
|
|
72
|
+
pnpm dlx openxiangda@2.31.5 auth status --base-url <平台地址> --json
|
|
73
|
+
pnpm dlx openxiangda@2.31.5 login --cwd my-app --base-url https://platform.example.com
|
|
74
|
+
pnpm dlx openxiangda@2.31.5 create my-app --base-url https://platform.example.com
|
|
75
75
|
cd my-app
|
|
76
76
|
pnpm openxiangda context --json
|
|
77
77
|
pnpm openxiangda dev
|
|
@@ -174,9 +174,9 @@ MCP 的 `docs_read` 可以读取本说明,当前没有独立的源码操作 MC
|
|
|
174
174
|
无需本地工作区,使用本 Skill 随包精确版本或已安装的对应 CLI:
|
|
175
175
|
|
|
176
176
|
```bash
|
|
177
|
-
pnpm dlx openxiangda@2.31.
|
|
178
|
-
pnpm dlx openxiangda@2.31.
|
|
179
|
-
pnpm dlx openxiangda@2.31.
|
|
177
|
+
pnpm dlx openxiangda@2.31.5 auth status --base-url <平台> --json
|
|
178
|
+
pnpm dlx openxiangda@2.31.5 source resolve <仓库URL> --base-url <平台> --json
|
|
179
|
+
pnpm dlx openxiangda@2.31.5 source clone <仓库URL> <新目录> --base-url <平台> --json
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
登录缺失或站点不匹配时,先按该平台执行 login。resolve 根据平台已经登记的绑定返回
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "openxiangda.documentation/v1",
|
|
3
|
-
"version": "2.31.
|
|
3
|
+
"version": "2.31.5",
|
|
4
4
|
"topics": [
|
|
5
5
|
{
|
|
6
6
|
"id": "getting-started",
|
|
7
7
|
"title": "安装与开始开发",
|
|
8
8
|
"file": "getting-started.md",
|
|
9
|
-
"sha256": "
|
|
9
|
+
"sha256": "9e2c56e9a8c7741400c5b6e915256b5e781f218d9cfe0f0c984249484b7a3406"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"id": "product-design",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"id": "declarations-cheatsheet",
|
|
37
37
|
"title": "声明速查:一次写对 config",
|
|
38
38
|
"file": "declarations-cheatsheet.md",
|
|
39
|
-
"sha256": "
|
|
39
|
+
"sha256": "726d9e992c16531aef0ee2e8510729d3dd4f2b1320104e39bba9744181946330"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"id": "application-foundation",
|
|
@@ -90,7 +90,13 @@
|
|
|
90
90
|
"id": "backend",
|
|
91
91
|
"title": "按需后端与业务动作",
|
|
92
92
|
"file": "backend.md",
|
|
93
|
-
"sha256": "
|
|
93
|
+
"sha256": "9c76b1fdea29d27a5f52ab057ce621857064a8e5e2ec84ea482d78651dabaa19"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"id": "agent-cards",
|
|
97
|
+
"title": "应用 Agent 自定义卡片",
|
|
98
|
+
"file": "agent-cards.md",
|
|
99
|
+
"sha256": "dcd2ae65c999a44e58228a767f861e622ea328ed09eff9cc511d9746f21851ef"
|
|
94
100
|
},
|
|
95
101
|
{
|
|
96
102
|
"id": "decimal-reservations",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda",
|
|
3
|
-
"version": "2.31.
|
|
3
|
+
"version": "2.31.5",
|
|
4
4
|
"description": "OpenXiangda 2.0 的统一命令、应用 SDK、MCP 与中文 AI 技能资料。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
"types": "./dist/react.d.ts",
|
|
27
27
|
"import": "./dist/react.js"
|
|
28
28
|
},
|
|
29
|
+
"./agent-card": {
|
|
30
|
+
"types": "./dist/agent-card.d.ts",
|
|
31
|
+
"import": "./dist/agent-card.js"
|
|
32
|
+
},
|
|
29
33
|
"./react/styles.css": "./dist/browser/styles.css",
|
|
30
34
|
"./mobile": {
|
|
31
35
|
"types": "./dist/mobile.d.ts",
|
|
@@ -60,13 +64,13 @@
|
|
|
60
64
|
"antd-mobile": "5.42.3",
|
|
61
65
|
"dayjs": "1.11.18",
|
|
62
66
|
"docx-preview": "0.3.7",
|
|
63
|
-
"openxiangda-cli": "2.6.
|
|
64
|
-
"openxiangda-contracts": "2.31.
|
|
65
|
-
"openxiangda-devkit-core": "2.34.
|
|
67
|
+
"openxiangda-cli": "2.6.7",
|
|
68
|
+
"openxiangda-contracts": "2.31.1",
|
|
69
|
+
"openxiangda-devkit-core": "2.34.1",
|
|
66
70
|
"openxiangda-legacy": "npm:openxiangda@1.0.269",
|
|
67
|
-
"openxiangda-mcp": "2.0.
|
|
68
|
-
"openxiangda-nest": "2.7.
|
|
69
|
-
"openxiangda-skill-kit": "2.3.
|
|
71
|
+
"openxiangda-mcp": "2.0.57",
|
|
72
|
+
"openxiangda-nest": "2.7.10",
|
|
73
|
+
"openxiangda-skill-kit": "2.3.31",
|
|
70
74
|
"xlsx": "https://github.com/1377385356/openxiangda/releases/download/vendor-mirror/xlsx-0.20.3.tgz"
|
|
71
75
|
},
|
|
72
76
|
"peerDependencies": {
|
|
@@ -132,36 +136,36 @@
|
|
|
132
136
|
},
|
|
133
137
|
"openxiangdaRelease": {
|
|
134
138
|
"schemaVersion": "openxiangda.release-notes/v1",
|
|
135
|
-
"version": "2.31.
|
|
139
|
+
"version": "2.31.5",
|
|
136
140
|
"status": "reviewed",
|
|
137
|
-
"title": "OpenXiangda 2.31.
|
|
138
|
-
"summary": "
|
|
141
|
+
"title": "OpenXiangda 2.31.5:应用 Agent 自定义卡片",
|
|
142
|
+
"summary": "应用可以把填写卡和结果卡的自定义脚本随同一发布版本交付,由平台在隔离卡片 Host 中展示。",
|
|
139
143
|
"newFeatures": [
|
|
140
|
-
"
|
|
141
|
-
"
|
|
144
|
+
"ai.agent.inputCard 和 resultCard 可声明受限的 agent-cards/*.js 资源;发布时核验脚本进入同一前端制品。",
|
|
145
|
+
"openxiangda/agent-card SDK 提供状态接收、只读选项查询、固定任务提交和尺寸同步;中文开发资料与 Skill 给出构建和验收示例。"
|
|
142
146
|
],
|
|
143
147
|
"fixes": [],
|
|
144
148
|
"affectedUsers": [
|
|
145
|
-
"
|
|
149
|
+
"需要在平台业务 Agent 中展示应用自有填写或结果布局的 OpenXiangda 2.0 应用开发者。"
|
|
146
150
|
],
|
|
147
151
|
"upgradeSteps": [
|
|
148
|
-
"升级 openxiangda
|
|
149
|
-
"
|
|
150
|
-
"
|
|
152
|
+
"升级 openxiangda 并更新锁文件;保留标准 inputCard/resultCard 字段声明作为资源失败时的回退。",
|
|
153
|
+
"将使用 SDK 的卡片构建为单文件 IIFE 放入前端 dist/agent-cards/,配置对应 resource,然后运行 check 与预发 deploy。",
|
|
154
|
+
"确认平台已发布配套 Agent 卡片资源端点与隔离 Host;在预发验证歧义选择、刷新、重复提交、权限拒绝与业务回读。"
|
|
151
155
|
],
|
|
152
156
|
"knownLimitations": [
|
|
153
|
-
"
|
|
154
|
-
"
|
|
157
|
+
"首版消息桥是平台限定协议,不宣称与官方 MCP Apps 线级兼容;卡片只支持已声明的选项查询和固定提交。",
|
|
158
|
+
"结果卡只收到已声明的标量字段;复杂列表、附件和额外工具调用仍需后续独立契约。"
|
|
155
159
|
],
|
|
156
160
|
"issues": [],
|
|
157
161
|
"compatibility": {
|
|
158
162
|
"node": ">=24",
|
|
159
163
|
"workspaceGenerations": "v2",
|
|
160
|
-
"platform": "
|
|
164
|
+
"platform": "自定义卡片需要配套 Agent Center 资源解析服务和无同源 iframe Host。",
|
|
161
165
|
"v1": "独立 V1 引擎和工作区不受影响。"
|
|
162
166
|
},
|
|
163
|
-
"sha256": "
|
|
164
|
-
"url": "https://github.com/1377385356/openxiangda/releases/tag/v2.31.
|
|
167
|
+
"sha256": "b674dd23dcb5fc9e00a7af758f01291295c78b8b6756b43d5f678ba79e4df345",
|
|
168
|
+
"url": "https://github.com/1377385356/openxiangda/releases/tag/v2.31.5"
|
|
165
169
|
},
|
|
166
170
|
"scripts": {
|
|
167
171
|
"build": "node ../../scripts/prune-package-dist.mjs && tsc -p tsconfig.json && node scripts/copy-assets.mjs",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "openxiangda.release-notes/v1",
|
|
3
|
+
"version": "2.31.5",
|
|
4
|
+
"status": "reviewed",
|
|
5
|
+
"title": "OpenXiangda 2.31.5:应用 Agent 自定义卡片",
|
|
6
|
+
"summary": "应用可以把填写卡和结果卡的自定义脚本随同一发布版本交付,由平台在隔离卡片 Host 中展示。",
|
|
7
|
+
"newFeatures": [
|
|
8
|
+
"ai.agent.inputCard 和 resultCard 可声明受限的 agent-cards/*.js 资源;发布时核验脚本进入同一前端制品。",
|
|
9
|
+
"openxiangda/agent-card SDK 提供状态接收、只读选项查询、固定任务提交和尺寸同步;中文开发资料与 Skill 给出构建和验收示例。"
|
|
10
|
+
],
|
|
11
|
+
"fixes": [],
|
|
12
|
+
"affectedUsers": [
|
|
13
|
+
"需要在平台业务 Agent 中展示应用自有填写或结果布局的 OpenXiangda 2.0 应用开发者。"
|
|
14
|
+
],
|
|
15
|
+
"upgradeSteps": [
|
|
16
|
+
"升级 openxiangda 并更新锁文件;保留标准 inputCard/resultCard 字段声明作为资源失败时的回退。",
|
|
17
|
+
"将使用 SDK 的卡片构建为单文件 IIFE 放入前端 dist/agent-cards/,配置对应 resource,然后运行 check 与预发 deploy。",
|
|
18
|
+
"确认平台已发布配套 Agent 卡片资源端点与隔离 Host;在预发验证歧义选择、刷新、重复提交、权限拒绝与业务回读。"
|
|
19
|
+
],
|
|
20
|
+
"knownLimitations": [
|
|
21
|
+
"首版消息桥是平台限定协议,不宣称与官方 MCP Apps 线级兼容;卡片只支持已声明的选项查询和固定提交。",
|
|
22
|
+
"结果卡只收到已声明的标量字段;复杂列表、附件和额外工具调用仍需后续独立契约。"
|
|
23
|
+
],
|
|
24
|
+
"issues": [],
|
|
25
|
+
"compatibility": {
|
|
26
|
+
"node": ">=24",
|
|
27
|
+
"workspaceGenerations": "v2",
|
|
28
|
+
"platform": "自定义卡片需要配套 Agent Center 资源解析服务和无同源 iframe Host。",
|
|
29
|
+
"v1": "独立 V1 引擎和工作区不受影响。"
|
|
30
|
+
},
|
|
31
|
+
"sha256": "b674dd23dcb5fc9e00a7af758f01291295c78b8b6756b43d5f678ba79e4df345",
|
|
32
|
+
"url": "https://github.com/1377385356/openxiangda/releases/tag/v2.31.5"
|
|
33
|
+
}
|
package/skills/manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"name": "openxiangda-v2",
|
|
6
6
|
"description": "使用 OpenXiangda 2.0 从模糊业务想法、已有资料或具体变更出发,通过对话发现模块、完成详细产品设计,由当前 AI Agent 按需用 Image 2.5 等图片能力形成视觉参考,直接实现真实页面并在浏览器修正,再检查和交付应用;维护 1.x 应用时使用对应的 1.x 技能。",
|
|
7
|
-
"sha256": "
|
|
7
|
+
"sha256": "b63f43c88bdeae8bb2adc6422acf07062ada0251ab2782ecfba4e9bc42dd6f73"
|
|
8
8
|
}
|
|
9
9
|
]
|
|
10
10
|
}
|
|
@@ -40,10 +40,10 @@ AI 接到新应用、页面或改版任务时,在同一个 OpenXiangda 工作
|
|
|
40
40
|
未创建工作区时使用本 Skill 随根包发布的精确版本:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
pnpm dlx openxiangda@2.31.
|
|
44
|
-
pnpm dlx openxiangda@2.31.
|
|
45
|
-
pnpm dlx openxiangda@2.31.
|
|
46
|
-
pnpm dlx openxiangda@2.31.
|
|
43
|
+
pnpm dlx openxiangda@2.31.5 auth status --cwd <应用目录> --base-url <平台地址> --json
|
|
44
|
+
pnpm dlx openxiangda@2.31.5 login --cwd <应用目录> --base-url <平台地址>
|
|
45
|
+
pnpm dlx openxiangda@2.31.5 create <应用目录> --base-url <同一平台地址>
|
|
46
|
+
pnpm dlx openxiangda@2.31.5 skill install --force
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
创建前把产品要求的目标平台明确带入命令,不从旧登录态推断站点。已有工作区从原绑定恢复,平台不一致时先解决登录与目标,不改 link 文件跨站创建。
|
|
@@ -72,6 +72,7 @@ pnpm dlx openxiangda@2.31.4 skill install --force
|
|
|
72
72
|
| 审批、待办、消息或事件 | [工作流与通知](references/workflow-events.md) |
|
|
73
73
|
| 自定义事务、校验或外部集成 | [按需后端](references/backend.md) |
|
|
74
74
|
| 向平台业务 Agent 开放任务、辅助查询和字段绑定 | [Agent 任务接入](references/backend.md#面向普通用户的-agent-任务);先完成业务操作、权限和规则,再声明 `ai.agent` |
|
|
75
|
+
| 为业务 Agent 提供自定义填写/结果卡片 | [Agent 卡片](references/agent-cards.md);声明同版本资源、使用隔离 SDK,保留平台标准卡片降级 |
|
|
75
76
|
| 主子额度、审批占用释放、撤回修订重提 | [精确金额占用](references/decimal-reservations.md) |
|
|
76
77
|
| 热点读取、抢票、排队、名额预占与原结果恢复 | [缓存、排队与配额](references/managed-concurrency.md) |
|
|
77
78
|
| 报名按钮、表单排队、短确认页、预占倒计时与前端恢复 | [并发前端接入](references/managed-concurrency-frontend.md):按六种形式选择;仅使用已导出的 API,区分待实现封装 |
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 应用 Agent 自定义卡片
|
|
2
|
+
|
|
3
|
+
应用先定义完整业务 operation、当前用户权限、只读参数查询和结果字段,再按需为 `ai.agent.inputCard` 或 `resultCard` 加 `resource`。例如两种卡片都使用同一个脚本:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
inputCard: { title: '补全报修', resource: 'agent-cards/repair.js', fields: [
|
|
7
|
+
{ path: 'locationId', label: '报修地点', control: 'select' },
|
|
8
|
+
{ path: 'description', label: '故障描述', control: 'textarea' },
|
|
9
|
+
] },
|
|
10
|
+
resultCard: { title: '报修已提交', resource: 'agent-cards/repair.js', fields: [
|
|
11
|
+
{ path: 'ticketNo', label: '单号' }, { path: 'locationName', label: '地点' },
|
|
12
|
+
] },
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`resource` 只能是 `agent-cards/*.js` 的相对路径,不能写外部 URL、整站入口或自由 HTML。应用前端构建必须将相同路径放入 `dist/`,`openxiangda deploy` 会核验它确实进入发布包。资源随前端制品摘要与环境 Head 固定,发布/回滚时和业务声明一起切换。标准卡片声明仍是必需的可靠回退路径。
|
|
16
|
+
|
|
17
|
+
卡片脚本用 `openxiangda/agent-card` 的 `connectAgentCard` SDK 与平台通信:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { connectAgentCard, type AgentCardState } from 'openxiangda/agent-card';
|
|
21
|
+
|
|
22
|
+
const bridge = connectAgentCard((state: AgentCardState) => {
|
|
23
|
+
if (state.mode === 'result') {
|
|
24
|
+
// 只读展示 state.resultFields。不能调用 submit。
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// 显示 state.fields、state.partialInput;select 预填仅是搜索线索。
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const found = await bridge.options('locationId', '教学楼');
|
|
31
|
+
// 展示 found.items[].label;用户明确选择后提交对应 value。
|
|
32
|
+
await bridge.submit({ locationId: found.items[0].value, description: '空调不制冷' });
|
|
33
|
+
// 卸载时 bridge.disconnect()。
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
例如使用 Vite 的独立 lib 配置打包成单文件 IIFE,不复用应用 Shell:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// apps/web/vite.agent-card.config.ts
|
|
40
|
+
import { defineConfig } from 'vite';
|
|
41
|
+
export default defineConfig({
|
|
42
|
+
build: { outDir: 'dist', emptyOutDir: false, cssCodeSplit: false,
|
|
43
|
+
lib: { entry: 'src/agent-card.tsx', name: 'OpenXiangdaRepairCard', formats: ['iife'], fileName: () => 'agent-cards/repair.js' },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
在普通前端构建之后运行 `vite build --config vite.agent-card.config.ts`。卡片样式可由脚本注入在自己的 iframe 内,不应依赖应用全局 CSS、路由、Cookie、登录或平台页面的 DOM。Host 使用无同源权限的 sandbox 和 CSP,只开放 `options` 与 `submit`;SDK 的请求先由 Host 检查卡片实例、声明字段、候选值,再由 Agent 服务端重验用户、应用权限、AppVersion、请求 Schema、Interaction revision 和幂等键。业务 handler 必须再次校验地点等稳定引用。结果卡只收到声明字段的只读投影。
|
|
49
|
+
|
|
50
|
+
卡片在 8 秒内无法握手、资源缺失或版本变化时,平台显示标准卡片。卡片消息不会修改 Codex 原生 SSE 文本流。这个桥采用与 MCP Apps 相同的资源/宿主调用思路,但首版不是官方 MCP Apps 线级协议;不要在应用里自行实现新工具网关或把 UI 脚本注入平台主页面。
|
|
51
|
+
|
|
52
|
+
预发验收至少包括:模糊地点出现两个中文候选、明确选中后提交、刷新恢复、双击/双标签只写一次、只读/非成员拒绝、资源缺失降级、结果卡与业务单号回读。普通问答成功或本地构建通过不能替代这些证据。
|
|
@@ -308,7 +308,7 @@ const enroll = {
|
|
|
308
308
|
|
|
309
309
|
`inputCard` 是平台标准填写卡片,只能用于 `customAction` 任务。字段必须是同一请求 Schema 的顶层字符串,所有必填字段必须包含在卡片中;首版控件为 `text`、`textarea`、`select`,最多 12 项。`select` 必须绑定 `inputLookups`,辅助 GET 操作接受可选 `keyword`,返回最多 20 项 `{items:[{value,label}],nextCursor:null|string}`。`label` 面向用户,`value` 是稳定引用,业务 handler 仍须校验该引用。模型只创建等待卡并预填已确定的值;刷新后从会话快照恢复,提交后平台以当前用户身份和固定任务创建后台 Run,不再次请求模型。提交检查权限、AppVersion/目录摘要、完整请求 Schema 和幂等键;旧卡、权限撤销、版本变化和未知结果均不能静默重放。
|
|
310
310
|
|
|
311
|
-
`resultCard` 是已完成任务的只读结果卡片:只允许引用 `responseSchema.properties` 中明确声明的顶层字符串、数字或布尔字段,最多 8
|
|
311
|
+
`resultCard` 是已完成任务的只读结果卡片:只允许引用 `responseSchema.properties` 中明确声明的顶层字符串、数字或布尔字段,最多 8 项。应用须确保这些字段可向当前用户显示。填写卡与结果卡可选声明 `resource: 'agent-cards/repair.js'` 使用隔离的应用自定义 UI;未声明或加载失败时保留标准卡片。资源必须是同一前端制品中的单文件 IIFE,`deploy` 会拒绝声明了却未打包的资源。开发 SDK、构建配置和 Host 消息边界见 [应用 Agent 卡片](agent-cards.md)。本声明不改变既有 MCP Facade 的写入确认协议。
|
|
312
312
|
|
|
313
313
|
业务规则必须在后端操作中验证;提示词、卡片预填和前端校验不能取代权限与业务校验。完整输入、缺失输入、同名地点、权限不足、重复提交和结果未知都应有应用测试与回执核对。任务声明随 AppVersion 的 AI Catalog 一起发布,不能另建手工目录。
|
|
314
314
|
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
| 任务输入需要地点、人员等业务选择时,绑定同应用的只读辅助操作,用户不填内部编码 | `agent: { visibility: 'task', supportOperations: ['repair.locations'], inputLookups: { location: 'repair.locations' } }`;被引用的 GET 操作须有 `agent: { visibility: 'support' }`,`location` 须是请求 Schema 字段 |
|
|
61
61
|
| 缺少字段或选项歧义时在对话中续填 | `agent.inputCard: { title: '补全报修', fields: [{ path: 'location', label: '地点', control: 'select' }, { path: 'description', label: '故障描述', control: 'textarea' }] }`;包含全部请求必填字段,单选字段绑定只读 `inputLookups`,辅助操作响应须为有界 `items[{value,label}]` |
|
|
62
62
|
| 任务完成后显示业务结果卡片 | `agent.resultCard: { title: '报修已提交', fields: [{ path: 'ticketNo', label: '单号' }] }`;`ticketNo` 必须是该操作响应 Schema 中的顶层标量字段,最多 8 项 |
|
|
63
|
+
| 应用自定义卡片必须随同一版本发布 | `inputCard` / `resultCard` 可加 `resource: 'agent-cards/repair.js'`;将单文件 IIFE 放进前端 `dist/agent-cards/`,平台隔离加载、失败回退标准卡,详见 `docs agent-cards` |
|
|
63
64
|
| controller 路由必须绑定 `@OpenXiangdaOperation(appOperations.<code>)`,普通 CRUD 不写 controller | check 门禁会拒绝未绑定路由 |
|
|
64
65
|
| 事务守卫 `errorCode` 必须匹配 `^OPENXIANGDA_[A-Z0-9_]{1,96}$` | `errorCode: 'OPENXIANGDA_REPAIR_REQUEST_NOT_PENDING'` |
|
|
65
66
|
|
|
@@ -68,10 +68,10 @@ MCP 服务随项目根包一起安装,AI 客户端的 stdio 连接仍需配置
|
|
|
68
68
|
以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
|
-
pnpm dlx openxiangda@2.31.
|
|
72
|
-
pnpm dlx openxiangda@2.31.
|
|
73
|
-
pnpm dlx openxiangda@2.31.
|
|
74
|
-
pnpm dlx openxiangda@2.31.
|
|
71
|
+
pnpm dlx openxiangda@2.31.5 skill install --force
|
|
72
|
+
pnpm dlx openxiangda@2.31.5 auth status --base-url <平台地址> --json
|
|
73
|
+
pnpm dlx openxiangda@2.31.5 login --cwd my-app --base-url https://platform.example.com
|
|
74
|
+
pnpm dlx openxiangda@2.31.5 create my-app --base-url https://platform.example.com
|
|
75
75
|
cd my-app
|
|
76
76
|
pnpm openxiangda context --json
|
|
77
77
|
pnpm openxiangda dev
|
|
@@ -174,9 +174,9 @@ MCP 的 `docs_read` 可以读取本说明,当前没有独立的源码操作 MC
|
|
|
174
174
|
无需本地工作区,使用本 Skill 随包精确版本或已安装的对应 CLI:
|
|
175
175
|
|
|
176
176
|
```bash
|
|
177
|
-
pnpm dlx openxiangda@2.31.
|
|
178
|
-
pnpm dlx openxiangda@2.31.
|
|
179
|
-
pnpm dlx openxiangda@2.31.
|
|
177
|
+
pnpm dlx openxiangda@2.31.5 auth status --base-url <平台> --json
|
|
178
|
+
pnpm dlx openxiangda@2.31.5 source resolve <仓库URL> --base-url <平台> --json
|
|
179
|
+
pnpm dlx openxiangda@2.31.5 source clone <仓库URL> <新目录> --base-url <平台> --json
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
登录缺失或站点不匹配时,先按该平台执行 login。resolve 根据平台已经登记的绑定返回
|