@gt-fe/eap-cli 0.2.1 → 0.2.3

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.
Files changed (50) hide show
  1. package/README.md +304 -311
  2. package/dist/commands/create.js +1 -1
  3. package/dist/commands/create.js.map +1 -1
  4. package/dist/commands/install.d.ts.map +1 -1
  5. package/dist/commands/install.js +9 -26
  6. package/dist/commands/install.js.map +1 -1
  7. package/dist/templates/README.md +51 -51
  8. package/dist/templates/agent-api-orchestration/.env +16 -0
  9. package/dist/templates/agent-api-orchestration/README.md +326 -327
  10. package/dist/templates/agent-api-orchestration/agent.manifest.json +1 -1
  11. package/dist/templates/agent-api-orchestration/eap.config.json +10 -6
  12. package/dist/templates/agent-api-orchestration/gitignore +0 -3
  13. package/dist/templates/agent-api-orchestration/graph.json +30 -45
  14. package/dist/templates/agent-api-orchestration/package.json +2 -2
  15. package/dist/templates/agent-api-orchestration/scripts/api-test.mjs +443 -0
  16. package/dist/templates/agent-api-orchestration/scripts/build-runtime.mjs +2 -4
  17. package/dist/templates/agent-api-orchestration/src/embedded-agent.ts +12 -0
  18. package/dist/templates/agent-api-orchestration/src/index.ts +2 -9
  19. package/dist/templates/dag-workflow/README.md +102 -102
  20. package/dist/templates/dag-workflow/agent.manifest.json +19 -19
  21. package/dist/templates/dag-workflow/eap.config.json +7 -3
  22. package/dist/templates/dag-workflow/gitignore +51 -51
  23. package/dist/templates/dag-workflow/graph.json +56 -56
  24. package/dist/templates/dag-workflow/skills/README.md +116 -116
  25. package/dist/templates/plan-and-execute/README.md +109 -109
  26. package/dist/templates/plan-and-execute/agent.manifest.json +19 -19
  27. package/dist/templates/plan-and-execute/eap.config.json +7 -3
  28. package/dist/templates/plan-and-execute/eap.lock.yaml +8 -8
  29. package/dist/templates/plan-and-execute/gitignore +51 -51
  30. package/dist/templates/plan-and-execute/graph.json +53 -53
  31. package/dist/templates/plan-and-execute/skills/README.md +120 -120
  32. package/dist/templates/simple-flow/README.md +85 -85
  33. package/dist/templates/simple-flow/agent.manifest.json +19 -19
  34. package/dist/templates/simple-flow/eap.config.json +7 -3
  35. package/dist/templates/simple-flow/gitignore +51 -51
  36. package/dist/templates/simple-flow/graph.json +35 -35
  37. package/dist/templates/simple-flow/package.json +10 -10
  38. package/dist/templates/simple-flow/skills/README.md +113 -113
  39. package/dist/templates/single-agent-with-tools/README.md +138 -138
  40. package/dist/templates/single-agent-with-tools/agent.manifest.json +19 -22
  41. package/dist/templates/single-agent-with-tools/eap.config.json +7 -3
  42. package/dist/templates/single-agent-with-tools/eap.lock.yaml +5 -13
  43. package/dist/templates/single-agent-with-tools/gitignore +51 -51
  44. package/dist/templates/single-agent-with-tools/graph.json +46 -46
  45. package/dist/templates/single-agent-with-tools/skills/README.md +119 -119
  46. package/dist/templates/single-agent-with-tools/tools/http-weather/toolset.manifest.json +73 -73
  47. package/dist/templates/single-agent-with-tools/tools/web-search/toolset.manifest.json +41 -41
  48. package/package.json +2 -2
  49. package/dist/templates/agent-api-orchestration/.env.local.example +0 -17
  50. package/dist/templates/agent-api-orchestration/.env.production.example +0 -18
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "models": {
12
12
  "default": "DeepSeek-V4-Pro",
13
- "allowed": ["DeepSeek-V4-Pro"]
13
+ "allowed": ["DeepSeek-V4-Pro", "DeepSeek-V4-Flash"]
14
14
  },
