@_daniel_jiang/host-sdk 1.0.0
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/README.md +163 -0
- package/dist/agent-host.js +222 -0
- package/dist/agent-host.mjs +772 -0
- package/index.d.ts +8 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @agent-platform/host-sdk
|
|
2
|
+
|
|
3
|
+
Agent 平台宿主嵌入 SDK(iframe 模式)。UI 由 Agent `/host/hub`、`/host/widget` 渲染;宿主只需 `init` + `registerPage`。
|
|
4
|
+
|
|
5
|
+
表单提交与附件上传均在 **Agent Widget iframe 内**完成:用户点「开始」后,Widget 以 **multipart** 一次调用 `POST /api/v1/host/scenarios/{workflow}/run`(表单 JSON 字段 + 可选 `attachment_files`)。**不再**使用独立的 `POST /sessions/{id}/files`。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
宿主工程(EDC `boot-ui` / 专病库 `imedway-rdr-web`)使用**已拷贝到本仓的 vendor 包**,不依赖 agent-platform 源码树:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# 依赖已指向本地副本,例如:
|
|
13
|
+
# "@agent-platform/host-sdk": "file:./vendor/agent-platform-host-sdk"
|
|
14
|
+
npm install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
在 **agent-platform** 更新 SDK 后,于本目录执行同步(会先 `pnpm run build:sdk`):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bash web/packages/host-sdk/sync-to-hosts.sh
|
|
21
|
+
# 然后在对应宿主工程重新 npm install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
monorepo 内临时联调仍可指向源包:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install file:../../../web/packages/host-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
安装前需已生成 `dist/`(`web/` 下执行 `pnpm run build:sdk`)。
|
|
31
|
+
|
|
32
|
+
## 用法
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
import { AgentHost } from '@agent-platform/host-sdk'
|
|
36
|
+
|
|
37
|
+
await AgentHost.init({
|
|
38
|
+
host: 'edc',
|
|
39
|
+
// 推荐:BFF bootstrap 返回 agent_token + agent_web_origin,无需前端环境变量
|
|
40
|
+
bootstrap: () => fetch('/boot-admin/agent/bootstrap?hosts=edc', { credentials: 'include' }).then((r) => r.json()),
|
|
41
|
+
// 可选:打开需 establish 的 Widget 前强制刷新会话
|
|
42
|
+
// prepareOpenWidget: () => bootstrapAgentSession(true),
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
AgentHost.registerPage(
|
|
46
|
+
'edc_patient_list',
|
|
47
|
+
[{
|
|
48
|
+
id: 'form_fill',
|
|
49
|
+
workflow: 'edc_form_fill',
|
|
50
|
+
label: 'AI 填表',
|
|
51
|
+
host: 'edc',
|
|
52
|
+
prefilled: () => ({
|
|
53
|
+
sub_project_id: currentSubProjectId,
|
|
54
|
+
project_id: currentProjectId,
|
|
55
|
+
target: buildTargetFromEdcSelection(selectedForm),
|
|
56
|
+
}),
|
|
57
|
+
enabled: () => AgentHost.canOpen('edc_form_fill', { prefilled: { ... } }),
|
|
58
|
+
hostContext: { refresh: 'patient_list' },
|
|
59
|
+
}],
|
|
60
|
+
{
|
|
61
|
+
// 任务 success 且 hostContext.refresh 匹配时调用;unregisterPage 后自动失效
|
|
62
|
+
refreshKey: 'patient_list',
|
|
63
|
+
onRefresh: () => refreshPatientList(),
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
// 表单列表页:AI 设计 CRF(上传 Word/PDF)
|
|
68
|
+
AgentHost.registerPage(
|
|
69
|
+
'edc_form_list',
|
|
70
|
+
[{
|
|
71
|
+
id: 'crf_design',
|
|
72
|
+
workflow: 'edc_crf_design',
|
|
73
|
+
label: 'AI 设计 CRF',
|
|
74
|
+
host: 'edc',
|
|
75
|
+
prefilled: () => ({
|
|
76
|
+
sub_project_id: currentSubProjectId,
|
|
77
|
+
sort_start: nextFormSort,
|
|
78
|
+
}),
|
|
79
|
+
enabled: () => AgentHost.canOpen('edc_crf_design', { prefilled: { sub_project_id: currentSubProjectId } }),
|
|
80
|
+
hostContext: { refresh: 'form_list' },
|
|
81
|
+
}],
|
|
82
|
+
{ refreshKey: 'form_list', onRefresh: () => refreshFormList() },
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
AgentHost.openAction('edc_patient_list', 'form_fill')
|
|
86
|
+
|
|
87
|
+
// 离开页时务必 unregister(keep-alive 切走 / destroy),避免后台误刷
|
|
88
|
+
AgentHost.unregisterPage('edc_patient_list')
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
EDC / 专病库可用 `createAgentPageMixin` 自动处理进出页 register/unregister。
|
|
92
|
+
|
|
93
|
+
### Widget 内提交流程(iframe,宿主无需处理文件)
|
|
94
|
+
|
|
95
|
+
1. SDK 打开 `/host/widget?workflow=...` iframe
|
|
96
|
+
2. Widget 拉取 `GET /host/workflows/{name}/ui` 渲染表单(勾选填表场景 Widget **仅**上传文书/文本)
|
|
97
|
+
3. Widget 创建会话 `POST /sessions`
|
|
98
|
+
4. 用户提交 → **`POST /host/scenarios/{name}/run`(multipart,一次完成)**
|
|
99
|
+
5. Hub iframe 展示任务进度;成功完成后 SDK 对仍注册页触发 `onRefresh`
|
|
100
|
+
|
|
101
|
+
`complete` / `success` 来自 Agent 任务协议(Hub/Widget `postMessage`),与宿主业务 API 返回结构无关。
|
|
102
|
+
|
|
103
|
+
带附件的工作流(如 Excel 批量填表)无需宿主先上传文件;附件在 Widget 内选好后随 scenario run 一并提交。
|
|
104
|
+
|
|
105
|
+
## Bootstrap 契约(宿主 BFF)
|
|
106
|
+
|
|
107
|
+
`GET /agent/bootstrap?hosts=edc` 建议返回:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"agent_token": "...",
|
|
112
|
+
"refresh_token": "...",
|
|
113
|
+
"agent_web_origin": "https://agent.example.com"
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- `agent_web_origin`:Agent **前端**地址(iframe、Hub)
|
|
118
|
+
- Token 换取走 boot-admin → Agent API(`agent-host-api-base-url`),与 `agent_web_origin` 分离
|
|
119
|
+
|
|
120
|
+
可选:`init({ agentOrigin: '...' })` 显式覆盖 BFF 下发的地址。
|
|
121
|
+
|
|
122
|
+
## Scenario API(Headless / 自绘表单时)
|
|
123
|
+
|
|
124
|
+
iframe SDK 一般不需要宿主直调;若宿主自画表单、绕过 Widget,可按下列契约提交:
|
|
125
|
+
|
|
126
|
+
```http
|
|
127
|
+
POST /api/v1/host/scenarios/{workflow_name}/run
|
|
128
|
+
Authorization: Bearer <token>
|
|
129
|
+
Content-Type: multipart/form-data
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
133
|
+
|------|------|------|------|
|
|
134
|
+
| `session_id` | string | 是 | 已创建的 Agent 会话 UUID |
|
|
135
|
+
| `host` | string | 否 | 宿主标识,默认 `research_portal` |
|
|
136
|
+
| `host_context` | string (JSON) | 否 | 页面上下文、刷新回调等 |
|
|
137
|
+
| `prefilled` | string (JSON) | 否 | 宿主勾选带入的只读参数 |
|
|
138
|
+
| `form_values` | string (JSON) | 否 | 用户在表单中的选择 |
|
|
139
|
+
| `prompt_extra` | string | 否 | 附加 prompt |
|
|
140
|
+
| `attachment_files` | file[] | 否 | 附件,可多文件 |
|
|
141
|
+
|
|
142
|
+
响应示例:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"success": true,
|
|
147
|
+
"data": {
|
|
148
|
+
"task_id": "uuid",
|
|
149
|
+
"session_id": "uuid",
|
|
150
|
+
"status": "queued",
|
|
151
|
+
"stream_url": "/api/v1/tasks/{task_id}/stream"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
与 Chat 对比:
|
|
157
|
+
|
|
158
|
+
| 场景 | 接口 |
|
|
159
|
+
|------|------|
|
|
160
|
+
| Chat 发消息 + 附件 | `POST /sessions/{id}/messages-with-files` |
|
|
161
|
+
| Host Widget / Scenario | `POST /host/scenarios/{name}/run`(multipart) |
|
|
162
|
+
|
|
163
|
+
完整契约见仓库 `PRD/11_host_widget_integration.md` §6。
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
var de=Object.defineProperty,fe=Object.defineProperties;var ge=Object.getOwnPropertyDescriptors;var U=Object.getOwnPropertySymbols;var pe=Object.prototype.hasOwnProperty,be=Object.prototype.propertyIsEnumerable;var _=(u,l,c)=>l in u?de(u,l,{enumerable:!0,configurable:!0,writable:!0,value:c}):u[l]=c,$=(u,l)=>{for(var c in l||(l={}))pe.call(l,c)&&_(u,c,l[c]);if(U)for(var c of U(l))be.call(l,c)&&_(u,c,l[c]);return u},F=(u,l)=>fe(u,ge(l));var h=(u,l,c)=>_(u,typeof l!="symbol"?l+"":l,c);var p=(u,l,c)=>new Promise((w,d)=>{var b=y=>{try{P(c.next(y))}catch(E){d(E)}},W=y=>{try{P(c.throw(y))}catch(E){d(E)}},P=y=>y.done?w(y.value):Promise.resolve(y.value).then(b,W);P((c=c.apply(u,l)).next())});(function(u){"use strict";const l="agent-host";function c(t){return typeof t=="object"&&t!==null&&t.channel===l&&typeof t.type=="string"}function w(t){return t==null?t:JSON.parse(JSON.stringify(t))}const d="agent-host-launcher",b="agent-host-hub-panel-overlay",W="agent-host-hub-iframe",P="agent-host-widget-overlay",y="agent-host-widget-iframe",E=400,j="agent-host-sdk-styles";function V(t){return t.replace(/\/$/,"")}function T(t){try{return new URL(t).origin}catch(e){return t.replace(/\/$/,"")}}function N(t,e){const n=T(t),i=T(e);if(n===i)return!0;try{const s=new URL(n),o=new URL(i),f=new Set(["localhost","127.0.0.1","[::1]"]);return s.protocol===o.protocol&&s.port===o.port&&f.has(s.hostname)&&f.has(o.hostname)}catch(s){return!1}}function G(){if(typeof document=="undefined"||document.getElementById(j))return;const t=document.createElement("style");t.id=j,t.textContent=`
|
|
2
|
+
#${d} {
|
|
3
|
+
position: fixed;
|
|
4
|
+
right: 24px;
|
|
5
|
+
bottom: 24px;
|
|
6
|
+
z-index: 2147482999;
|
|
7
|
+
width: 56px;
|
|
8
|
+
height: 56px;
|
|
9
|
+
border: none;
|
|
10
|
+
border-radius: 50%;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
color: #fff;
|
|
16
|
+
font-size: 22px;
|
|
17
|
+
line-height: 1;
|
|
18
|
+
background: linear-gradient(135deg, #4f46e5, #7c3aed);
|
|
19
|
+
box-shadow: 0 4px 16px rgba(79, 70, 229, 0.45);
|
|
20
|
+
transition: transform 0.15s ease;
|
|
21
|
+
}
|
|
22
|
+
#${d}:hover { transform: scale(1.05); }
|
|
23
|
+
#${d}.is-pulse {
|
|
24
|
+
animation: agent-host-fab-pulse 2s ease-in-out infinite;
|
|
25
|
+
}
|
|
26
|
+
#${d} .agent-host-launcher-icon {
|
|
27
|
+
display: inline-block;
|
|
28
|
+
line-height: 1;
|
|
29
|
+
transform-origin: center center;
|
|
30
|
+
}
|
|
31
|
+
#${d}.is-breathe .agent-host-launcher-icon {
|
|
32
|
+
animation: agent-host-clover-breathe 1.8s ease-in-out infinite;
|
|
33
|
+
}
|
|
34
|
+
#${d} .agent-host-launcher-bell {
|
|
35
|
+
display: none;
|
|
36
|
+
width: 22px;
|
|
37
|
+
height: 22px;
|
|
38
|
+
line-height: 0;
|
|
39
|
+
transform-origin: top center;
|
|
40
|
+
}
|
|
41
|
+
#${d} .agent-host-launcher-bell.is-visible {
|
|
42
|
+
display: inline-block;
|
|
43
|
+
animation: agent-host-bell-shake 0.85s ease-in-out infinite;
|
|
44
|
+
}
|
|
45
|
+
#${d} .agent-host-launcher-bell svg {
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
display: block;
|
|
49
|
+
}
|
|
50
|
+
#${d} .agent-host-launcher-badge {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: -4px;
|
|
53
|
+
right: -4px;
|
|
54
|
+
box-sizing: border-box;
|
|
55
|
+
min-width: 20px;
|
|
56
|
+
height: 20px;
|
|
57
|
+
padding: 0 5px;
|
|
58
|
+
border-radius: 999px;
|
|
59
|
+
font-size: 11px;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
line-height: 1;
|
|
62
|
+
display: none;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
border: 2px solid #fff;
|
|
66
|
+
background: #f59e0b;
|
|
67
|
+
color: #fff;
|
|
68
|
+
}
|
|
69
|
+
#${d} .agent-host-launcher-badge.is-visible { display: flex; }
|
|
70
|
+
#${d} .agent-host-launcher-badge.is-waiting { background: #ef4444; }
|
|
71
|
+
#agent-host-launcher-hint {
|
|
72
|
+
position: fixed;
|
|
73
|
+
right: 24px;
|
|
74
|
+
bottom: 88px;
|
|
75
|
+
z-index: 2147482998;
|
|
76
|
+
max-width: min(800px, calc(100vw - 48px));
|
|
77
|
+
padding: 10px 14px;
|
|
78
|
+
border-radius: 10px;
|
|
79
|
+
font-size: 13px;
|
|
80
|
+
line-height: 1.45;
|
|
81
|
+
color: #333;
|
|
82
|
+
background: #fff;
|
|
83
|
+
border: 1px solid #e8e8ff;
|
|
84
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
|
|
85
|
+
display: none;
|
|
86
|
+
pointer-events: auto;
|
|
87
|
+
}
|
|
88
|
+
#agent-host-launcher-hint.is-visible { display: block; }
|
|
89
|
+
#agent-host-launcher-hint .agent-host-hint-inner {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
gap: 10px;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
}
|
|
95
|
+
#agent-host-launcher-hint .agent-host-hint-icon {
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
width: 20px;
|
|
101
|
+
height: 20px;
|
|
102
|
+
font-size: 16px;
|
|
103
|
+
line-height: 1;
|
|
104
|
+
color: #7c3aed;
|
|
105
|
+
transform-origin: center center;
|
|
106
|
+
animation: agent-host-hint-clover 4.5s ease-in-out infinite;
|
|
107
|
+
}
|
|
108
|
+
#agent-host-launcher-hint .agent-host-hint-text {
|
|
109
|
+
flex: 1;
|
|
110
|
+
min-width: 140px;
|
|
111
|
+
color: #333;
|
|
112
|
+
}
|
|
113
|
+
#agent-host-launcher-hint .agent-host-hint-actions {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
gap: 4px;
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
}
|
|
119
|
+
#agent-host-launcher-hint .agent-host-hint-use {
|
|
120
|
+
border: 1px solid #7c3aed;
|
|
121
|
+
border-radius: 6px;
|
|
122
|
+
padding: 0 12px;
|
|
123
|
+
height: 28px;
|
|
124
|
+
font-size: 12px;
|
|
125
|
+
font-weight: 500;
|
|
126
|
+
color: #7c3aed;
|
|
127
|
+
background: transparent;
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
}
|
|
130
|
+
#agent-host-launcher-hint .agent-host-hint-use:hover {
|
|
131
|
+
color: #fff;
|
|
132
|
+
background: #7c3aed;
|
|
133
|
+
}
|
|
134
|
+
#agent-host-launcher-hint .agent-host-hint-dismiss {
|
|
135
|
+
border: none;
|
|
136
|
+
border-radius: 6px;
|
|
137
|
+
padding: 0 8px;
|
|
138
|
+
height: 28px;
|
|
139
|
+
font-size: 12px;
|
|
140
|
+
color: #999;
|
|
141
|
+
background: transparent;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
}
|
|
144
|
+
#agent-host-launcher-hint .agent-host-hint-dismiss:hover { color: #666; }
|
|
145
|
+
#${b} {
|
|
146
|
+
position: fixed;
|
|
147
|
+
inset: 0;
|
|
148
|
+
z-index: 2147483000;
|
|
149
|
+
pointer-events: none;
|
|
150
|
+
opacity: 0;
|
|
151
|
+
transition: opacity 0.2s ease;
|
|
152
|
+
}
|
|
153
|
+
#${b}.is-open {
|
|
154
|
+
pointer-events: auto;
|
|
155
|
+
opacity: 1;
|
|
156
|
+
}
|
|
157
|
+
#${b} .agent-host-hub-backdrop {
|
|
158
|
+
position: absolute;
|
|
159
|
+
inset: 0;
|
|
160
|
+
background: rgba(15, 23, 42, 0.45);
|
|
161
|
+
}
|
|
162
|
+
#${b} .agent-host-hub-panel-shell {
|
|
163
|
+
position: absolute;
|
|
164
|
+
top: 0;
|
|
165
|
+
right: 0;
|
|
166
|
+
bottom: 0;
|
|
167
|
+
width: min(${E}px, 100vw);
|
|
168
|
+
transform: translateX(100%);
|
|
169
|
+
transition: transform 0.28s cubic-bezier(0.2, 0, 0, 1), width 0.28s cubic-bezier(0.2, 0, 0, 1);
|
|
170
|
+
background: #fff;
|
|
171
|
+
box-shadow: -8px 0 24px rgba(15, 23, 42, 0.14);
|
|
172
|
+
overflow: hidden;
|
|
173
|
+
}
|
|
174
|
+
#${b} .agent-host-hub-panel-shell.is-expanded {
|
|
175
|
+
width: min(50vw, 100vw);
|
|
176
|
+
}
|
|
177
|
+
#${b}.is-open .agent-host-hub-panel-shell {
|
|
178
|
+
transform: translateX(0);
|
|
179
|
+
}
|
|
180
|
+
#${b} iframe {
|
|
181
|
+
width: 100%;
|
|
182
|
+
height: 100%;
|
|
183
|
+
border: none;
|
|
184
|
+
background: #fff;
|
|
185
|
+
display: block;
|
|
186
|
+
}
|
|
187
|
+
@keyframes agent-host-fab-pulse {
|
|
188
|
+
0%, 100% { box-shadow: 0 4px 16px rgba(79, 70, 229, 0.45); }
|
|
189
|
+
50% { box-shadow: 0 4px 24px rgba(124, 58, 237, 0.65); }
|
|
190
|
+
}
|
|
191
|
+
@keyframes agent-host-clover-breathe {
|
|
192
|
+
0%, 100% { transform: scale(1); }
|
|
193
|
+
50% { transform: scale(1.28); }
|
|
194
|
+
}
|
|
195
|
+
/* 提示条四叶草:前 3s 呼吸 2 次(各 1.5s),后 1.5s 缓转一圈,循环 */
|
|
196
|
+
@keyframes agent-host-hint-clover {
|
|
197
|
+
0% { transform: scale(0.88) rotate(0deg); }
|
|
198
|
+
16.67% { transform: scale(1.12) rotate(0deg); }
|
|
199
|
+
33.33% { transform: scale(0.88) rotate(0deg); }
|
|
200
|
+
50% { transform: scale(1.12) rotate(0deg); }
|
|
201
|
+
66.67% { transform: scale(1) rotate(0deg); }
|
|
202
|
+
100% { transform: scale(1) rotate(360deg); }
|
|
203
|
+
}
|
|
204
|
+
@keyframes agent-host-bell-shake {
|
|
205
|
+
0%, 100% { transform: rotate(0deg); }
|
|
206
|
+
12% { transform: rotate(14deg); }
|
|
207
|
+
24% { transform: rotate(-12deg); }
|
|
208
|
+
36% { transform: rotate(10deg); }
|
|
209
|
+
48% { transform: rotate(-8deg); }
|
|
210
|
+
60% { transform: rotate(5deg); }
|
|
211
|
+
72% { transform: rotate(-3deg); }
|
|
212
|
+
84% { transform: rotate(1deg); }
|
|
213
|
+
}
|
|
214
|
+
`,document.head.appendChild(t)}class K{constructor(e,n,i){h(this,"agentOrigin","");h(this,"hubLauncher",null);h(this,"hubLauncherBadge",null);h(this,"hubLauncherHint",null);h(this,"hubPanelOverlay",null);h(this,"hubIframe",null);h(this,"widgetIframe",null);h(this,"hubReady",!1);h(this,"widgetReady",!1);h(this,"hubPanelOpen",!1);h(this,"hubPanelExpanded",!1);h(this,"lastRunning",0);h(this,"lastWaiting",0);h(this,"launcherHintAction",null);h(this,"pendingHubMessages",[]);h(this,"pendingWidgetMessages",[]);h(this,"onChildMessage");h(this,"onHintUse");h(this,"onHintDismiss");h(this,"handleMessage",e=>{var i,s;if(!N(this.agentOrigin,e.origin)||!c(e.data))return;const n=e.data;if(n.type==="ready"){n.surface==="hub"?(this.hubReady=!0,this.flush("hub")):(this.widgetReady=!0,this.flush("widget"));return}if(n.type==="hub-panel-close"){this.closeHubPanel();return}if(n.type==="hub-panel-width"){this.setHubPanelExpanded(!!n.expanded);return}if(n.type==="hub-stats"){this.updateLauncherStats(n.running,n.waiting),(i=this.onChildMessage)==null||i.call(this,n);return}(s=this.onChildMessage)==null||s.call(this,n)});this.agentOrigin=V(e),this.onChildMessage=n,this.onHintUse=i==null?void 0:i.onHintUse,this.onHintDismiss=i==null?void 0:i.onHintDismiss,window.addEventListener("message",this.handleMessage)}destroy(){window.removeEventListener("message",this.handleMessage),this.removeHub(),this.closeWidget()}mountHub(){this.hubPanelOverlay||typeof document=="undefined"||(G(),this.mountLauncher(),this.mountHubPanel())}openHubPanel(){var e;this.hubPanelOverlay&&(this.hubPanelOpen=!0,this.hubPanelOverlay.classList.add("is-open"),(e=this.hubLauncherHint)==null||e.classList.remove("is-visible"),this.post("hub",{channel:l,type:"open-hub-panel"}),this.applyLauncherVisual())}closeHubPanel(){this.hubPanelOverlay&&(this.hubPanelOpen=!1,this.hubPanelOverlay.classList.remove("is-open"),this.setHubPanelExpanded(!1),this.post("hub",{channel:l,type:"close-hub-panel"}),this.updateLauncherHint(this.launcherHintAction),this.applyLauncherVisual())}setHubPanelExpanded(e){var i;this.hubPanelExpanded=e;const n=(i=this.hubPanelOverlay)==null?void 0:i.querySelector(".agent-host-hub-panel-shell");n==null||n.classList.toggle("is-expanded",e)}updateLauncherHint(e){var s,o;this.launcherHintAction=e;const n=this.hubLauncherHint;if(!n)return;if(this.hubPanelOpen){n.classList.remove("is-visible");return}if(!e||!e.hint.trim()){n.innerHTML="",n.classList.remove("is-visible");return}n.innerHTML=`
|
|
215
|
+
<div class="agent-host-hint-inner">
|
|
216
|
+
<span class="agent-host-hint-icon" aria-hidden="true">✦</span>
|
|
217
|
+
<span class="agent-host-hint-text"></span>
|
|
218
|
+
<div class="agent-host-hint-actions">
|
|
219
|
+
<button type="button" class="agent-host-hint-use">立即开始</button>
|
|
220
|
+
<button type="button" class="agent-host-hint-dismiss">稍后</button>
|
|
221
|
+
</div>
|
|
222
|
+
</div>`;const i=n.querySelector(".agent-host-hint-text");i&&(i.textContent=e.hint),(s=n.querySelector(".agent-host-hint-use"))==null||s.addEventListener("click",f=>{var g;f.stopPropagation(),(g=this.onHintUse)==null||g.call(this,e.pageId,e.actionId)}),(o=n.querySelector(".agent-host-hint-dismiss"))==null||o.addEventListener("click",f=>{var g;f.stopPropagation(),(g=this.onHintDismiss)==null||g.call(this)}),n.classList.add("is-visible")}mountLauncher(){if(this.hubLauncher||document.getElementById(d))return;const e=document.createElement("button");if(e.id=d,e.type="button",e.title="科研AI助手",e.setAttribute("aria-label","科研AI助手"),e.innerHTML='<span class="agent-host-launcher-icon" aria-hidden="true">✦</span><span class="agent-host-launcher-bell" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3a5 5 0 0 0-5 5v1.5c0 1.3-.4 2.6-1.2 3.7L4.5 15.5c-.4.5-.1 1.3.5 1.3h14c.6 0 .9-.8.5-1.3l-1.3-2.3A6.6 6.6 0 0 1 17 9.5V8a5 5 0 0 0-5-5Z" fill="#f59e0b"/><path d="M10 18.5a2 2 0 0 0 4 0" stroke="#f59e0b" stroke-width="1.8" stroke-linecap="round"/></svg></span><span class="agent-host-launcher-badge"></span>',e.addEventListener("click",()=>this.openHubPanel()),document.body.appendChild(e),this.hubLauncher=e,this.hubLauncherBadge=e.querySelector(".agent-host-launcher-badge"),document.getElementById("agent-host-launcher-hint"))this.hubLauncherHint=document.getElementById("agent-host-launcher-hint");else{const n=document.createElement("div");n.id="agent-host-launcher-hint",document.body.appendChild(n),this.hubLauncherHint=n}}mountHubPanel(){const e=document.createElement("div");e.id=b;const n=document.createElement("div");n.className="agent-host-hub-backdrop",n.addEventListener("click",()=>this.closeHubPanel());const i=document.createElement("div");i.className="agent-host-hub-panel-shell";const s=document.createElement("iframe");s.id=W,s.title="科研AI助手",s.src=`${this.agentOrigin}/host/hub?embed=1&panel=1`,s.allow="clipboard-read; clipboard-write",i.appendChild(s),e.appendChild(n),e.appendChild(i),document.body.appendChild(e),this.hubPanelOverlay=e,this.hubIframe=s}updateLauncherStats(e,n){this.lastRunning=e,this.lastWaiting=n,this.applyLauncherVisual()}applyLauncherVisual(){const e=this.hubLauncher,n=this.hubLauncherBadge;if(!e||!n)return;const i=e.querySelector(".agent-host-launcher-icon"),s=e.querySelector(".agent-host-launcher-bell"),o=this.lastRunning,f=this.lastWaiting,g=f>0&&!this.hubPanelOpen;e.classList.toggle("is-pulse",o>0),e.classList.toggle("is-breathe",(o>0||f>0)&&!g),g?(e.title="有待确认事项,点击打开助手",e.setAttribute("aria-label","有待确认事项,点击打开助手")):(e.title="科研AI助手",e.setAttribute("aria-label","科研AI助手")),i&&(i.style.display=g?"none":""),s&&s.classList.toggle("is-visible",g),o>0?(n.textContent=String(o),n.classList.add("is-visible"),n.classList.remove("is-waiting")):f>0?(n.textContent="!",n.classList.add("is-visible","is-waiting")):(n.textContent="",n.classList.remove("is-visible","is-waiting"))}removeHub(){var e,n,i;(e=document.getElementById(d))==null||e.remove(),(n=document.getElementById("agent-host-launcher-hint"))==null||n.remove(),(i=document.getElementById(b))==null||i.remove(),this.hubLauncher=null,this.hubLauncherBadge=null,this.hubLauncherHint=null,this.hubPanelOverlay=null,this.hubIframe=null,this.hubReady=!1,this.hubPanelOpen=!1,this.hubPanelExpanded=!1,this.pendingHubMessages=[]}openWidget(e,n,i){this.closeWidget();const s=document.createElement("div");s.id=P,s.style.cssText="position:fixed;inset:0;z-index:2147483646;background:rgba(15,23,42,0.45);display:flex;align-items:center;justify-content:center;padding:16px;",s.addEventListener("click",ue=>{ue.target===s&&this.closeWidget()});const o=document.createElement("iframe");o.id=y,o.title=e.title||e.workflow;const f=new URLSearchParams({embed:"1",workflow:e.workflow,host:e.host||"",title:e.title||""});o.src=`${this.agentOrigin}/host/widget?${f.toString()}`,o.style.cssText="width:min(560px,100%);height:80vh;border:none;border-radius:12px;background:#fff;box-shadow:0 20px 60px rgba(0,0,0,0.25);display:block;",s.appendChild(o),document.body.appendChild(s),this.widgetIframe=o,this.widgetReady=!1;const g={channel:l,type:"init",token:n,refreshToken:i},he={workflow:e.workflow,title:e.title,host:e.host,prefilled:e.prefilled?w(e.prefilled):void 0,hostContext:e.hostContext?w(e.hostContext):void 0,sessionId:e.sessionId,preferSandboxFiles:e.preferSandboxFiles},ce={channel:l,type:"open-widget",payload:he};this.pendingWidgetMessages=[g,ce]}closeWidget(){var e;(e=document.getElementById(P))==null||e.remove(),this.widgetIframe=null,this.widgetReady=!1,this.pendingWidgetMessages=[]}sendToHub(e){this.post("hub",e)}post(e,n){var f;const i=e==="hub"?this.hubReady:this.widgetReady,s=e==="hub"?this.pendingHubMessages:this.pendingWidgetMessages;if(!i){s.push(n);return}const o=e==="hub"?this.hubIframe:this.widgetIframe;(f=o==null?void 0:o.contentWindow)==null||f.postMessage(n,T(this.agentOrigin))}flush(e){const n=e==="hub"?this.pendingHubMessages:this.pendingWidgetMessages,i=e==="hub"?this.hubIframe:this.widgetIframe;if(!(i!=null&&i.contentWindow))return;const s=T(this.agentOrigin);for(;n.length;){const o=n.shift();o&&i.contentWindow.postMessage(o,s)}}}function k(t){return typeof t=="function"?t():t}const H={},I={};let m=null,O=!1;function Y(t,e){const n=(e||"").trim();if(n)return n;for(const i of t){if(!i.hostContext)continue;const s=k(i.hostContext),o=s&&typeof s=="object"?String(s.refresh||"").trim():"";if(o)return o}}function J(t,e,n={}){const i=t!==m;i&&(O=!1),H[t]=e,m=t,!i&&e.some(o=>!o.enabled||o.enabled())&&(O=!1);const s=Y(e,n.refreshKey);s&&typeof n.onRefresh=="function"?I[t]={refreshKey:s,onRefresh:n.onRefresh}:delete I[t]}function X(t){delete H[t],delete I[t],m===t&&(m=null)}function Z(t){const e=String(t||"").trim();if(e){for(const n of Object.values(I))if(n.refreshKey===e)try{n.onRefresh()}catch(i){}}}function Q(){for(const t of Object.keys(H))delete H[t];for(const t of Object.keys(I))delete I[t];m=null,O=!1}function ee(t){t!==m&&(O=!1),m=t}function te(){O=!0}function z(t){return t.map(e=>({id:e.id,workflow:e.workflow,label:e.label,host:e.host,hint:e.hint?k(e.hint):void 0,hostContext:e.hostContext?w(k(e.hostContext)):void 0,prefilled:e.prefilled?w(k(e.prefilled)):void 0,enabled:e.enabled?e.enabled():!0}))}function B(t,e){const n=(H[t]||[]).find(o=>o.id===e);if(!n||n.enabled&&!n.enabled())return null;const i=n.prefilled?w(k(n.prefilled)):void 0,s=(n.workflow||"").trim();if(s==="edc_form_fill"&&i&&typeof i=="object"){const o=i;if(!o.sub_project_id&&!o.subProjectId)return null}if(s==="edc_crf_design"&&i&&typeof i=="object"){const o=i;if(!o.sub_project_id&&!o.subProjectId)return null}return{workflow:n.workflow,title:n.label,host:n.host,prefilled:i,hostContext:n.hostContext?w(k(n.hostContext)):void 0}}function ne(){return m}function ie(){return Object.entries(H).map(([t,e])=>({pageId:t,actions:e}))}function se(){if(O||!m)return null;const t=H[m]||[];for(const e of t){if(e.enabled&&!e.enabled())continue;const n=e.hint?k(e.hint):`可使用「${e.label}」`;return{pageId:m,actionId:e.id,hint:n}}return null}let r={},a=null,x="",A="",v=null;function oe(){const t=(r.agentOrigin||"").replace(/\/$/,"");if(!t)throw new Error("Agent 前端地址未配置:请在 init({ agentOrigin }) 传入,或由宿主 BFF bootstrap 返回 agent_web_origin");return t}function D(t){var e;t.agent_web_origin&&(r.agentOrigin=t.agent_web_origin.replace(/\/$/,"")),t.agent_token&&(x=t.agent_token),t.refresh_token&&(A=t.refresh_token),(e=r.onBootstrap)==null||e.call(r,t)}function R(){return p(this,null,function*(){if(r.getToken)return x=yield r.getToken(),x;if(x)return x;if(r.bootstrap){const t=yield r.bootstrap();if(D(t),x)return x}throw new Error("未连接 Agent:请配置 bootstrap 或 getToken")})}function C(){if(r.agentOrigin)try{L().updateLauncherHint(se())}catch(t){}}function L(){const t=oe();return a||(a=new K(t,re,{onHintUse:(e,n)=>{const i=B(e,n);i&&M(i)},onHintDismiss:()=>{te(),C()}}),r.showHub!==!1&&a.mountHub()),a}function ae(){if(!(!a||!r.agentOrigin)){for(const{pageId:t,actions:e}of ie())a.sendToHub({channel:"agent-host",type:"register-page",pageId:t,actions:z(e)});a.sendToHub({channel:"agent-host",type:"set-page",pageId:ne()}),C()}}function re(t){var e;if(t.type==="ready"&&t.surface==="hub"&&R().then(n=>{a==null||a.sendToHub({channel:"agent-host",type:"init",token:n,refreshToken:A||void 0}),ae()}).catch(()=>{}),t.type==="started"&&(a==null||a.closeWidget(),a==null||a.openHubPanel(),a==null||a.sendToHub({channel:"agent-host",type:"task-started",taskId:t.taskId,sessionId:t.sessionId,workflow:t.workflow,label:t.label||t.workflow,formValues:t.formValues,prefilled:t.prefilled,hostContext:t.hostContext,hubContinue:t.hubContinue})),t.type==="complete"){if(t.status==="success"){const n=t.hostContext&&t.hostContext.refresh;Z(n)}(e=r.onTaskComplete)==null||e.call(r,{taskId:t.taskId,status:t.status,hostContext:t.hostContext}),a==null||a.closeWidget()}if(t.type==="close"&&(a==null||a.closeWidget()),t.type==="open-widget"&&M(t.payload),t.type==="open-action"){const n=B(t.pageId,t.actionId);n&&M(n)}t.type==="hub-stats"&&(t.running,a==null||a.updateLauncherStats(t.running,t.waiting),C())}function M(t){return p(this,null,function*(){yield S(),r.prepareOpenWidget&&(yield r.prepareOpenWidget());const e=L(),n=yield R();e.openWidget({workflow:t.workflow,title:t.title||t.label,host:t.host||r.host,prefilled:t.prefilled,hostContext:t.hostContext,sessionId:t.sessionId,preferSandboxFiles:t.preferSandboxFiles},n,A||void 0)})}function S(){return p(this,null,function*(){v&&(yield v)})}function le(t){return p(this,null,function*(){if(r=$({showHub:!0},t),r.bootstrap){const e=yield r.bootstrap();D(e)}if(r.agentOrigin&&r.showHub!==!1&&typeof document!="undefined")try{L();const e=yield R();a==null||a.sendToHub({channel:"agent-host",type:"init",token:e,refreshToken:A||void 0})}catch(e){}})}const q={init(t){return p(this,null,function*(){v&&(yield v),v=le(t).finally(()=>{v=null}),yield v})},getToken(){return p(this,null,function*(){return yield S(),R()})},registerPage(i,s){return p(this,arguments,function*(t,e,n={}){yield S(),J(t,e,n),r.agentOrigin&&L().sendToHub({channel:"agent-host",type:"register-page",pageId:t,actions:z(e)}),C()})},unregisterPage(t){return p(this,null,function*(){yield S(),X(t),r.agentOrigin&&(L().sendToHub({channel:"agent-host",type:"unregister-page",pageId:t}),L().sendToHub({channel:"agent-host",type:"set-page",pageId:null})),C()})},setCurrentPage(t){return p(this,null,function*(){yield S(),ee(t),r.agentOrigin&&L().sendToHub({channel:"agent-host",type:"set-page",pageId:t}),C()})},openAction(t,e){return p(this,null,function*(){const n=B(t,e);if(!n)throw new Error("当前操作不可用");yield M(n)})},openWorkflow(n){return p(this,arguments,function*(t,e={}){yield M(F($({workflow:t},e),{host:e.host||r.host,title:e.title||e.label||t}))})},canOpen(t,e={}){const n=(t||"").trim(),i=e.prefilled||{},s=String(i.sub_project_id||i.subProjectId||"").trim();if(n==="edc_form_fill"){const o=i.forms;return!!(s&&Array.isArray(o)&&o.length>0)}return n==="edc_crf_design"?!!s:!0},destroy(){a==null||a.destroy(),a=null,x="",A="",r={},v=null,Q()}};typeof window!="undefined"&&(window.AgentHost=q),u.AGENT_HOST_MSG=l,u.AgentHost=q,u.isAgentHostMessage=c,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})})(this.AgentHost=this.AgentHost||{});
|
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
var q = Object.defineProperty, U = Object.defineProperties;
|
|
2
|
+
var F = Object.getOwnPropertyDescriptors;
|
|
3
|
+
var W = Object.getOwnPropertySymbols;
|
|
4
|
+
var V = Object.prototype.hasOwnProperty, N = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var R = (t, e, n) => e in t ? q(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n, S = (t, e) => {
|
|
6
|
+
for (var n in e || (e = {}))
|
|
7
|
+
V.call(e, n) && R(t, n, e[n]);
|
|
8
|
+
if (W)
|
|
9
|
+
for (var n of W(e))
|
|
10
|
+
N.call(e, n) && R(t, n, e[n]);
|
|
11
|
+
return t;
|
|
12
|
+
}, B = (t, e) => U(t, F(e));
|
|
13
|
+
var l = (t, e, n) => R(t, typeof e != "symbol" ? e + "" : e, n);
|
|
14
|
+
var d = (t, e, n) => new Promise((i, s) => {
|
|
15
|
+
var o = (g) => {
|
|
16
|
+
try {
|
|
17
|
+
c(n.next(g));
|
|
18
|
+
} catch (P) {
|
|
19
|
+
s(P);
|
|
20
|
+
}
|
|
21
|
+
}, h = (g) => {
|
|
22
|
+
try {
|
|
23
|
+
c(n.throw(g));
|
|
24
|
+
} catch (P) {
|
|
25
|
+
s(P);
|
|
26
|
+
}
|
|
27
|
+
}, c = (g) => g.done ? i(g.value) : Promise.resolve(g.value).then(o, h);
|
|
28
|
+
c((n = n.apply(t, e)).next());
|
|
29
|
+
});
|
|
30
|
+
const I = "agent-host";
|
|
31
|
+
function K(t) {
|
|
32
|
+
return typeof t == "object" && t !== null && t.channel === I && typeof t.type == "string";
|
|
33
|
+
}
|
|
34
|
+
function k(t) {
|
|
35
|
+
return t == null ? t : JSON.parse(JSON.stringify(t));
|
|
36
|
+
}
|
|
37
|
+
const u = "agent-host-launcher", p = "agent-host-hub-panel-overlay", G = "agent-host-hub-iframe", $ = "agent-host-widget-overlay", Y = "agent-host-widget-iframe", J = 400, _ = "agent-host-sdk-styles";
|
|
38
|
+
function X(t) {
|
|
39
|
+
return t.replace(/\/$/, "");
|
|
40
|
+
}
|
|
41
|
+
function A(t) {
|
|
42
|
+
try {
|
|
43
|
+
return new URL(t).origin;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return t.replace(/\/$/, "");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function Z(t, e) {
|
|
49
|
+
const n = A(t), i = A(e);
|
|
50
|
+
if (n === i) return !0;
|
|
51
|
+
try {
|
|
52
|
+
const s = new URL(n), o = new URL(i), h = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
53
|
+
return s.protocol === o.protocol && s.port === o.port && h.has(s.hostname) && h.has(o.hostname);
|
|
54
|
+
} catch (s) {
|
|
55
|
+
return !1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function Q() {
|
|
59
|
+
if (typeof document == "undefined" || document.getElementById(_)) return;
|
|
60
|
+
const t = document.createElement("style");
|
|
61
|
+
t.id = _, t.textContent = `
|
|
62
|
+
#${u} {
|
|
63
|
+
position: fixed;
|
|
64
|
+
right: 24px;
|
|
65
|
+
bottom: 24px;
|
|
66
|
+
z-index: 2147482999;
|
|
67
|
+
width: 56px;
|
|
68
|
+
height: 56px;
|
|
69
|
+
border: none;
|
|
70
|
+
border-radius: 50%;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
color: #fff;
|
|
76
|
+
font-size: 22px;
|
|
77
|
+
line-height: 1;
|
|
78
|
+
background: linear-gradient(135deg, #4f46e5, #7c3aed);
|
|
79
|
+
box-shadow: 0 4px 16px rgba(79, 70, 229, 0.45);
|
|
80
|
+
transition: transform 0.15s ease;
|
|
81
|
+
}
|
|
82
|
+
#${u}:hover { transform: scale(1.05); }
|
|
83
|
+
#${u}.is-pulse {
|
|
84
|
+
animation: agent-host-fab-pulse 2s ease-in-out infinite;
|
|
85
|
+
}
|
|
86
|
+
#${u} .agent-host-launcher-icon {
|
|
87
|
+
display: inline-block;
|
|
88
|
+
line-height: 1;
|
|
89
|
+
transform-origin: center center;
|
|
90
|
+
}
|
|
91
|
+
#${u}.is-breathe .agent-host-launcher-icon {
|
|
92
|
+
animation: agent-host-clover-breathe 1.8s ease-in-out infinite;
|
|
93
|
+
}
|
|
94
|
+
#${u} .agent-host-launcher-bell {
|
|
95
|
+
display: none;
|
|
96
|
+
width: 22px;
|
|
97
|
+
height: 22px;
|
|
98
|
+
line-height: 0;
|
|
99
|
+
transform-origin: top center;
|
|
100
|
+
}
|
|
101
|
+
#${u} .agent-host-launcher-bell.is-visible {
|
|
102
|
+
display: inline-block;
|
|
103
|
+
animation: agent-host-bell-shake 0.85s ease-in-out infinite;
|
|
104
|
+
}
|
|
105
|
+
#${u} .agent-host-launcher-bell svg {
|
|
106
|
+
width: 100%;
|
|
107
|
+
height: 100%;
|
|
108
|
+
display: block;
|
|
109
|
+
}
|
|
110
|
+
#${u} .agent-host-launcher-badge {
|
|
111
|
+
position: absolute;
|
|
112
|
+
top: -4px;
|
|
113
|
+
right: -4px;
|
|
114
|
+
box-sizing: border-box;
|
|
115
|
+
min-width: 20px;
|
|
116
|
+
height: 20px;
|
|
117
|
+
padding: 0 5px;
|
|
118
|
+
border-radius: 999px;
|
|
119
|
+
font-size: 11px;
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
line-height: 1;
|
|
122
|
+
display: none;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
border: 2px solid #fff;
|
|
126
|
+
background: #f59e0b;
|
|
127
|
+
color: #fff;
|
|
128
|
+
}
|
|
129
|
+
#${u} .agent-host-launcher-badge.is-visible { display: flex; }
|
|
130
|
+
#${u} .agent-host-launcher-badge.is-waiting { background: #ef4444; }
|
|
131
|
+
#agent-host-launcher-hint {
|
|
132
|
+
position: fixed;
|
|
133
|
+
right: 24px;
|
|
134
|
+
bottom: 88px;
|
|
135
|
+
z-index: 2147482998;
|
|
136
|
+
max-width: min(800px, calc(100vw - 48px));
|
|
137
|
+
padding: 10px 14px;
|
|
138
|
+
border-radius: 10px;
|
|
139
|
+
font-size: 13px;
|
|
140
|
+
line-height: 1.45;
|
|
141
|
+
color: #333;
|
|
142
|
+
background: #fff;
|
|
143
|
+
border: 1px solid #e8e8ff;
|
|
144
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
|
|
145
|
+
display: none;
|
|
146
|
+
pointer-events: auto;
|
|
147
|
+
}
|
|
148
|
+
#agent-host-launcher-hint.is-visible { display: block; }
|
|
149
|
+
#agent-host-launcher-hint .agent-host-hint-inner {
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 10px;
|
|
153
|
+
flex-wrap: wrap;
|
|
154
|
+
}
|
|
155
|
+
#agent-host-launcher-hint .agent-host-hint-icon {
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
display: inline-flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
width: 20px;
|
|
161
|
+
height: 20px;
|
|
162
|
+
font-size: 16px;
|
|
163
|
+
line-height: 1;
|
|
164
|
+
color: #7c3aed;
|
|
165
|
+
transform-origin: center center;
|
|
166
|
+
animation: agent-host-hint-clover 4.5s ease-in-out infinite;
|
|
167
|
+
}
|
|
168
|
+
#agent-host-launcher-hint .agent-host-hint-text {
|
|
169
|
+
flex: 1;
|
|
170
|
+
min-width: 140px;
|
|
171
|
+
color: #333;
|
|
172
|
+
}
|
|
173
|
+
#agent-host-launcher-hint .agent-host-hint-actions {
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
gap: 4px;
|
|
177
|
+
flex-shrink: 0;
|
|
178
|
+
}
|
|
179
|
+
#agent-host-launcher-hint .agent-host-hint-use {
|
|
180
|
+
border: 1px solid #7c3aed;
|
|
181
|
+
border-radius: 6px;
|
|
182
|
+
padding: 0 12px;
|
|
183
|
+
height: 28px;
|
|
184
|
+
font-size: 12px;
|
|
185
|
+
font-weight: 500;
|
|
186
|
+
color: #7c3aed;
|
|
187
|
+
background: transparent;
|
|
188
|
+
cursor: pointer;
|
|
189
|
+
}
|
|
190
|
+
#agent-host-launcher-hint .agent-host-hint-use:hover {
|
|
191
|
+
color: #fff;
|
|
192
|
+
background: #7c3aed;
|
|
193
|
+
}
|
|
194
|
+
#agent-host-launcher-hint .agent-host-hint-dismiss {
|
|
195
|
+
border: none;
|
|
196
|
+
border-radius: 6px;
|
|
197
|
+
padding: 0 8px;
|
|
198
|
+
height: 28px;
|
|
199
|
+
font-size: 12px;
|
|
200
|
+
color: #999;
|
|
201
|
+
background: transparent;
|
|
202
|
+
cursor: pointer;
|
|
203
|
+
}
|
|
204
|
+
#agent-host-launcher-hint .agent-host-hint-dismiss:hover { color: #666; }
|
|
205
|
+
#${p} {
|
|
206
|
+
position: fixed;
|
|
207
|
+
inset: 0;
|
|
208
|
+
z-index: 2147483000;
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
opacity: 0;
|
|
211
|
+
transition: opacity 0.2s ease;
|
|
212
|
+
}
|
|
213
|
+
#${p}.is-open {
|
|
214
|
+
pointer-events: auto;
|
|
215
|
+
opacity: 1;
|
|
216
|
+
}
|
|
217
|
+
#${p} .agent-host-hub-backdrop {
|
|
218
|
+
position: absolute;
|
|
219
|
+
inset: 0;
|
|
220
|
+
background: rgba(15, 23, 42, 0.45);
|
|
221
|
+
}
|
|
222
|
+
#${p} .agent-host-hub-panel-shell {
|
|
223
|
+
position: absolute;
|
|
224
|
+
top: 0;
|
|
225
|
+
right: 0;
|
|
226
|
+
bottom: 0;
|
|
227
|
+
width: min(${J}px, 100vw);
|
|
228
|
+
transform: translateX(100%);
|
|
229
|
+
transition: transform 0.28s cubic-bezier(0.2, 0, 0, 1), width 0.28s cubic-bezier(0.2, 0, 0, 1);
|
|
230
|
+
background: #fff;
|
|
231
|
+
box-shadow: -8px 0 24px rgba(15, 23, 42, 0.14);
|
|
232
|
+
overflow: hidden;
|
|
233
|
+
}
|
|
234
|
+
#${p} .agent-host-hub-panel-shell.is-expanded {
|
|
235
|
+
width: min(50vw, 100vw);
|
|
236
|
+
}
|
|
237
|
+
#${p}.is-open .agent-host-hub-panel-shell {
|
|
238
|
+
transform: translateX(0);
|
|
239
|
+
}
|
|
240
|
+
#${p} iframe {
|
|
241
|
+
width: 100%;
|
|
242
|
+
height: 100%;
|
|
243
|
+
border: none;
|
|
244
|
+
background: #fff;
|
|
245
|
+
display: block;
|
|
246
|
+
}
|
|
247
|
+
@keyframes agent-host-fab-pulse {
|
|
248
|
+
0%, 100% { box-shadow: 0 4px 16px rgba(79, 70, 229, 0.45); }
|
|
249
|
+
50% { box-shadow: 0 4px 24px rgba(124, 58, 237, 0.65); }
|
|
250
|
+
}
|
|
251
|
+
@keyframes agent-host-clover-breathe {
|
|
252
|
+
0%, 100% { transform: scale(1); }
|
|
253
|
+
50% { transform: scale(1.28); }
|
|
254
|
+
}
|
|
255
|
+
/* 提示条四叶草:前 3s 呼吸 2 次(各 1.5s),后 1.5s 缓转一圈,循环 */
|
|
256
|
+
@keyframes agent-host-hint-clover {
|
|
257
|
+
0% { transform: scale(0.88) rotate(0deg); }
|
|
258
|
+
16.67% { transform: scale(1.12) rotate(0deg); }
|
|
259
|
+
33.33% { transform: scale(0.88) rotate(0deg); }
|
|
260
|
+
50% { transform: scale(1.12) rotate(0deg); }
|
|
261
|
+
66.67% { transform: scale(1) rotate(0deg); }
|
|
262
|
+
100% { transform: scale(1) rotate(360deg); }
|
|
263
|
+
}
|
|
264
|
+
@keyframes agent-host-bell-shake {
|
|
265
|
+
0%, 100% { transform: rotate(0deg); }
|
|
266
|
+
12% { transform: rotate(14deg); }
|
|
267
|
+
24% { transform: rotate(-12deg); }
|
|
268
|
+
36% { transform: rotate(10deg); }
|
|
269
|
+
48% { transform: rotate(-8deg); }
|
|
270
|
+
60% { transform: rotate(5deg); }
|
|
271
|
+
72% { transform: rotate(-3deg); }
|
|
272
|
+
84% { transform: rotate(1deg); }
|
|
273
|
+
}
|
|
274
|
+
`, document.head.appendChild(t);
|
|
275
|
+
}
|
|
276
|
+
class ee {
|
|
277
|
+
constructor(e, n, i) {
|
|
278
|
+
l(this, "agentOrigin", "");
|
|
279
|
+
l(this, "hubLauncher", null);
|
|
280
|
+
l(this, "hubLauncherBadge", null);
|
|
281
|
+
l(this, "hubLauncherHint", null);
|
|
282
|
+
l(this, "hubPanelOverlay", null);
|
|
283
|
+
l(this, "hubIframe", null);
|
|
284
|
+
l(this, "widgetIframe", null);
|
|
285
|
+
l(this, "hubReady", !1);
|
|
286
|
+
l(this, "widgetReady", !1);
|
|
287
|
+
l(this, "hubPanelOpen", !1);
|
|
288
|
+
l(this, "hubPanelExpanded", !1);
|
|
289
|
+
l(this, "lastRunning", 0);
|
|
290
|
+
l(this, "lastWaiting", 0);
|
|
291
|
+
l(this, "launcherHintAction", null);
|
|
292
|
+
l(this, "pendingHubMessages", []);
|
|
293
|
+
l(this, "pendingWidgetMessages", []);
|
|
294
|
+
l(this, "onChildMessage");
|
|
295
|
+
l(this, "onHintUse");
|
|
296
|
+
l(this, "onHintDismiss");
|
|
297
|
+
l(this, "handleMessage", (e) => {
|
|
298
|
+
var i, s;
|
|
299
|
+
if (!Z(this.agentOrigin, e.origin) || !K(e.data)) return;
|
|
300
|
+
const n = e.data;
|
|
301
|
+
if (n.type === "ready") {
|
|
302
|
+
n.surface === "hub" ? (this.hubReady = !0, this.flush("hub")) : (this.widgetReady = !0, this.flush("widget"));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (n.type === "hub-panel-close") {
|
|
306
|
+
this.closeHubPanel();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (n.type === "hub-panel-width") {
|
|
310
|
+
this.setHubPanelExpanded(!!n.expanded);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (n.type === "hub-stats") {
|
|
314
|
+
this.updateLauncherStats(n.running, n.waiting), (i = this.onChildMessage) == null || i.call(this, n);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
(s = this.onChildMessage) == null || s.call(this, n);
|
|
318
|
+
});
|
|
319
|
+
this.agentOrigin = X(e), this.onChildMessage = n, this.onHintUse = i == null ? void 0 : i.onHintUse, this.onHintDismiss = i == null ? void 0 : i.onHintDismiss, window.addEventListener("message", this.handleMessage);
|
|
320
|
+
}
|
|
321
|
+
destroy() {
|
|
322
|
+
window.removeEventListener("message", this.handleMessage), this.removeHub(), this.closeWidget();
|
|
323
|
+
}
|
|
324
|
+
/** Launcher(宿主 DOM)+ 固定尺寸 Hub Panel(显隐用 CSS,不改 iframe 尺寸) */
|
|
325
|
+
mountHub() {
|
|
326
|
+
this.hubPanelOverlay || typeof document == "undefined" || (Q(), this.mountLauncher(), this.mountHubPanel());
|
|
327
|
+
}
|
|
328
|
+
openHubPanel() {
|
|
329
|
+
var e;
|
|
330
|
+
this.hubPanelOverlay && (this.hubPanelOpen = !0, this.hubPanelOverlay.classList.add("is-open"), (e = this.hubLauncherHint) == null || e.classList.remove("is-visible"), this.post("hub", { channel: I, type: "open-hub-panel" }), this.applyLauncherVisual());
|
|
331
|
+
}
|
|
332
|
+
closeHubPanel() {
|
|
333
|
+
this.hubPanelOverlay && (this.hubPanelOpen = !1, this.hubPanelOverlay.classList.remove("is-open"), this.setHubPanelExpanded(!1), this.post("hub", { channel: I, type: "close-hub-panel" }), this.updateLauncherHint(this.launcherHintAction), this.applyLauncherVisual());
|
|
334
|
+
}
|
|
335
|
+
setHubPanelExpanded(e) {
|
|
336
|
+
var i;
|
|
337
|
+
this.hubPanelExpanded = e;
|
|
338
|
+
const n = (i = this.hubPanelOverlay) == null ? void 0 : i.querySelector(".agent-host-hub-panel-shell");
|
|
339
|
+
n == null || n.classList.toggle("is-expanded", e);
|
|
340
|
+
}
|
|
341
|
+
updateLauncherHint(e) {
|
|
342
|
+
var s, o;
|
|
343
|
+
this.launcherHintAction = e;
|
|
344
|
+
const n = this.hubLauncherHint;
|
|
345
|
+
if (!n) return;
|
|
346
|
+
if (this.hubPanelOpen) {
|
|
347
|
+
n.classList.remove("is-visible");
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (!e || !e.hint.trim()) {
|
|
351
|
+
n.innerHTML = "", n.classList.remove("is-visible");
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
n.innerHTML = `
|
|
355
|
+
<div class="agent-host-hint-inner">
|
|
356
|
+
<span class="agent-host-hint-icon" aria-hidden="true">✦</span>
|
|
357
|
+
<span class="agent-host-hint-text"></span>
|
|
358
|
+
<div class="agent-host-hint-actions">
|
|
359
|
+
<button type="button" class="agent-host-hint-use">立即开始</button>
|
|
360
|
+
<button type="button" class="agent-host-hint-dismiss">稍后</button>
|
|
361
|
+
</div>
|
|
362
|
+
</div>`;
|
|
363
|
+
const i = n.querySelector(".agent-host-hint-text");
|
|
364
|
+
i && (i.textContent = e.hint), (s = n.querySelector(".agent-host-hint-use")) == null || s.addEventListener("click", (h) => {
|
|
365
|
+
var c;
|
|
366
|
+
h.stopPropagation(), (c = this.onHintUse) == null || c.call(this, e.pageId, e.actionId);
|
|
367
|
+
}), (o = n.querySelector(".agent-host-hint-dismiss")) == null || o.addEventListener("click", (h) => {
|
|
368
|
+
var c;
|
|
369
|
+
h.stopPropagation(), (c = this.onHintDismiss) == null || c.call(this);
|
|
370
|
+
}), n.classList.add("is-visible");
|
|
371
|
+
}
|
|
372
|
+
mountLauncher() {
|
|
373
|
+
if (this.hubLauncher || document.getElementById(u)) return;
|
|
374
|
+
const e = document.createElement("button");
|
|
375
|
+
if (e.id = u, e.type = "button", e.title = "科研AI助手", e.setAttribute("aria-label", "科研AI助手"), e.innerHTML = '<span class="agent-host-launcher-icon" aria-hidden="true">✦</span><span class="agent-host-launcher-bell" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3a5 5 0 0 0-5 5v1.5c0 1.3-.4 2.6-1.2 3.7L4.5 15.5c-.4.5-.1 1.3.5 1.3h14c.6 0 .9-.8.5-1.3l-1.3-2.3A6.6 6.6 0 0 1 17 9.5V8a5 5 0 0 0-5-5Z" fill="#f59e0b"/><path d="M10 18.5a2 2 0 0 0 4 0" stroke="#f59e0b" stroke-width="1.8" stroke-linecap="round"/></svg></span><span class="agent-host-launcher-badge"></span>', e.addEventListener("click", () => this.openHubPanel()), document.body.appendChild(e), this.hubLauncher = e, this.hubLauncherBadge = e.querySelector(".agent-host-launcher-badge"), document.getElementById("agent-host-launcher-hint"))
|
|
376
|
+
this.hubLauncherHint = document.getElementById("agent-host-launcher-hint");
|
|
377
|
+
else {
|
|
378
|
+
const n = document.createElement("div");
|
|
379
|
+
n.id = "agent-host-launcher-hint", document.body.appendChild(n), this.hubLauncherHint = n;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
mountHubPanel() {
|
|
383
|
+
const e = document.createElement("div");
|
|
384
|
+
e.id = p;
|
|
385
|
+
const n = document.createElement("div");
|
|
386
|
+
n.className = "agent-host-hub-backdrop", n.addEventListener("click", () => this.closeHubPanel());
|
|
387
|
+
const i = document.createElement("div");
|
|
388
|
+
i.className = "agent-host-hub-panel-shell";
|
|
389
|
+
const s = document.createElement("iframe");
|
|
390
|
+
s.id = G, s.title = "科研AI助手", s.src = `${this.agentOrigin}/host/hub?embed=1&panel=1`, s.allow = "clipboard-read; clipboard-write", i.appendChild(s), e.appendChild(n), e.appendChild(i), document.body.appendChild(e), this.hubPanelOverlay = e, this.hubIframe = s;
|
|
391
|
+
}
|
|
392
|
+
updateLauncherStats(e, n) {
|
|
393
|
+
this.lastRunning = e, this.lastWaiting = n, this.applyLauncherVisual();
|
|
394
|
+
}
|
|
395
|
+
applyLauncherVisual() {
|
|
396
|
+
const e = this.hubLauncher, n = this.hubLauncherBadge;
|
|
397
|
+
if (!e || !n) return;
|
|
398
|
+
const i = e.querySelector(".agent-host-launcher-icon"), s = e.querySelector(".agent-host-launcher-bell"), o = this.lastRunning, h = this.lastWaiting, c = h > 0 && !this.hubPanelOpen;
|
|
399
|
+
e.classList.toggle("is-pulse", o > 0), e.classList.toggle("is-breathe", (o > 0 || h > 0) && !c), c ? (e.title = "有待确认事项,点击打开助手", e.setAttribute("aria-label", "有待确认事项,点击打开助手")) : (e.title = "科研AI助手", e.setAttribute("aria-label", "科研AI助手")), i && (i.style.display = c ? "none" : ""), s && s.classList.toggle("is-visible", c), o > 0 ? (n.textContent = String(o), n.classList.add("is-visible"), n.classList.remove("is-waiting")) : h > 0 ? (n.textContent = "!", n.classList.add("is-visible", "is-waiting")) : (n.textContent = "", n.classList.remove("is-visible", "is-waiting"));
|
|
400
|
+
}
|
|
401
|
+
removeHub() {
|
|
402
|
+
var e, n, i;
|
|
403
|
+
(e = document.getElementById(u)) == null || e.remove(), (n = document.getElementById("agent-host-launcher-hint")) == null || n.remove(), (i = document.getElementById(p)) == null || i.remove(), this.hubLauncher = null, this.hubLauncherBadge = null, this.hubLauncherHint = null, this.hubPanelOverlay = null, this.hubIframe = null, this.hubReady = !1, this.hubPanelOpen = !1, this.hubPanelExpanded = !1, this.pendingHubMessages = [];
|
|
404
|
+
}
|
|
405
|
+
openWidget(e, n, i) {
|
|
406
|
+
this.closeWidget();
|
|
407
|
+
const s = document.createElement("div");
|
|
408
|
+
s.id = $, s.style.cssText = "position:fixed;inset:0;z-index:2147483646;background:rgba(15,23,42,0.45);display:flex;align-items:center;justify-content:center;padding:16px;", s.addEventListener("click", (D) => {
|
|
409
|
+
D.target === s && this.closeWidget();
|
|
410
|
+
});
|
|
411
|
+
const o = document.createElement("iframe");
|
|
412
|
+
o.id = Y, o.title = e.title || e.workflow;
|
|
413
|
+
const h = new URLSearchParams({
|
|
414
|
+
embed: "1",
|
|
415
|
+
workflow: e.workflow,
|
|
416
|
+
host: e.host || "",
|
|
417
|
+
title: e.title || ""
|
|
418
|
+
});
|
|
419
|
+
o.src = `${this.agentOrigin}/host/widget?${h.toString()}`, o.style.cssText = "width:min(560px,100%);height:80vh;border:none;border-radius:12px;background:#fff;box-shadow:0 20px 60px rgba(0,0,0,0.25);display:block;", s.appendChild(o), document.body.appendChild(s), this.widgetIframe = o, this.widgetReady = !1;
|
|
420
|
+
const c = {
|
|
421
|
+
channel: I,
|
|
422
|
+
type: "init",
|
|
423
|
+
token: n,
|
|
424
|
+
refreshToken: i
|
|
425
|
+
}, g = {
|
|
426
|
+
workflow: e.workflow,
|
|
427
|
+
title: e.title,
|
|
428
|
+
host: e.host,
|
|
429
|
+
prefilled: e.prefilled ? k(e.prefilled) : void 0,
|
|
430
|
+
hostContext: e.hostContext ? k(e.hostContext) : void 0,
|
|
431
|
+
sessionId: e.sessionId,
|
|
432
|
+
preferSandboxFiles: e.preferSandboxFiles
|
|
433
|
+
}, P = {
|
|
434
|
+
channel: I,
|
|
435
|
+
type: "open-widget",
|
|
436
|
+
payload: g
|
|
437
|
+
};
|
|
438
|
+
this.pendingWidgetMessages = [c, P];
|
|
439
|
+
}
|
|
440
|
+
closeWidget() {
|
|
441
|
+
var e;
|
|
442
|
+
(e = document.getElementById($)) == null || e.remove(), this.widgetIframe = null, this.widgetReady = !1, this.pendingWidgetMessages = [];
|
|
443
|
+
}
|
|
444
|
+
sendToHub(e) {
|
|
445
|
+
this.post("hub", e);
|
|
446
|
+
}
|
|
447
|
+
post(e, n) {
|
|
448
|
+
var h;
|
|
449
|
+
const i = e === "hub" ? this.hubReady : this.widgetReady, s = e === "hub" ? this.pendingHubMessages : this.pendingWidgetMessages;
|
|
450
|
+
if (!i) {
|
|
451
|
+
s.push(n);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const o = e === "hub" ? this.hubIframe : this.widgetIframe;
|
|
455
|
+
(h = o == null ? void 0 : o.contentWindow) == null || h.postMessage(n, A(this.agentOrigin));
|
|
456
|
+
}
|
|
457
|
+
flush(e) {
|
|
458
|
+
const n = e === "hub" ? this.pendingHubMessages : this.pendingWidgetMessages, i = e === "hub" ? this.hubIframe : this.widgetIframe;
|
|
459
|
+
if (!(i != null && i.contentWindow)) return;
|
|
460
|
+
const s = A(this.agentOrigin);
|
|
461
|
+
for (; n.length; ) {
|
|
462
|
+
const o = n.shift();
|
|
463
|
+
o && i.contentWindow.postMessage(o, s);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function w(t) {
|
|
468
|
+
return typeof t == "function" ? t() : t;
|
|
469
|
+
}
|
|
470
|
+
const x = {}, H = {};
|
|
471
|
+
let f = null, L = !1;
|
|
472
|
+
function te(t, e) {
|
|
473
|
+
const n = (e || "").trim();
|
|
474
|
+
if (n) return n;
|
|
475
|
+
for (const i of t) {
|
|
476
|
+
if (!i.hostContext) continue;
|
|
477
|
+
const s = w(i.hostContext), o = s && typeof s == "object" ? String(s.refresh || "").trim() : "";
|
|
478
|
+
if (o) return o;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function ne(t, e, n = {}) {
|
|
482
|
+
const i = t !== f;
|
|
483
|
+
i && (L = !1), x[t] = e, f = t, !i && e.some((o) => !o.enabled || o.enabled()) && (L = !1);
|
|
484
|
+
const s = te(e, n.refreshKey);
|
|
485
|
+
s && typeof n.onRefresh == "function" ? H[t] = { refreshKey: s, onRefresh: n.onRefresh } : delete H[t];
|
|
486
|
+
}
|
|
487
|
+
function ie(t) {
|
|
488
|
+
delete x[t], delete H[t], f === t && (f = null);
|
|
489
|
+
}
|
|
490
|
+
function se(t) {
|
|
491
|
+
const e = String(t || "").trim();
|
|
492
|
+
if (e) {
|
|
493
|
+
for (const n of Object.values(H))
|
|
494
|
+
if (n.refreshKey === e)
|
|
495
|
+
try {
|
|
496
|
+
n.onRefresh();
|
|
497
|
+
} catch (i) {
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function oe() {
|
|
502
|
+
for (const t of Object.keys(x)) delete x[t];
|
|
503
|
+
for (const t of Object.keys(H)) delete H[t];
|
|
504
|
+
f = null, L = !1;
|
|
505
|
+
}
|
|
506
|
+
function ae(t) {
|
|
507
|
+
t !== f && (L = !1), f = t;
|
|
508
|
+
}
|
|
509
|
+
function re() {
|
|
510
|
+
L = !0;
|
|
511
|
+
}
|
|
512
|
+
function j(t) {
|
|
513
|
+
return t.map((e) => ({
|
|
514
|
+
id: e.id,
|
|
515
|
+
workflow: e.workflow,
|
|
516
|
+
label: e.label,
|
|
517
|
+
host: e.host,
|
|
518
|
+
hint: e.hint ? w(e.hint) : void 0,
|
|
519
|
+
hostContext: e.hostContext ? k(w(e.hostContext)) : void 0,
|
|
520
|
+
prefilled: e.prefilled ? k(w(e.prefilled)) : void 0,
|
|
521
|
+
enabled: e.enabled ? e.enabled() : !0
|
|
522
|
+
}));
|
|
523
|
+
}
|
|
524
|
+
function T(t, e) {
|
|
525
|
+
const n = (x[t] || []).find((o) => o.id === e);
|
|
526
|
+
if (!n || n.enabled && !n.enabled()) return null;
|
|
527
|
+
const i = n.prefilled ? k(w(n.prefilled)) : void 0, s = (n.workflow || "").trim();
|
|
528
|
+
if (s === "edc_form_fill" && i && typeof i == "object") {
|
|
529
|
+
const o = i;
|
|
530
|
+
if (!o.sub_project_id && !o.subProjectId) return null;
|
|
531
|
+
}
|
|
532
|
+
if (s === "edc_crf_design" && i && typeof i == "object") {
|
|
533
|
+
const o = i;
|
|
534
|
+
if (!o.sub_project_id && !o.subProjectId) return null;
|
|
535
|
+
}
|
|
536
|
+
return {
|
|
537
|
+
workflow: n.workflow,
|
|
538
|
+
title: n.label,
|
|
539
|
+
host: n.host,
|
|
540
|
+
prefilled: i,
|
|
541
|
+
hostContext: n.hostContext ? k(w(n.hostContext)) : void 0
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function le() {
|
|
545
|
+
return f;
|
|
546
|
+
}
|
|
547
|
+
function he() {
|
|
548
|
+
return Object.entries(x).map(([t, e]) => ({ pageId: t, actions: e }));
|
|
549
|
+
}
|
|
550
|
+
function ce() {
|
|
551
|
+
if (L || !f) return null;
|
|
552
|
+
const t = x[f] || [];
|
|
553
|
+
for (const e of t) {
|
|
554
|
+
if (e.enabled && !e.enabled()) continue;
|
|
555
|
+
const n = e.hint ? w(e.hint) : `可使用「${e.label}」`;
|
|
556
|
+
return { pageId: f, actionId: e.id, hint: n };
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
let r = {}, a = null, b = "", E = "", m = null;
|
|
561
|
+
function ue() {
|
|
562
|
+
const t = (r.agentOrigin || "").replace(/\/$/, "");
|
|
563
|
+
if (!t)
|
|
564
|
+
throw new Error(
|
|
565
|
+
"Agent 前端地址未配置:请在 init({ agentOrigin }) 传入,或由宿主 BFF bootstrap 返回 agent_web_origin"
|
|
566
|
+
);
|
|
567
|
+
return t;
|
|
568
|
+
}
|
|
569
|
+
function z(t) {
|
|
570
|
+
var e;
|
|
571
|
+
t.agent_web_origin && (r.agentOrigin = t.agent_web_origin.replace(/\/$/, "")), t.agent_token && (b = t.agent_token), t.refresh_token && (E = t.refresh_token), (e = r.onBootstrap) == null || e.call(r, t);
|
|
572
|
+
}
|
|
573
|
+
function M() {
|
|
574
|
+
return d(this, null, function* () {
|
|
575
|
+
if (r.getToken)
|
|
576
|
+
return b = yield r.getToken(), b;
|
|
577
|
+
if (b) return b;
|
|
578
|
+
if (r.bootstrap) {
|
|
579
|
+
const t = yield r.bootstrap();
|
|
580
|
+
if (z(t), b) return b;
|
|
581
|
+
}
|
|
582
|
+
throw new Error("未连接 Agent:请配置 bootstrap 或 getToken");
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
function v() {
|
|
586
|
+
if (r.agentOrigin)
|
|
587
|
+
try {
|
|
588
|
+
y().updateLauncherHint(ce());
|
|
589
|
+
} catch (t) {
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
function y() {
|
|
593
|
+
const t = ue();
|
|
594
|
+
return a || (a = new ee(t, fe, {
|
|
595
|
+
onHintUse: (e, n) => {
|
|
596
|
+
const i = T(e, n);
|
|
597
|
+
i && O(i);
|
|
598
|
+
},
|
|
599
|
+
onHintDismiss: () => {
|
|
600
|
+
re(), v();
|
|
601
|
+
}
|
|
602
|
+
}), r.showHub !== !1 && a.mountHub()), a;
|
|
603
|
+
}
|
|
604
|
+
function de() {
|
|
605
|
+
if (!(!a || !r.agentOrigin)) {
|
|
606
|
+
for (const { pageId: t, actions: e } of he())
|
|
607
|
+
a.sendToHub({
|
|
608
|
+
channel: "agent-host",
|
|
609
|
+
type: "register-page",
|
|
610
|
+
pageId: t,
|
|
611
|
+
actions: j(e)
|
|
612
|
+
});
|
|
613
|
+
a.sendToHub({
|
|
614
|
+
channel: "agent-host",
|
|
615
|
+
type: "set-page",
|
|
616
|
+
pageId: le()
|
|
617
|
+
}), v();
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
function fe(t) {
|
|
621
|
+
var e;
|
|
622
|
+
if (t.type === "ready" && t.surface === "hub" && M().then((n) => {
|
|
623
|
+
a == null || a.sendToHub({
|
|
624
|
+
channel: "agent-host",
|
|
625
|
+
type: "init",
|
|
626
|
+
token: n,
|
|
627
|
+
refreshToken: E || void 0
|
|
628
|
+
}), de();
|
|
629
|
+
}).catch(() => {
|
|
630
|
+
}), t.type === "started" && (a == null || a.closeWidget(), a == null || a.openHubPanel(), a == null || a.sendToHub({
|
|
631
|
+
channel: "agent-host",
|
|
632
|
+
type: "task-started",
|
|
633
|
+
taskId: t.taskId,
|
|
634
|
+
sessionId: t.sessionId,
|
|
635
|
+
workflow: t.workflow,
|
|
636
|
+
label: t.label || t.workflow,
|
|
637
|
+
formValues: t.formValues,
|
|
638
|
+
prefilled: t.prefilled,
|
|
639
|
+
hostContext: t.hostContext,
|
|
640
|
+
hubContinue: t.hubContinue
|
|
641
|
+
})), t.type === "complete") {
|
|
642
|
+
if (t.status === "success") {
|
|
643
|
+
const n = t.hostContext && t.hostContext.refresh;
|
|
644
|
+
se(n);
|
|
645
|
+
}
|
|
646
|
+
(e = r.onTaskComplete) == null || e.call(r, {
|
|
647
|
+
taskId: t.taskId,
|
|
648
|
+
status: t.status,
|
|
649
|
+
hostContext: t.hostContext
|
|
650
|
+
}), a == null || a.closeWidget();
|
|
651
|
+
}
|
|
652
|
+
if (t.type === "close" && (a == null || a.closeWidget()), t.type === "open-widget" && O(t.payload), t.type === "open-action") {
|
|
653
|
+
const n = T(t.pageId, t.actionId);
|
|
654
|
+
n && O(n);
|
|
655
|
+
}
|
|
656
|
+
t.type === "hub-stats" && (t.running, a == null || a.updateLauncherStats(t.running, t.waiting), v());
|
|
657
|
+
}
|
|
658
|
+
function O(t) {
|
|
659
|
+
return d(this, null, function* () {
|
|
660
|
+
yield C(), r.prepareOpenWidget && (yield r.prepareOpenWidget());
|
|
661
|
+
const e = y(), n = yield M();
|
|
662
|
+
e.openWidget(
|
|
663
|
+
{
|
|
664
|
+
workflow: t.workflow,
|
|
665
|
+
title: t.title || t.label,
|
|
666
|
+
host: t.host || r.host,
|
|
667
|
+
prefilled: t.prefilled,
|
|
668
|
+
hostContext: t.hostContext,
|
|
669
|
+
sessionId: t.sessionId,
|
|
670
|
+
preferSandboxFiles: t.preferSandboxFiles
|
|
671
|
+
},
|
|
672
|
+
n,
|
|
673
|
+
E || void 0
|
|
674
|
+
);
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
function C() {
|
|
678
|
+
return d(this, null, function* () {
|
|
679
|
+
m && (yield m);
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
function ge(t) {
|
|
683
|
+
return d(this, null, function* () {
|
|
684
|
+
if (r = S({ showHub: !0 }, t), r.bootstrap) {
|
|
685
|
+
const e = yield r.bootstrap();
|
|
686
|
+
z(e);
|
|
687
|
+
}
|
|
688
|
+
if (r.agentOrigin && r.showHub !== !1 && typeof document != "undefined")
|
|
689
|
+
try {
|
|
690
|
+
y();
|
|
691
|
+
const e = yield M();
|
|
692
|
+
a == null || a.sendToHub({
|
|
693
|
+
channel: "agent-host",
|
|
694
|
+
type: "init",
|
|
695
|
+
token: e,
|
|
696
|
+
refreshToken: E || void 0
|
|
697
|
+
});
|
|
698
|
+
} catch (e) {
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
const pe = {
|
|
703
|
+
init(t) {
|
|
704
|
+
return d(this, null, function* () {
|
|
705
|
+
m && (yield m), m = ge(t).finally(() => {
|
|
706
|
+
m = null;
|
|
707
|
+
}), yield m;
|
|
708
|
+
});
|
|
709
|
+
},
|
|
710
|
+
getToken() {
|
|
711
|
+
return d(this, null, function* () {
|
|
712
|
+
return yield C(), M();
|
|
713
|
+
});
|
|
714
|
+
},
|
|
715
|
+
registerPage(i, s) {
|
|
716
|
+
return d(this, arguments, function* (t, e, n = {}) {
|
|
717
|
+
yield C(), ne(t, e, n), r.agentOrigin && y().sendToHub({
|
|
718
|
+
channel: "agent-host",
|
|
719
|
+
type: "register-page",
|
|
720
|
+
pageId: t,
|
|
721
|
+
actions: j(e)
|
|
722
|
+
}), v();
|
|
723
|
+
});
|
|
724
|
+
},
|
|
725
|
+
unregisterPage(t) {
|
|
726
|
+
return d(this, null, function* () {
|
|
727
|
+
yield C(), ie(t), r.agentOrigin && (y().sendToHub({ channel: "agent-host", type: "unregister-page", pageId: t }), y().sendToHub({ channel: "agent-host", type: "set-page", pageId: null })), v();
|
|
728
|
+
});
|
|
729
|
+
},
|
|
730
|
+
setCurrentPage(t) {
|
|
731
|
+
return d(this, null, function* () {
|
|
732
|
+
yield C(), ae(t), r.agentOrigin && y().sendToHub({ channel: "agent-host", type: "set-page", pageId: t }), v();
|
|
733
|
+
});
|
|
734
|
+
},
|
|
735
|
+
openAction(t, e) {
|
|
736
|
+
return d(this, null, function* () {
|
|
737
|
+
const n = T(t, e);
|
|
738
|
+
if (!n) throw new Error("当前操作不可用");
|
|
739
|
+
yield O(n);
|
|
740
|
+
});
|
|
741
|
+
},
|
|
742
|
+
openWorkflow(n) {
|
|
743
|
+
return d(this, arguments, function* (t, e = {}) {
|
|
744
|
+
yield O(B(S({
|
|
745
|
+
workflow: t
|
|
746
|
+
}, e), {
|
|
747
|
+
host: e.host || r.host,
|
|
748
|
+
title: e.title || e.label || t
|
|
749
|
+
}));
|
|
750
|
+
});
|
|
751
|
+
},
|
|
752
|
+
/**
|
|
753
|
+
* EDC AI 填表是否可打开:须 prefilled.sub_project_id + forms 列表(表单在 Widget 内选择)。
|
|
754
|
+
*/
|
|
755
|
+
canOpen(t, e = {}) {
|
|
756
|
+
const n = (t || "").trim(), i = e.prefilled || {}, s = String(i.sub_project_id || i.subProjectId || "").trim();
|
|
757
|
+
if (n === "edc_form_fill") {
|
|
758
|
+
const o = i.forms;
|
|
759
|
+
return !!(s && Array.isArray(o) && o.length > 0);
|
|
760
|
+
}
|
|
761
|
+
return n === "edc_crf_design" ? !!s : !0;
|
|
762
|
+
},
|
|
763
|
+
destroy() {
|
|
764
|
+
a == null || a.destroy(), a = null, b = "", E = "", r = {}, m = null, oe();
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
typeof window != "undefined" && (window.AgentHost = pe);
|
|
768
|
+
export {
|
|
769
|
+
I as AGENT_HOST_MSG,
|
|
770
|
+
pe as AgentHost,
|
|
771
|
+
K as isAgentHostMessage
|
|
772
|
+
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
BootstrapResult,
|
|
3
|
+
HostInitOptions,
|
|
4
|
+
HostPageAction,
|
|
5
|
+
OpenWorkflowOptions,
|
|
6
|
+
} from './src/types'
|
|
7
|
+
export type { WidgetPayload, SerializedPageAction } from './src/messages'
|
|
8
|
+
export { AgentHost, AGENT_HOST_MSG, isAgentHostMessage } from './src/index'
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@_daniel_jiang/host-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Agent 平台宿主嵌入 SDK(iframe Hub/Widget,框架无关)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/agent-host.js",
|
|
7
|
+
"module": "./dist/agent-host.mjs",
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/agent-host.mjs",
|
|
12
|
+
"require": "./dist/agent-host.js",
|
|
13
|
+
"default": "./dist/agent-host.mjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/agent-host.js",
|
|
18
|
+
"dist/agent-host.mjs",
|
|
19
|
+
"index.d.ts",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "vite build"
|
|
24
|
+
},
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
}
|
|
31
|
+
}
|