@kweaver-ai/kweaver-sdk 0.5.1 → 0.6.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 +25 -2
- package/README.zh.md +24 -1
- package/dist/api/agent-chat.d.ts +8 -2
- package/dist/api/agent-chat.js +150 -44
- package/dist/api/agent-list.d.ts +35 -0
- package/dist/api/agent-list.js +95 -21
- package/dist/api/bkn-backend.d.ts +60 -0
- package/dist/api/bkn-backend.js +103 -10
- package/dist/api/business-domains.js +9 -5
- package/dist/api/context-loader.js +4 -1
- package/dist/api/conversations.d.ts +6 -3
- package/dist/api/conversations.js +29 -35
- package/dist/api/dataflow.js +1 -10
- package/dist/api/dataflow2.d.ts +95 -0
- package/dist/api/dataflow2.js +80 -0
- package/dist/api/datasources.js +1 -10
- package/dist/api/dataviews.js +1 -10
- package/dist/api/headers.d.ts +11 -0
- package/dist/api/headers.js +30 -0
- package/dist/api/knowledge-networks.d.ts +41 -0
- package/dist/api/knowledge-networks.js +69 -22
- package/dist/api/ontology-query.d.ts +14 -1
- package/dist/api/ontology-query.js +63 -49
- package/dist/api/semantic-search.js +2 -12
- package/dist/api/skills.d.ts +141 -0
- package/dist/api/skills.js +208 -0
- package/dist/api/vega.d.ts +54 -7
- package/dist/api/vega.js +112 -25
- package/dist/auth/oauth.d.ts +5 -1
- package/dist/auth/oauth.js +351 -95
- package/dist/cli.js +49 -5
- package/dist/client.d.ts +12 -0
- package/dist/client.js +52 -8
- package/dist/commands/agent.d.ts +33 -1
- package/dist/commands/agent.js +721 -49
- package/dist/commands/auth.js +226 -55
- package/dist/commands/bkn-ops.d.ts +77 -0
- package/dist/commands/bkn-ops.js +1056 -0
- package/dist/commands/bkn-query.d.ts +14 -0
- package/dist/commands/bkn-query.js +370 -0
- package/dist/commands/bkn-schema.d.ts +135 -0
- package/dist/commands/bkn-schema.js +1483 -0
- package/dist/commands/bkn-utils.d.ts +36 -0
- package/dist/commands/bkn-utils.js +102 -0
- package/dist/commands/bkn.d.ts +7 -113
- package/dist/commands/bkn.js +175 -2429
- package/dist/commands/call.js +8 -5
- package/dist/commands/dataflow.d.ts +1 -0
- package/dist/commands/dataflow.js +251 -0
- package/dist/commands/dataview.d.ts +7 -0
- package/dist/commands/dataview.js +38 -2
- package/dist/commands/ds.d.ts +1 -0
- package/dist/commands/ds.js +8 -1
- package/dist/commands/explore-bkn.d.ts +79 -0
- package/dist/commands/explore-bkn.js +273 -0
- package/dist/commands/explore-chat.d.ts +3 -0
- package/dist/commands/explore-chat.js +193 -0
- package/dist/commands/explore-vega.d.ts +3 -0
- package/dist/commands/explore-vega.js +71 -0
- package/dist/commands/explore.d.ts +9 -0
- package/dist/commands/explore.js +258 -0
- package/dist/commands/import-csv.d.ts +2 -0
- package/dist/commands/import-csv.js +3 -2
- package/dist/commands/skill.d.ts +26 -0
- package/dist/commands/skill.js +524 -0
- package/dist/commands/vega.js +372 -117
- package/dist/config/jwt.d.ts +6 -0
- package/dist/config/jwt.js +21 -0
- package/dist/config/no-auth.d.ts +3 -0
- package/dist/config/no-auth.js +5 -0
- package/dist/config/store.d.ts +45 -5
- package/dist/config/store.js +385 -30
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -1
- package/dist/kweaver.d.ts +5 -0
- package/dist/kweaver.js +32 -2
- package/dist/resources/bkn.d.ts +4 -0
- package/dist/resources/bkn.js +6 -3
- package/dist/resources/conversations.d.ts +5 -2
- package/dist/resources/conversations.js +17 -3
- package/dist/resources/knowledge-networks.js +3 -8
- package/dist/resources/skills.d.ts +47 -0
- package/dist/resources/skills.js +47 -0
- package/dist/resources/vega.d.ts +11 -6
- package/dist/resources/vega.js +37 -10
- package/dist/templates/explorer/app.js +136 -0
- package/dist/templates/explorer/bkn.js +747 -0
- package/dist/templates/explorer/chat.js +980 -0
- package/dist/templates/explorer/dashboard.js +82 -0
- package/dist/templates/explorer/index.html +35 -0
- package/dist/templates/explorer/style.css +2440 -0
- package/dist/templates/explorer/vega.js +291 -0
- package/dist/utils/http.d.ts +3 -0
- package/dist/utils/http.js +37 -1
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -133,19 +133,24 @@ const health = await client.vega.health();
|
|
|
133
133
|
// Context Loader (semantic search over a BKN via MCP)
|
|
134
134
|
const cl = client.contextLoader(mcpUrl, "bkn-id");
|
|
135
135
|
const results = await cl.search({ query: "hypertension treatment" });
|
|
136
|
+
|
|
137
|
+
// Skills (registry + market + progressive read)
|
|
138
|
+
const skills = await client.skills.market({ name: "kweaver" });
|
|
139
|
+
const skillMd = await client.skills.fetchContent("skill-id");
|
|
136
140
|
```
|
|
137
141
|
|
|
138
142
|
## CLI Reference
|
|
139
143
|
|
|
140
144
|
```
|
|
141
|
-
kweaver auth login <url> [--alias name] [-u user] [-p pass] [--playwright] [--insecure|-k]
|
|
145
|
+
kweaver auth login <url> [--alias name] [--no-auth] [-u user] [-p pass] [--playwright] [--insecure|-k]
|
|
142
146
|
kweaver auth login <url> --client-id ID --client-secret S --refresh-token T (headless login)
|
|
143
147
|
kweaver auth export [url|alias] [--json] (export command to run on a headless host)
|
|
144
148
|
kweaver auth status/list/use/delete/logout
|
|
145
149
|
kweaver config show / list-bd / set-bd <value> # platform business domain — after login
|
|
146
150
|
kweaver token
|
|
147
151
|
kweaver ds list/get/delete/tables/connect
|
|
148
|
-
kweaver ds import-csv <ds_id> --files <glob> [--table-prefix <p>] [--batch-size 500]
|
|
152
|
+
kweaver ds import-csv <ds_id> --files <glob> [--table-prefix <p>] [--batch-size 500] [--recreate]
|
|
153
|
+
kweaver dataflow list/run/runs/logs
|
|
149
154
|
kweaver dataview list/find/get/query/delete
|
|
150
155
|
kweaver bkn list/get/stats/export/create/update/delete
|
|
151
156
|
kweaver bkn create-from-ds <ds_id> --name <name> [--tables t1,t2] [--build]
|
|
@@ -158,12 +163,29 @@ kweaver bkn subgraph / search
|
|
|
158
163
|
kweaver bkn action-execution get
|
|
159
164
|
kweaver bkn action-log list/get/cancel
|
|
160
165
|
kweaver agent list/get/create/update/delete/chat/sessions/history/publish/unpublish
|
|
166
|
+
kweaver skill list/market/get/register/status/delete/content/read-file/download/install
|
|
161
167
|
kweaver vega health/stats/inspect/catalog/resource/connector-type
|
|
162
168
|
kweaver context-loader config set/use/list/show
|
|
163
169
|
kweaver context-loader kn-search/query-object-instance/...
|
|
164
170
|
kweaver call <path> [-X METHOD] [-d BODY] [-H header]
|
|
165
171
|
```
|
|
166
172
|
|
|
173
|
+
### Dataflow CLI examples
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
kweaver dataflow list
|
|
177
|
+
kweaver dataflow run <dagId> --file ./demo.pdf
|
|
178
|
+
kweaver dataflow run <dagId> --url https://example.com/demo.pdf --name demo.pdf
|
|
179
|
+
kweaver dataflow runs <dagId>
|
|
180
|
+
kweaver dataflow runs <dagId> --since 2026-04-01
|
|
181
|
+
kweaver dataflow logs <dagId> <instanceId>
|
|
182
|
+
kweaver dataflow logs <dagId> <instanceId> --detail
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`kweaver dataflow runs --since` filters one local natural day. If the value cannot be parsed by `new Date(...)`, the CLI falls back to the most recent 20 runs. `kweaver dataflow logs` defaults to summary output; add `--detail` to print indented `input` and `output` payloads.
|
|
186
|
+
|
|
187
|
+
**No-auth platforms:** If OAuth is not enabled, use `kweaver auth <url> --no-auth` (or run a normal `auth login`; a **404** on `POST /oauth2/clients` switches to no-auth automatically). Credentials are still saved under `~/.kweaver/` and work with `auth use` / `auth list`. Optional: `KWEAVER_NO_AUTH=1` with `KWEAVER_BASE_URL` when no token env is set. SDK: `new KWeaverClient({ baseUrl, auth: false })` or `kweaver.configure({ baseUrl, auth: false })`.
|
|
188
|
+
|
|
167
189
|
## Environment Variables
|
|
168
190
|
|
|
169
191
|
| Variable | Description |
|
|
@@ -171,6 +193,7 @@ kweaver call <path> [-X METHOD] [-d BODY] [-H header]
|
|
|
171
193
|
| `KWEAVER_BASE_URL` | KWeaver instance URL |
|
|
172
194
|
| `KWEAVER_BUSINESS_DOMAIN` | Business domain identifier |
|
|
173
195
|
| `KWEAVER_TOKEN` | Access token |
|
|
196
|
+
| `KWEAVER_NO_AUTH` | Set to `1`/`true`/`yes` to use no-auth sentinel when `KWEAVER_TOKEN` is unset (with `KWEAVER_BASE_URL` or active platform) |
|
|
174
197
|
| `KWEAVER_TLS_INSECURE` | Set to `1` or `true` to skip TLS certificate verification for all HTTPS in the process (dev only; prefer `kweaver auth … --insecure` which saves per platform) |
|
|
175
198
|
| `NODE_TLS_REJECT_UNAUTHORIZED` | Node.js built-in TLS switch: set to `0` to skip certificate verification for HTTPS in this process. The `kweaver` CLI sets this when `KWEAVER_TLS_INSECURE` is set or the saved token has insecure TLS (same scope as above; dev only). |
|
|
176
199
|
|
package/README.zh.md
CHANGED
|
@@ -122,18 +122,23 @@ const queryRows = await client.dataviews.query(viewId, {
|
|
|
122
122
|
// Context Loader(通过 MCP 对 BKN 做语义搜索)
|
|
123
123
|
const cl = client.contextLoader(mcpUrl, "bkn-id");
|
|
124
124
|
const results = await cl.search({ query: "高血压 治疗" });
|
|
125
|
+
|
|
126
|
+
// Skill(注册表/市场/渐进式读取)
|
|
127
|
+
const skills = await client.skills.market({ name: "kweaver" });
|
|
128
|
+
const skillMd = await client.skills.fetchContent("skill-id");
|
|
125
129
|
```
|
|
126
130
|
|
|
127
131
|
## 命令速查
|
|
128
132
|
|
|
129
133
|
```
|
|
130
|
-
kweaver auth login <url> [--alias name] [-u user] [-p pass] [--playwright] [--insecure|-k]
|
|
134
|
+
kweaver auth login <url> [--alias name] [--no-auth] [-u user] [-p pass] [--playwright] [--insecure|-k]
|
|
131
135
|
kweaver auth login <url> --client-id ID --client-secret S --refresh-token T (无浏览器登录)
|
|
132
136
|
kweaver auth export [url|alias] [--json] (导出在无浏览器机器上运行的命令)
|
|
133
137
|
kweaver auth status/list/use/delete/logout
|
|
134
138
|
kweaver config show / list-bd / set-bd <value> # 平台业务域,登录后优先
|
|
135
139
|
kweaver token
|
|
136
140
|
kweaver ds list/get/delete/tables/connect
|
|
141
|
+
kweaver dataflow list/run/runs/logs
|
|
137
142
|
kweaver dataview list/find/get/query/delete
|
|
138
143
|
kweaver bkn list/get/stats/export/create/update/delete
|
|
139
144
|
kweaver bkn object-type list/get/create/update/delete/query/properties
|
|
@@ -143,11 +148,28 @@ kweaver bkn subgraph
|
|
|
143
148
|
kweaver bkn action-execution get
|
|
144
149
|
kweaver bkn action-log list/get/cancel
|
|
145
150
|
kweaver agent list/get/chat/sessions/history
|
|
151
|
+
kweaver skill list/market/get/register/status/delete/content/read-file/download/install
|
|
146
152
|
kweaver context-loader config set/use/list/show
|
|
147
153
|
kweaver context-loader kn-search/query-object-instance/...
|
|
148
154
|
kweaver call <path> [-X METHOD] [-d BODY] [-H header]
|
|
149
155
|
```
|
|
150
156
|
|
|
157
|
+
### Dataflow CLI 示例
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
kweaver dataflow list
|
|
161
|
+
kweaver dataflow run <dagId> --file ./demo.pdf
|
|
162
|
+
kweaver dataflow run <dagId> --url https://example.com/demo.pdf --name demo.pdf
|
|
163
|
+
kweaver dataflow runs <dagId>
|
|
164
|
+
kweaver dataflow runs <dagId> --since 2026-04-01
|
|
165
|
+
kweaver dataflow logs <dagId> <instanceId>
|
|
166
|
+
kweaver dataflow logs <dagId> <instanceId> --detail
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`kweaver dataflow runs --since` 会按本地自然日过滤;如果参数无法被 `new Date(...)` 解析,CLI 会回退到最近 20 条运行记录。`kweaver dataflow logs` 默认输出摘要;加上 `--detail` 会打印带缩进的 `input` 和 `output` 载荷。
|
|
170
|
+
|
|
171
|
+
**无 OAuth 的平台:** 使用 `kweaver auth <url> --no-auth`,或照常 `auth login`;若 `POST /oauth2/clients` 返回 **404**,CLI 会提示并自动保存为 no-auth。凭据仍在 `~/.kweaver/`,可用 `auth use` / `auth list` 切换。可选环境变量 `KWEAVER_NO_AUTH=1`(未设置 `KWEAVER_TOKEN` 时)配合 `KWEAVER_BASE_URL`。SDK:`new KWeaverClient({ baseUrl, auth: false })` 或 `kweaver.configure({ baseUrl, auth: false })`。
|
|
172
|
+
|
|
151
173
|
## 环境变量
|
|
152
174
|
|
|
153
175
|
| 变量 | 说明 |
|
|
@@ -155,6 +177,7 @@ kweaver call <path> [-X METHOD] [-d BODY] [-H header]
|
|
|
155
177
|
| `KWEAVER_BASE_URL` | KWeaver 实例地址 |
|
|
156
178
|
| `KWEAVER_BUSINESS_DOMAIN` | 业务域标识 |
|
|
157
179
|
| `KWEAVER_TOKEN` | 访问令牌 |
|
|
180
|
+
| `KWEAVER_NO_AUTH` | 设为 `1`/`true`/`yes` 且未设置 `KWEAVER_TOKEN` 时使用 no-auth 占位(需 `KWEAVER_BASE_URL` 或已选平台) |
|
|
158
181
|
| `KWEAVER_TLS_INSECURE` | 设为 `1` 或 `true` 时跳过 TLS 证书校验(仅开发;更推荐 `kweaver auth … --insecure` 以按平台持久化) |
|
|
159
182
|
| `NODE_TLS_REJECT_UNAUTHORIZED` | Node.js 内置 TLS 开关:设为 `0` 时在本进程内跳过 HTTPS 证书校验。`kweaver` 在 `KWEAVER_TLS_INSECURE` 生效或已保存 token 为不安全 TLS 时会设置此项(范围同上;仅开发)。 |
|
|
160
183
|
|
package/dist/api/agent-chat.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export interface AgentInfo {
|
|
|
41
41
|
key: string;
|
|
42
42
|
version: string;
|
|
43
43
|
}
|
|
44
|
-
export declare function buildChatUrl(baseUrl: string,
|
|
44
|
+
export declare function buildChatUrl(baseUrl: string, agentKey: string): string;
|
|
45
45
|
export declare function buildAgentInfoUrl(baseUrl: string, agentId: string, version: string): string;
|
|
46
46
|
export declare function fetchAgentInfo(options: {
|
|
47
47
|
baseUrl: string;
|
|
@@ -58,9 +58,15 @@ export declare function processIncrementalUpdate(data: {
|
|
|
58
58
|
}, result: Record<string, unknown>): void;
|
|
59
59
|
export declare function sendChatRequest(options: SendChatRequestOptions): Promise<ChatResult>;
|
|
60
60
|
export interface SendChatRequestStreamCallbacks {
|
|
61
|
-
onTextDelta: (fullText: string) => void;
|
|
61
|
+
onTextDelta: (fullText: string, currentSegmentText: string) => void;
|
|
62
62
|
/** Optional: called when message.content.middle_answer.progress updates (tool/skill steps). */
|
|
63
63
|
onProgress?: (progress: ProgressItem[]) => void;
|
|
64
|
+
/** Optional: called when a text segment is completed and a new phase starts. */
|
|
65
|
+
onSegmentComplete?: (segmentText: string, segmentIndex: number) => void;
|
|
66
|
+
/** Optional: called when answer_type_other changes (step metadata like status, tool info). */
|
|
67
|
+
onStepMeta?: (meta: Record<string, unknown>) => void;
|
|
68
|
+
/** Optional: called as soon as conversationId is discovered in the stream. */
|
|
69
|
+
onConversationId?: (conversationId: string) => void;
|
|
64
70
|
}
|
|
65
71
|
/**
|
|
66
72
|
* Stream-only entry point for TUI: same as sendChatRequest with stream=true,
|
package/dist/api/agent-chat.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNoAuth } from "../config/no-auth.js";
|
|
2
|
+
import { fetchTextOrThrow, fetchWithRetry, HttpError } from "../utils/http.js";
|
|
2
3
|
import { normalizeDisplayText } from "../utils/display-text.js";
|
|
3
4
|
const CHAT_PATH = "/api/agent-factory/v1/app";
|
|
4
5
|
const AGENT_INFO_PATH = "/api/agent-factory/v3/agent-market/agent";
|
|
5
|
-
export function buildChatUrl(baseUrl,
|
|
6
|
+
export function buildChatUrl(baseUrl, agentKey) {
|
|
6
7
|
const base = baseUrl.replace(/\/+$/, "");
|
|
7
|
-
return `${base}${CHAT_PATH}/${
|
|
8
|
+
return `${base}${CHAT_PATH}/${agentKey}/chat/completion`;
|
|
8
9
|
}
|
|
9
10
|
export function buildAgentInfoUrl(baseUrl, agentId, version) {
|
|
10
11
|
const base = baseUrl.replace(/\/+$/, "");
|
|
@@ -13,16 +14,19 @@ export function buildAgentInfoUrl(baseUrl, agentId, version) {
|
|
|
13
14
|
export async function fetchAgentInfo(options) {
|
|
14
15
|
const { baseUrl, accessToken, agentId, version, businessDomain = "bd_public" } = options;
|
|
15
16
|
const url = buildAgentInfoUrl(baseUrl, agentId, version);
|
|
17
|
+
const agentHeaders = {
|
|
18
|
+
accept: "application/json, text/plain, */*",
|
|
19
|
+
"x-business-domain": businessDomain,
|
|
20
|
+
"x-language": "zh-CN",
|
|
21
|
+
"x-requested-with": "XMLHttpRequest",
|
|
22
|
+
};
|
|
23
|
+
if (!isNoAuth(accessToken)) {
|
|
24
|
+
agentHeaders.Authorization = `Bearer ${accessToken}`;
|
|
25
|
+
agentHeaders.token = accessToken;
|
|
26
|
+
}
|
|
16
27
|
const { body } = await fetchTextOrThrow(url, {
|
|
17
28
|
method: "GET",
|
|
18
|
-
headers:
|
|
19
|
-
accept: "application/json, text/plain, */*",
|
|
20
|
-
Authorization: `Bearer ${accessToken}`,
|
|
21
|
-
token: accessToken,
|
|
22
|
-
"x-business-domain": businessDomain,
|
|
23
|
-
"x-language": "zh-CN",
|
|
24
|
-
"x-requested-with": "XMLHttpRequest",
|
|
25
|
-
},
|
|
29
|
+
headers: agentHeaders,
|
|
26
30
|
});
|
|
27
31
|
const data = JSON.parse(body);
|
|
28
32
|
if (!data.id || !data.key) {
|
|
@@ -67,6 +71,19 @@ function stringFromAnswerObject(obj) {
|
|
|
67
71
|
const parts = [d, c ? `code: ${c}` : "", s ? `solution: ${s}` : ""].filter(Boolean);
|
|
68
72
|
return parts.join("\n");
|
|
69
73
|
}
|
|
74
|
+
/** Format answer_type_other which may be an array of strings or an object. */
|
|
75
|
+
function stringFromAnswerTypeOther(other) {
|
|
76
|
+
if (Array.isArray(other)) {
|
|
77
|
+
const strings = other.filter((s) => typeof s === "string" && s);
|
|
78
|
+
if (strings.length > 0)
|
|
79
|
+
return JSON.stringify(strings);
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
if (other && typeof other === "object") {
|
|
83
|
+
return stringFromAnswerObject(other);
|
|
84
|
+
}
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
70
87
|
export function extractText(data) {
|
|
71
88
|
if (!data || typeof data !== "object")
|
|
72
89
|
return "";
|
|
@@ -74,44 +91,44 @@ export function extractText(data) {
|
|
|
74
91
|
const fa = obj.final_answer;
|
|
75
92
|
if (fa?.answer && typeof fa.answer === "object") {
|
|
76
93
|
const ans = fa.answer;
|
|
77
|
-
if (typeof ans.text === "string")
|
|
94
|
+
if (typeof ans.text === "string" && ans.text)
|
|
78
95
|
return ans.text;
|
|
79
96
|
}
|
|
80
|
-
if (typeof fa?.text === "string") {
|
|
97
|
+
if (typeof fa?.text === "string" && fa.text) {
|
|
81
98
|
return fa.text;
|
|
82
99
|
}
|
|
100
|
+
// Check answer_type_other at final_answer level (for content_type "other")
|
|
101
|
+
if (fa?.answer_type_other) {
|
|
102
|
+
const desc = stringFromAnswerTypeOther(fa.answer_type_other);
|
|
103
|
+
if (desc)
|
|
104
|
+
return desc;
|
|
105
|
+
}
|
|
83
106
|
const msg = obj.message;
|
|
84
|
-
if (typeof msg?.text === "string") {
|
|
107
|
+
if (typeof msg?.text === "string" && msg.text) {
|
|
85
108
|
return msg.text;
|
|
86
109
|
}
|
|
87
110
|
if (msg?.content && typeof msg.content === "object") {
|
|
88
111
|
const content = msg.content;
|
|
89
|
-
if (typeof content.text === "string")
|
|
112
|
+
if (typeof content.text === "string" && content.text)
|
|
90
113
|
return content.text;
|
|
91
114
|
const contentFinalAnswer = content.final_answer;
|
|
92
115
|
if (contentFinalAnswer?.answer && typeof contentFinalAnswer.answer === "object") {
|
|
93
116
|
const answer = contentFinalAnswer.answer;
|
|
94
|
-
if (typeof answer.text === "string")
|
|
117
|
+
if (typeof answer.text === "string" && answer.text)
|
|
95
118
|
return answer.text;
|
|
96
119
|
}
|
|
97
|
-
if (typeof contentFinalAnswer?.text === "string") {
|
|
120
|
+
if (typeof contentFinalAnswer?.text === "string" && contentFinalAnswer.text) {
|
|
98
121
|
return contentFinalAnswer.text;
|
|
99
122
|
}
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
const desc =
|
|
123
|
+
// Check answer_type_other at content.final_answer level
|
|
124
|
+
if (contentFinalAnswer?.answer_type_other) {
|
|
125
|
+
const desc = stringFromAnswerTypeOther(contentFinalAnswer.answer_type_other);
|
|
103
126
|
if (desc)
|
|
104
127
|
return desc;
|
|
105
128
|
}
|
|
106
129
|
}
|
|
107
|
-
const topOther = fa?.answer_type_other;
|
|
108
|
-
if (topOther && typeof topOther === "object") {
|
|
109
|
-
const desc = stringFromAnswerObject(topOther);
|
|
110
|
-
if (desc)
|
|
111
|
-
return desc;
|
|
112
|
-
}
|
|
113
130
|
const answer = obj.answer;
|
|
114
|
-
if (typeof answer?.text === "string") {
|
|
131
|
+
if (typeof answer?.text === "string" && answer.text) {
|
|
115
132
|
return answer.text;
|
|
116
133
|
}
|
|
117
134
|
return "";
|
|
@@ -194,7 +211,7 @@ function getProgressFromResult(result) {
|
|
|
194
211
|
};
|
|
195
212
|
});
|
|
196
213
|
}
|
|
197
|
-
function applySseDataLine(line, state, verbose, onTextDelta, onProgress) {
|
|
214
|
+
function applySseDataLine(line, state, verbose, onTextDelta, onProgress, onSegmentComplete, onStepMeta, onConversationId) {
|
|
198
215
|
if (!line.startsWith("data: ")) {
|
|
199
216
|
return;
|
|
200
217
|
}
|
|
@@ -208,21 +225,45 @@ function applySseDataLine(line, state, verbose, onTextDelta, onProgress) {
|
|
|
208
225
|
if (data.key?.length === 1 && data.key[0] === "conversation_id" && data.action === "upsert") {
|
|
209
226
|
state.conversationId =
|
|
210
227
|
typeof data.content === "string" ? data.content : String(data.content ?? "");
|
|
228
|
+
if (state.conversationId && onConversationId) {
|
|
229
|
+
onConversationId(state.conversationId);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Detect answer_type_other changes (step metadata: status, end_time, etc.)
|
|
233
|
+
if (data.key && data.key.join(".").includes("answer_type_other") && data.action === "upsert") {
|
|
234
|
+
const ato = getByPath(state.result, ["message", "content", "final_answer", "answer_type_other"]);
|
|
235
|
+
console.error(`[STEP_META] ${JSON.stringify(ato).slice(0, 500)}`);
|
|
236
|
+
if (ato && typeof ato === "object" && onStepMeta) {
|
|
237
|
+
onStepMeta(ato);
|
|
238
|
+
}
|
|
211
239
|
}
|
|
212
240
|
const progress = getProgressFromResult(state.result);
|
|
213
241
|
if (progress.length > 0 && onProgress) {
|
|
214
242
|
onProgress(progress);
|
|
215
243
|
}
|
|
216
|
-
const
|
|
217
|
-
|
|
244
|
+
const rawText = normalizeDisplayText(extractText(state.result));
|
|
245
|
+
// Detect when the upstream clears text between steps: previous had content, now empty or
|
|
246
|
+
// significantly shorter (new segment starting). Save the completed segment.
|
|
247
|
+
if (state.prevRawText && (!rawText || rawText.length < state.prevRawText.length * 0.5)) {
|
|
248
|
+
state.completedSegments.push(state.prevRawText);
|
|
249
|
+
if (onSegmentComplete) {
|
|
250
|
+
onSegmentComplete(state.prevRawText, state.completedSegments.length - 1);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
state.prevRawText = rawText;
|
|
254
|
+
// Build full text: completed segments + current segment
|
|
255
|
+
const fullText = state.completedSegments.length > 0
|
|
256
|
+
? state.completedSegments.join("\n\n") + (rawText ? "\n\n" + rawText : "")
|
|
257
|
+
: rawText;
|
|
258
|
+
if (fullText && fullText !== state.lastText) {
|
|
218
259
|
if (onTextDelta) {
|
|
219
|
-
onTextDelta(
|
|
260
|
+
onTextDelta(fullText, rawText);
|
|
220
261
|
}
|
|
221
262
|
else {
|
|
222
|
-
const delta =
|
|
263
|
+
const delta = fullText.slice(state.lastText.length);
|
|
223
264
|
process.stdout.write(delta);
|
|
224
265
|
}
|
|
225
|
-
state.lastText =
|
|
266
|
+
state.lastText = fullText;
|
|
226
267
|
}
|
|
227
268
|
}
|
|
228
269
|
catch {
|
|
@@ -233,7 +274,7 @@ function applySseDataLine(line, state, verbose, onTextDelta, onProgress) {
|
|
|
233
274
|
}
|
|
234
275
|
export async function sendChatRequest(options) {
|
|
235
276
|
const { baseUrl, accessToken, agentId, agentKey, agentVersion, query, conversationId, stream, verbose, businessDomain = "bd_public", } = options;
|
|
236
|
-
const url = buildChatUrl(baseUrl,
|
|
277
|
+
const url = buildChatUrl(baseUrl, agentKey);
|
|
237
278
|
const body = {
|
|
238
279
|
agent_id: agentId,
|
|
239
280
|
agent_key: agentKey,
|
|
@@ -247,11 +288,13 @@ export async function sendChatRequest(options) {
|
|
|
247
288
|
const headers = {
|
|
248
289
|
"Content-Type": "application/json",
|
|
249
290
|
accept: stream ? "text/event-stream" : "application/json",
|
|
250
|
-
Authorization: `Bearer ${accessToken}`,
|
|
251
291
|
"Accept-Language": "zh-CN",
|
|
252
292
|
"x-Language": "zh-CN",
|
|
253
293
|
"x-business-domain": businessDomain,
|
|
254
294
|
};
|
|
295
|
+
if (!isNoAuth(accessToken)) {
|
|
296
|
+
headers.Authorization = `Bearer ${accessToken}`;
|
|
297
|
+
}
|
|
255
298
|
if (verbose) {
|
|
256
299
|
console.error(`POST ${url}`);
|
|
257
300
|
const safeHeaders = Object.fromEntries(Object.entries(headers).map(([k, v]) => k.toLowerCase() === "authorization" ? [k, "Bearer ***"] : [k, v]));
|
|
@@ -260,7 +303,7 @@ export async function sendChatRequest(options) {
|
|
|
260
303
|
}
|
|
261
304
|
let response;
|
|
262
305
|
try {
|
|
263
|
-
response = await
|
|
306
|
+
response = await fetchWithRetry(url, {
|
|
264
307
|
method: "POST",
|
|
265
308
|
headers,
|
|
266
309
|
body: JSON.stringify(body),
|
|
@@ -292,7 +335,7 @@ export async function sendChatRequest(options) {
|
|
|
292
335
|
export async function sendChatRequestStream(options, callbacks) {
|
|
293
336
|
const opts = { ...options, stream: true };
|
|
294
337
|
const { baseUrl, accessToken, agentId, agentKey, agentVersion, query, conversationId, verbose, businessDomain = "bd_public", } = opts;
|
|
295
|
-
const url = buildChatUrl(baseUrl,
|
|
338
|
+
const url = buildChatUrl(baseUrl, agentKey);
|
|
296
339
|
const body = {
|
|
297
340
|
agent_id: agentId,
|
|
298
341
|
agent_key: agentKey,
|
|
@@ -306,11 +349,13 @@ export async function sendChatRequestStream(options, callbacks) {
|
|
|
306
349
|
const headers = {
|
|
307
350
|
"Content-Type": "application/json",
|
|
308
351
|
accept: "text/event-stream",
|
|
309
|
-
Authorization: `Bearer ${accessToken}`,
|
|
310
352
|
"Accept-Language": "zh-CN",
|
|
311
353
|
"x-Language": "zh-CN",
|
|
312
354
|
"x-business-domain": businessDomain,
|
|
313
355
|
};
|
|
356
|
+
if (!isNoAuth(accessToken)) {
|
|
357
|
+
headers.Authorization = `Bearer ${accessToken}`;
|
|
358
|
+
}
|
|
314
359
|
if (verbose) {
|
|
315
360
|
console.error(`POST ${url}`);
|
|
316
361
|
const safeHeaders = Object.fromEntries(Object.entries(headers).map(([k, v]) => k.toLowerCase() === "authorization" ? [k, "Bearer ***"] : [k, v]));
|
|
@@ -319,7 +364,7 @@ export async function sendChatRequestStream(options, callbacks) {
|
|
|
319
364
|
}
|
|
320
365
|
let response;
|
|
321
366
|
try {
|
|
322
|
-
response = await
|
|
367
|
+
response = await fetchWithRetry(url, {
|
|
323
368
|
method: "POST",
|
|
324
369
|
headers,
|
|
325
370
|
body: JSON.stringify(body),
|
|
@@ -335,29 +380,75 @@ export async function sendChatRequestStream(options, callbacks) {
|
|
|
335
380
|
throw new HttpError(response.status, response.statusText, text);
|
|
336
381
|
}
|
|
337
382
|
if (contentType.includes("text/event-stream")) {
|
|
338
|
-
return handleStreamResponse(response, verbose, callbacks.onTextDelta, callbacks.onProgress);
|
|
383
|
+
return handleStreamResponse(response, verbose, callbacks.onTextDelta, callbacks.onProgress, callbacks.onSegmentComplete, callbacks.onStepMeta, callbacks.onConversationId);
|
|
339
384
|
}
|
|
340
385
|
const text = await response.text();
|
|
341
386
|
const json = parseJsonResponse(text);
|
|
342
387
|
const resultText = normalizeDisplayText(extractText(json));
|
|
343
388
|
const convId = json.conversation_id;
|
|
344
|
-
callbacks.onTextDelta(resultText);
|
|
389
|
+
callbacks.onTextDelta(resultText, resultText);
|
|
345
390
|
return { text: resultText, conversationId: convId, progress: getProgressFromResult(json) };
|
|
346
391
|
}
|
|
347
|
-
async function handleStreamResponse(response, verbose, onTextDelta, onProgress) {
|
|
392
|
+
async function handleStreamResponse(response, verbose, onTextDelta, onProgress, onSegmentComplete, onStepMeta, onConversationId) {
|
|
348
393
|
const reader = response.body?.getReader();
|
|
349
394
|
if (!reader) {
|
|
350
395
|
throw new Error("No response body for stream");
|
|
351
396
|
}
|
|
352
397
|
const decoder = new TextDecoder();
|
|
353
398
|
let buffer = "";
|
|
399
|
+
let pendingEventType = "";
|
|
354
400
|
const state = {
|
|
355
401
|
result: {},
|
|
356
402
|
conversationId: undefined,
|
|
357
403
|
lastText: "",
|
|
404
|
+
completedSegments: [],
|
|
405
|
+
prevRawText: "",
|
|
358
406
|
};
|
|
359
407
|
const applyLine = (line) => {
|
|
360
|
-
|
|
408
|
+
// Track SSE event type (e.g., "event:error")
|
|
409
|
+
if (line.startsWith("event:")) {
|
|
410
|
+
pendingEventType = line.slice(6).trim();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
// If we have an error event type, handle the data line as an error
|
|
414
|
+
if (pendingEventType === "error" && line.startsWith("data: ")) {
|
|
415
|
+
pendingEventType = "";
|
|
416
|
+
const errStr = line.slice(6).trim();
|
|
417
|
+
// Emit as error text rather than processing as incremental update
|
|
418
|
+
if (onTextDelta) {
|
|
419
|
+
let errMsg = errStr;
|
|
420
|
+
let errDetail = "";
|
|
421
|
+
try {
|
|
422
|
+
const errObj = JSON.parse(errStr);
|
|
423
|
+
errMsg = errObj.description || errObj.details || errStr;
|
|
424
|
+
if (errObj.solution && errObj.solution !== "无")
|
|
425
|
+
errMsg += "\n💡 " + errObj.solution;
|
|
426
|
+
// Collect all remaining fields as detail context
|
|
427
|
+
const detailFields = {};
|
|
428
|
+
for (const [k, v] of Object.entries(errObj)) {
|
|
429
|
+
if (k !== "description" && k !== "solution" && v != null && v !== "") {
|
|
430
|
+
detailFields[k] = v;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (Object.keys(detailFields).length > 0) {
|
|
434
|
+
errDetail = "\n\n<details><summary>详细错误信息</summary>\n\n```json\n" + JSON.stringify(detailFields, null, 2) + "\n```\n</details>";
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
if (verbose)
|
|
439
|
+
console.error("Failed to parse SSE error JSON:", errStr);
|
|
440
|
+
}
|
|
441
|
+
const errText = "⚠️ " + errMsg + errDetail;
|
|
442
|
+
const fullText = state.completedSegments.length > 0
|
|
443
|
+
? state.completedSegments.join("\n\n") + "\n\n" + errText
|
|
444
|
+
: errText;
|
|
445
|
+
onTextDelta(fullText, errText);
|
|
446
|
+
state.lastText = fullText;
|
|
447
|
+
}
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
pendingEventType = "";
|
|
451
|
+
applySseDataLine(line, state, verbose, onTextDelta, onProgress, onSegmentComplete, onStepMeta, onConversationId);
|
|
361
452
|
};
|
|
362
453
|
while (true) {
|
|
363
454
|
const { done, value } = await reader.read();
|
|
@@ -376,6 +467,21 @@ async function handleStreamResponse(response, verbose, onTextDelta, onProgress)
|
|
|
376
467
|
if (!onTextDelta && state.lastText && !state.lastText.endsWith("\n")) {
|
|
377
468
|
process.stdout.write("\n");
|
|
378
469
|
}
|
|
379
|
-
|
|
470
|
+
// Fallback: try to extract conversationId from accumulated result if not found in stream
|
|
471
|
+
if (!state.conversationId) {
|
|
472
|
+
const r = state.result;
|
|
473
|
+
const candidate = r.conversation_id ??
|
|
474
|
+
r.message?.conversation_id ??
|
|
475
|
+
r.conversationId;
|
|
476
|
+
if (typeof candidate === "string" && candidate) {
|
|
477
|
+
state.conversationId = candidate;
|
|
478
|
+
if (onConversationId)
|
|
479
|
+
onConversationId(candidate);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const rawFinal = normalizeDisplayText(extractText(state.result));
|
|
483
|
+
const finalText = state.completedSegments.length > 0
|
|
484
|
+
? state.completedSegments.join("\n\n") + (rawFinal ? "\n\n" + rawFinal : "")
|
|
485
|
+
: rawFinal || state.lastText;
|
|
380
486
|
return { text: finalText, conversationId: state.conversationId };
|
|
381
487
|
}
|
package/dist/api/agent-list.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ export interface PublishAgentOptions {
|
|
|
51
51
|
accessToken: string;
|
|
52
52
|
agentId: string;
|
|
53
53
|
body?: string;
|
|
54
|
+
categoryId?: string;
|
|
54
55
|
businessDomain?: string;
|
|
55
56
|
}
|
|
56
57
|
export declare function publishAgent(options: PublishAgentOptions): Promise<string>;
|
|
@@ -61,3 +62,37 @@ export interface UnpublishAgentOptions {
|
|
|
61
62
|
businessDomain?: string;
|
|
62
63
|
}
|
|
63
64
|
export declare function unpublishAgent(options: UnpublishAgentOptions): Promise<void>;
|
|
65
|
+
export interface ListPersonalAgentsOptions {
|
|
66
|
+
baseUrl: string;
|
|
67
|
+
accessToken: string;
|
|
68
|
+
businessDomain?: string;
|
|
69
|
+
name?: string;
|
|
70
|
+
pagination_marker_str?: string;
|
|
71
|
+
publish_status?: string;
|
|
72
|
+
publish_to_be?: string;
|
|
73
|
+
size?: number;
|
|
74
|
+
}
|
|
75
|
+
export declare function listPersonalAgents(options: ListPersonalAgentsOptions): Promise<string>;
|
|
76
|
+
export interface ListPublishedAgentTemplatesOptions {
|
|
77
|
+
baseUrl: string;
|
|
78
|
+
accessToken: string;
|
|
79
|
+
businessDomain?: string;
|
|
80
|
+
category_id?: string;
|
|
81
|
+
name?: string;
|
|
82
|
+
pagination_marker_str?: string;
|
|
83
|
+
size?: number;
|
|
84
|
+
}
|
|
85
|
+
export declare function listPublishedAgentTemplates(options: ListPublishedAgentTemplatesOptions): Promise<string>;
|
|
86
|
+
export interface GetPublishedAgentTemplateOptions {
|
|
87
|
+
baseUrl: string;
|
|
88
|
+
accessToken: string;
|
|
89
|
+
templateId: string;
|
|
90
|
+
businessDomain?: string;
|
|
91
|
+
}
|
|
92
|
+
export declare function getPublishedAgentTemplate(options: GetPublishedAgentTemplateOptions): Promise<string>;
|
|
93
|
+
export interface ListAgentCategoriesOptions {
|
|
94
|
+
baseUrl: string;
|
|
95
|
+
accessToken: string;
|
|
96
|
+
businessDomain?: string;
|
|
97
|
+
}
|
|
98
|
+
export declare function listAgentCategories(options: ListAgentCategoriesOptions): Promise<string>;
|