15
15
  "metadata": {
16
16
  "owner": "agent-api-orchestration-template",
@@ -1,9 +1,13 @@
1
1
  {
2
- "version": "0.2.1",
3
- "localToolDirectories": ["./tools"],
4
- "localSkillDirectories": ["./skills"],
2
+ "version": "0.2.3",
3
+ "localToolDirectories": [
4
+ "./tools"
5
+ ],
6
+ "localSkillDirectories": [
7
+ "./skills"
8
+ ],
5
9
  "platform": {
6
- "foundationServiceUrl": null,
10
+ "foundationServiceUrl": "https://eap-foundation-test.gtcloud.cn",
7
11
  "portalUrl": "https://developer-portal-test.gtcloud.cn"
8
12
  },
9
13
  "runtime": {
@@ -24,11 +28,11 @@
24
28
  "models": {
25
29
  "DeepSeek-V4-Pro": {
26
30
  "baseUrl": "https://gtaiapi.gtcloud.cn/v1",
27
- "apiKey": "${OPENAI_API_KEY}"
31
+ "apiKey": "sk-example-token"
28
32
  },
29
33
  "DeepSeek-V4-Flash": {
30
34
  "baseUrl": "https://gtaiapi.gtcloud.cn/v1",
31
- "apiKey": "${OPENAI_API_KEY}"
35
+ "apiKey": "sk-example-token"
32
36
  }
33
37
  }
34
38
  }
@@ -1,6 +1,3 @@
1
1
  node_modules/
2
2
  dist/
3
3
  .eap/
4
- .env
5
- .env.local
6
- .env.production
@@ -1,45 +1,30 @@
1
- {
2
- "description": "用于演示 Agent API 编排的最小模型流程(含 RAG 多源检索)。",
3
- "state": {
4
- "userRequest": "string",
5
- "response": "string"
6
- },
7
- "nodes": [
8
- {
9
- "id": "rag",
10
- "type": "rag",
11
- "config": {
12
- "model": "DeepSeek-V4-Pro",
13
- "totalK": 10,
14
- "maxIterations": 5,
15
- "retrievalSources": {
16
- "sources": [
17
- { "type": "local-file", "id": "共享资料", "source": "./docs" }
18
- ]
19
- }
20
- }
21
- },
22
- {
23
- "id": "respond",
24
- "type": "llm",
25
- "config": {
26
- "model": "DeepSeek-V4-Pro",
27
- "disableTools": true,
28
- "systemPrompt": "你是企业知识与数据问答助手。上游 rag 节点已完成多源检索并把结果放在上下文中([rag] 消息),请仅依据检索到的内容回答;检索结果不足以回答时明确说明,并标注信息来源。"
29
- }
30
- }
31
- ],
32
- "edges": [
33
- { "from": "__start__", "to": "rag" },
34
- { "from": "rag", "to": "respond" },
35
- { "from": "respond", "to": "__end__" }
36
- ],
37
- "entryPoint": "rag",
38
- "finishPoints": ["__end__"],
39
- "config": {
40
- "maxIterations": 50,
41
- "maxRetries": 3,
42
- "timeout": 120000,
43
- "checkpointStore": "memory"
44
- }
45
- }
1
+ {
2
+ "description": "用于演示 Agent API 编排的最小模型流程(含 RAG 多源检索)。",
3
+ "state": {
4
+ "userRequest": "string",
5
+ "response": "string"
6
+ },
7
+ "nodes": [
8
+ {
9
+ "id": "respond",
10
+ "type": "llm",
11
+ "config": {
12
+ "model": "DeepSeek-V4-Pro",
13
+ "disableTools": true,
14
+ "systemPrompt": "你是企业知识与数据问答助手,请根据用户的问题直接回答。"
15
+ }
16
+ }
17
+ ],
18
+ "edges": [
19
+ { "from": "__start__", "to": "respond" },
20
+ { "from": "respond", "to": "__end__" }
21
+ ],
22
+ "entryPoint": "respond",
23
+ "finishPoints": ["__end__"],
24
+ "config": {
25
+ "maxIterations": 50,
26
+ "maxRetries": 3,
27
+ "timeout": 120000,
28
+ "checkpointStore": "memory"
29
+ }
30
+ }
@@ -14,14 +14,14 @@
14
14
  "type-check": "tsc --noEmit"
15
15
  },
16
16
  "dependencies": {
17
- "@gt-fe/eap-sdk": "^0.2.1",
17
+ "@gt-fe/eap-sdk": "^0.2.3",
18
18
  "dotenv": "^17.2.2",
19
19
  "express": "^4.21.2"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/express": "^4.17.21",
23
23
  "@types/node": "^22.0.0",
24
- "esbuild": "^0.25.0",
24
+ "esbuild": "^0.28.2",
25
25
  "tsx": "^4.19.2",
26
26
  "typescript": "^5.5.0"
27
27
  },
@@ -0,0 +1,443 @@
1
+ /**
2
+ * Agent API 接口测试脚本(可直接运行)
3
+ *
4
+ * 用法:
5
+ * node scripts/api-test.mjs
6
+ *
7
+ * 可选环境变量:
8
+ * BASE_URL 服务地址,默认 http://127.0.0.1:3000
9
+ * AGENT_CODE Agent code,默认 agent-test
10
+ * TEST_MESSAGE 发送给 Agent 的测试消息,默认“你好,请用一句话介绍你自己”
11
+ *
12
+ * 会依次覆盖:健康检查、能力发现、会话增查、消息发送(同步调用)、
13
+ * 历史消息查询、无会话同步调用、流式对话、归档、恢复(预期 501)。
14
+ * 每个用例独立 try/catch,失败不中断后续用例,最后打印汇总。
15
+ */
16
+
17
+ const BASE_URL = (process.env.BASE_URL || "http://127.0.0.1:3000").replace(
18
+ /\/+$/,
19
+ "",
20
+ );
21
+ const AGENT_CODE = process.env.AGENT_CODE || "agent-test";
22
+ const TEST_MESSAGE = process.env.TEST_MESSAGE || "你好,请用一句话介绍你自己";
23
+
24
+ const api = (path) => `${BASE_URL}/api/v1/agents/${AGENT_CODE}${path}`;
25
+
26
+ let step = 0;
27
+ let passed = 0;
28
+ let failed = 0;
29
+ const failures = [];
30
+
31
+ // ---------- 工具函数 ----------
32
+
33
+ function header(title) {
34
+ console.log("\n" + "═".repeat(70));
35
+ console.log(` ${title}`);
36
+ console.log("═".repeat(70));
37
+ }
38
+
39
+ function log(label, value) {
40
+ console.log(` ▶ ${label}`);
41
+ if (value !== undefined) console.log(pretty(value, 2));
42
+ }
43
+
44
+ function ok(msg) {
45
+ passed += 1;
46
+ console.log(` ✅ [PASS] ${msg}`);
47
+ }
48
+
49
+ function fail(msg, detail) {
50
+ failed += 1;
51
+ failures.push({ msg, detail });
52
+ console.log(` ❌ [FAIL] ${msg}`);
53
+ if (detail !== undefined) console.log(pretty(detail, 2));
54
+ }
55
+
56
+ function pretty(value, indent = 0) {
57
+ const text =
58
+ typeof value === "string" ? value : JSON.stringify(value, null, indent);
59
+ const lines = text.split("\n");
60
+ const head = lines.slice(0, 40);
61
+ let out = " " + head.join("\n ");
62
+ if (lines.length > 40) out += `\n ... (共 ${lines.length} 行,已截断)`;
63
+ return out;
64
+ }
65
+
66
+ function truncate(value, max = 800) {
67
+ const text =
68
+ value == null
69
+ ? ""
70
+ : typeof value === "string"
71
+ ? value
72
+ : JSON.stringify(value);
73
+ return text.length > max
74
+ ? text.slice(0, max) + `... (共 ${text.length} 字符)`
75
+ : text;
76
+ }
77
+
78
+ async function request(
79
+ method,
80
+ url,
81
+ { body, headers = {}, timeout = 30000 } = {},
82
+ ) {
83
+ const controller = new AbortController();
84
+ const timer = setTimeout(() => controller.abort(), timeout);
85
+ try {
86
+ const response = await fetch(url, {
87
+ method,
88
+ headers: { "Content-Type": "application/json", ...headers },
89
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
90
+ signal: controller.signal,
91
+ });
92
+ const text = await response.text();
93
+ let data;
94
+ try {
95
+ data = text ? JSON.parse(text) : null;
96
+ } catch {
97
+ data = text;
98
+ }
99
+ return { status: response.status, data, ok: response.ok };
100
+ } catch (error) {
101
+ const message =
102
+ error?.name === "AbortError"
103
+ ? `请求超时(${timeout}ms)`
104
+ : (error?.message ?? String(error));
105
+ return { status: 0, data: null, ok: false, error: message };
106
+ } finally {
107
+ clearTimeout(timer);
108
+ }
109
+ }
110
+
111
+ /** 消费 SSE 流,返回 [{ event, data }],data 已解析为 JSON。 */
112
+ async function consumeSse(url, { body, timeout = 120000 } = {}) {
113
+ const controller = new AbortController();
114
+ const timer = setTimeout(() => controller.abort(), timeout);
115
+ const events = [];
116
+ try {
117
+ const response = await fetch(url, {
118
+ method: "POST",
119
+ headers: { "Content-Type": "application/json" },
120
+ body: JSON.stringify(body),
121
+ signal: controller.signal,
122
+ });
123
+ if (!response.ok || !response.body) {
124
+ const text = await response.text();
125
+ return { status: response.status, events, raw: text };
126
+ }
127
+ const reader = response.body.getReader();
128
+ const decoder = new TextDecoder();
129
+ let buffer = "";
130
+ while (true) {
131
+ const { done, value } = await reader.read();
132
+ if (done) break;
133
+ buffer += decoder.decode(value, { stream: true });
134
+ const frames = buffer.split("\n\n");
135
+ buffer = frames.pop() ?? "";
136
+ for (const frame of frames) {
137
+ const eventLine = frame.split("\n").find((l) => l.startsWith("event:"));
138
+ const dataLine = frame.split("\n").find((l) => l.startsWith("data:"));
139
+ if (!dataLine) continue;
140
+ const type = eventLine ? eventLine.slice(6).trim() : "message";
141
+ let data;
142
+ try {
143
+ data = JSON.parse(dataLine.slice(5).trim());
144
+ } catch {
145
+ data = dataLine.slice(5).trim();
146
+ }
147
+ events.push({ event: type, data });
148
+ }
149
+ }
150
+ return { status: response.status, events };
151
+ } finally {
152
+ clearTimeout(timer);
153
+ }
154
+ }
155
+
156
+ function assert(condition, message) {
157
+ if (!condition) throw new Error(message);
158
+ }
159
+
160
+ // ---------- 测试用例 ----------
161
+
162
+ async function testHealth() {
163
+ const name = "健康检查";
164
+ header(`${name} · GET /health`);
165
+ const { status, data } = await request("GET", `${BASE_URL}/health`);
166
+ log("响应", data);
167
+ try {
168
+ assert(status === 200, `期望 200,实际 ${status}`);
169
+ assert(
170
+ data?.status === "ok",
171
+ `期望 status=ok,实际 ${JSON.stringify(data)}`,
172
+ );
173
+ assert(
174
+ data?.agentCode === AGENT_CODE,
175
+ `期望 agentCode=${AGENT_CODE},实际 ${data?.agentCode}`,
176
+ );
177
+ ok(name);
178
+ } catch (e) {
179
+ fail(name, e.message);
180
+ }
181
+ }
182
+
183
+ async function testCapability() {
184
+ const name = "能力发现";
185
+ header(`${name} · GET ${api("")}`);
186
+ const { status, data } = await request("GET", api(""));
187
+ log("响应(截断)", truncate(data, 1200));
188
+ try {
189
+ assert(status === 200, `期望 200,实际 ${status}`);
190
+ assert(
191
+ data?.agent?.code === AGENT_CODE,
192
+ `期望 agent.code=${AGENT_CODE},实际 ${data?.agent?.code}`,
193
+ );
194
+ assert(
195
+ data?.capabilities?.stream === true,
196
+ "期望 capabilities.stream=true",
197
+ );
198
+ assert(Array.isArray(data?.graph?.nodes), "期望 graph.nodes 为数组");
199
+ ok(
200
+ `${name}(版本 ${data?.agent?.version},节点 ${data?.graph?.nodes?.length ?? 0} 个)`,
201
+ );
202
+ } catch (e) {
203
+ fail(name, e.message);
204
+ }
205
+ }
206
+
207
+ async function testCreateSession() {
208
+ const name = "创建会话";
209
+ header(`${name} · POST ${api("/sessions")}`);
210
+ const { status, data } = await request("POST", api("/sessions"), {
211
+ body: { userId: "test-user", title: "接口测试会话" },
212
+ });
213
+ log("响应", data);
214
+ try {
215
+ assert(status === 201, `期望 201,实际 ${status}`);
216
+ assert(data?.id, `期望返回 session.id,实际 ${JSON.stringify(data)}`);
217
+ ok(name);
218
+ return data.id;
219
+ } catch (e) {
220
+ fail(name, e.message);
221
+ return undefined;
222
+ }
223
+ }
224
+
225
+ async function testListSessions() {
226
+ const name = "查询会话列表";
227
+ header(`${name} · GET ${api("/sessions?limit=20&offset=0")}`);
228
+ const { status, data } = await request(
229
+ "GET",
230
+ `${api("/sessions")}?limit=20&offset=0`,
231
+ );
232
+ log("响应", data);
233
+ try {
234
+ assert(status === 200, `期望 200,实际 ${status}`);
235
+ assert(
236
+ Array.isArray(data?.items) || Array.isArray(data),
237
+ `期望返回会话列表,实际 ${JSON.stringify(data)}`,
238
+ );
239
+ ok(name);
240
+ } catch (e) {
241
+ fail(name, e.message);
242
+ }
243
+ }
244
+
245
+ async function testGetSession(sessionId) {
246
+ const name = "查询会话详情";
247
+ header(`${name} · GET ${api(`/sessions/${sessionId}`)}`);
248
+ const { status, data } = await request("GET", api(`/sessions/${sessionId}`));
249
+ log("响应", data);
250
+ try {
251
+ assert(status === 200, `期望 200,实际 ${status}`);
252
+ assert(data?.id === sessionId, `期望 id=${sessionId},实际 ${data?.id}`);
253
+ ok(name);
254
+ } catch (e) {
255
+ fail(name, e.message);
256
+ }
257
+ }
258
+
259
+ async function testSendMessage(sessionId) {
260
+ const name = "发送消息(同步调用)";
261
+ header(`${name} · POST ${api(`/sessions/${sessionId}/messages`)}`);
262
+ const { status, data } = await request(
263
+ "POST",
264
+ api(`/sessions/${sessionId}/messages`),
265
+ {
266
+ body: { content: TEST_MESSAGE },
267
+ timeout: 120000,
268
+ },
269
+ );
270
+ log("响应", truncate(data, 1200));
271
+ try {
272
+ assert(status === 200, `期望 200,实际 ${status}`);
273
+ const output = data?.output;
274
+ log("Agent 回复", truncate(output, 1200));
275
+ assert(
276
+ data?.status === "success",
277
+ `期望 status=success,实际 ${data?.status}${output ? `(${truncate(output, 200)})` : ""}`,
278
+ );
279
+ ok(name);
280
+ } catch (e) {
281
+ fail(name, e.message);
282
+ }
283
+ }
284
+
285
+ async function testListMessages(sessionId) {
286
+ const name = "查询历史消息";
287
+ header(`${name} · GET ${api(`/sessions/${sessionId}/messages`)}`);
288
+ const { status, data } = await request(
289
+ "GET",
290
+ api(`/sessions/${sessionId}/messages`),
291
+ );
292
+ log("响应", data);
293
+ try {
294
+ assert(status === 200, `期望 200,实际 ${status}`);
295
+ ok(name);
296
+ } catch (e) {
297
+ fail(name, e.message);
298
+ }
299
+ }
300
+
301
+ async function testStatelessInvoke() {
302
+ const name = "无会话同步调用";
303
+ header(`${name} · POST ${api("/invoke")}`);
304
+ const { status, data } = await request("POST", api("/invoke"), {
305
+ body: { content: TEST_MESSAGE },
306
+ timeout: 120000,
307
+ });
308
+ log("响应", truncate(data, 800));
309
+ log("Agent 回复", truncate(data?.output, 1200));
310
+ try {
311
+ assert(status === 200, `期望 200,实际 ${status}`);
312
+ assert(
313
+ data?.status === "success",
314
+ `期望 status=success,实际 ${data?.status}${data?.output ? `(${truncate(data.output, 200)})` : ""}`,
315
+ );
316
+ ok(name);
317
+ } catch (e) {
318
+ fail(name, e.message);
319
+ }
320
+ }
321
+
322
+ async function testStream(sessionId) {
323
+ const name = "流式对话";
324
+ header(`${name} · POST ${api(`/sessions/${sessionId}/stream`)}`);
325
+ const { status, events, raw } = await consumeSse(
326
+ api(`/sessions/${sessionId}/stream`),
327
+ {
328
+ body: { content: "继续,用一句话补充说明" },
329
+ },
330
+ );
331
+ try {
332
+ assert(status === 200, `期望 200,实际 ${status}`);
333
+ assert(events.length > 0, "期望至少收到 1 个 SSE 事件");
334
+ log(
335
+ `共收到 ${events.length} 个事件,类型分布:`,
336
+ countBy(events.map((e) => e.event)),
337
+ );
338
+ const chunks = events
339
+ .filter((e) => e.event === "response.chunk")
340
+ .map((e) => e.data?.delta ?? e.data?.text ?? e.data?.content);
341
+ log("流式文本片段(前 20 个)", chunks.slice(0, 20));
342
+ const text = chunks.filter(Boolean).join("");
343
+ log("流式回复全文", truncate(text, 1200));
344
+ const errorEvent = events.find(
345
+ (e) => e.event === "error" || e.event === "task.error",
346
+ );
347
+ assert(!errorEvent, `流中收到错误事件:${truncate(errorEvent?.data, 300)}`);
348
+ ok(name);
349
+ } catch (e) {
350
+ if (raw) log("原始响应", truncate(raw, 800));
351
+ fail(name, e.message);
352
+ }
353
+ }
354
+
355
+ async function testArchive(sessionId) {
356
+ const name = "归档会话";
357
+ header(`${name} · POST ${api(`/sessions/${sessionId}/archive`)}`);
358
+ const { status, data } = await request(
359
+ "POST",
360
+ api(`/sessions/${sessionId}/archive`),
361
+ );
362
+ log("响应", data);
363
+ try {
364
+ assert(status === 200, `期望 200,实际 ${status}`);
365
+ ok(name);
366
+ } catch (e) {
367
+ fail(name, e.message);
368
+ }
369
+ }
370
+
371
+ async function testRestore(sessionId) {
372
+ const name = "恢复会话(预期 501)";
373
+ header(`${name} · POST ${api(`/sessions/${sessionId}/restore`)}`);
374
+ const { status, data } = await request(
375
+ "POST",
376
+ api(`/sessions/${sessionId}/restore`),
377
+ );
378
+ log("响应", data);
379
+ try {
380
+ assert(status === 501, `期望 501 not_supported,实际 ${status}`);
381
+ ok(name);
382
+ } catch (e) {
383
+ fail(name, e.message);
384
+ }
385
+ }
386
+
387
+ function countBy(items) {
388
+ return items.reduce(
389
+ (acc, item) => ((acc[item] = (acc[item] ?? 0) + 1), acc),
390
+ {},
391
+ );
392
+ }
393
+
394
+ // ---------- 汇总 ----------
395
+
396
+ function summary() {
397
+ header("测试汇总");
398
+ const total = passed + failed;
399
+ console.log(` 总计 ${total} 项 · 通过 ${passed} · 失败 ${failed}`);
400
+ if (failures.length) {
401
+ console.log("\n 失败明细:");
402
+ for (const f of failures) {
403
+ console.log(
404
+ ` ✗ ${f.msg}${f.detail ? " — " + truncate(f.detail, 300) : ""}`,
405
+ );
406
+ }
407
+ }
408
+ console.log("\n" + "─".repeat(70));
409
+ process.exitCode = failed ? 1 : 0;
410
+ }
411
+
412
+ // ---------- 主流程 ----------
413
+
414
+ async function main() {
415
+ header(`Agent API 接口测试`);
416
+ console.log(` 服务地址:${BASE_URL}`);
417
+ console.log(` Agent code:${AGENT_CODE}`);
418
+ console.log(` 测试消息:${TEST_MESSAGE}`);
419
+
420
+ const sessionId = await testCreateSession();
421
+ if (!sessionId) {
422
+ summary();
423
+ return;
424
+ }
425
+
426
+ await testHealth();
427
+ await testCapability();
428
+ await testListSessions();
429
+ await testGetSession(sessionId);
430
+ await testSendMessage(sessionId);
431
+ await testListMessages(sessionId);
432
+ await testStatelessInvoke();
433
+ await testStream(sessionId);
434
+ await testArchive(sessionId);
435
+ await testRestore(sessionId);
436
+
437
+ summary();
438
+ }
439
+
440
+ main().catch((error) => {
441
+ console.error("测试脚本执行异常:", error);
442
+ process.exitCode = 1;
443
+ });
@@ -8,10 +8,8 @@ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
8
8
  // --dev 使用项目根的 .eap/runtime;生产构建使用 dist/.eap/runtime。
9
9
  const isDev = process.argv.includes('--dev');
10
10
 
11
- // dev 使用项目根 .env.local;构建使用项目根 .env.production,均回退 .env。
12
- config({
13
- path: [resolve(root, isDev ? '.env.local' : '.env.production'), resolve(root, '.env')],
14
- });
11
+ // 统一读取项目根 .env。
12
+ config({ path: resolve(root, '.env') });
15
13
 
16
14
  // 生产输出目录必须位于 dist 下,便于与 dist/index.js 一起发布。
17
15
  const runtimeBase = isDev ? root : resolve(root, 'dist');
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  createAgent,
3
+ resolveProjectRuntimeEnvironment,
3
4
  type Agent,
4
5
  type AgentCredentialProvider,
5
6
  type AgentResourceManager,
@@ -54,11 +55,22 @@ export async function createEmbeddedAgent(options: EmbeddedAgentOptions = {}): P
54
55
  };
55
56
  const deploymentRoot = resolve(runtimeRoot, '..', '..');
56
57
 
58
+ // 把 eap.config.json 里的 runtime.llm.models 映射成运行时识别的本地模型连接
59
+ // (EAP_LLM_MODE=local + EAP_LLM_CONNECTIONS)。漏掉这一步时,运行时会因为拿不到
60
+ // 本地网关而退回 EchoLLMProvider,表现为 [echo:model] 回显用户输入而非真实对话。
61
+ const projectRoot = resolve(entryDirectory, '..');
62
+ const runtimeEnvironment = resolveProjectRuntimeEnvironment({
63
+ root: projectRoot,
64
+ preinstallRoot: runtimeRoot,
65
+ }).environment;
66
+
57
67
  return createAgent({
58
68
  runtimeRoot,
59
69
  deploymentContext: isDev ? 'dev' : 'server',
60
70
  embeddedConfig,
61
71
  environment: {
72
+ ...runtimeEnvironment,
73
+ // 模板以物化 Runtime 目录为基准,覆盖 SDK 相对项目根算出的路径。
62
74
  EAP_DATA_DIR: resolve(runtimeRoot, '..'),
63
75
  EAP_CHECKPOINT_DIR: resolve(deploymentRoot, loadedRuntime.config.runtime.storage.checkpointDir),
64
76
  },
@@ -15,15 +15,8 @@ export type { ResourceApplyAndReloadResult } from './http/services/resource-serv
15
15
  // 入口文件的位置决定 Runtime 的相对路径,不依赖启动命令所在的当前目录。
16
16
  const entryDirectory = dirname(fileURLToPath(import.meta.url));
17
17
  const projectRoot = resolve(entryDirectory, '..');
18
- const isDev = process.argv.includes('--dev');
19
-
20
- // 开发态读取 .env.local,生产态读取 .env.production;两者都以 .env 作为最后的回退。
21
- config({
22
- path: [
23
- resolve(projectRoot, isDev ? '.env.local' : '.env.production'),
24
- resolve(projectRoot, '.env'),
25
- ],
26
- });
18
+ // 统一读取项目根 .env。
19
+ config({ path: resolve(projectRoot, '.env') });
27
20
 
28
21
  // 默认导出实例用于模板开发演示(npm run dev);生产宿主应调用
29
22
  // createEmbeddedAgent({ credentialProvider }),显式注入凭证。