@lark-apaas/nestjs-capability 0.0.1-alpha.1 → 0.0.1-alpha.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.
- package/README.md +107 -5
- package/dist/index.cjs +259 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -7
- package/dist/index.d.ts +90 -7
- package/dist/index.js +261 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ npm install @lark-apaas/nestjs-capability
|
|
|
15
15
|
- 从 `server/capabilities/` 目录加载能力配置
|
|
16
16
|
- 加载并实例化关联的插件
|
|
17
17
|
- 多种调用方式(Node 调用、Debug 调用、前端调用)
|
|
18
|
+
- 流式调用支持(SSE)
|
|
18
19
|
- 模板参数解析
|
|
19
20
|
|
|
20
21
|
## 快速开始
|
|
@@ -59,6 +60,36 @@ export class TaskService {
|
|
|
59
60
|
}
|
|
60
61
|
```
|
|
61
62
|
|
|
63
|
+
### 流式调用
|
|
64
|
+
|
|
65
|
+
用于 LLM 对话等流式输出场景:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
@Injectable()
|
|
69
|
+
export class ChatService {
|
|
70
|
+
constructor(private readonly capabilityService: CapabilityService) {}
|
|
71
|
+
|
|
72
|
+
async *chat(message: string): AsyncIterable<{ content: string }> {
|
|
73
|
+
const stream = this.capabilityService
|
|
74
|
+
.load('ai_chat')
|
|
75
|
+
.callStream('chat', { message });
|
|
76
|
+
|
|
77
|
+
for await (const chunk of stream) {
|
|
78
|
+
yield chunk as { content: string };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
普通调用会自动聚合流式结果:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// 即使是流式 action,call() 也会返回聚合后的完整结果
|
|
88
|
+
const result = await this.capabilityService
|
|
89
|
+
.load('ai_chat')
|
|
90
|
+
.call('chat', { message: 'hello' });
|
|
91
|
+
```
|
|
92
|
+
|
|
62
93
|
### 上下文覆盖
|
|
63
94
|
|
|
64
95
|
```typescript
|
|
@@ -128,16 +159,42 @@ POST /api/capability/:capability_id
|
|
|
128
159
|
}
|
|
129
160
|
```
|
|
130
161
|
|
|
131
|
-
###
|
|
162
|
+
### 前端流式调用
|
|
132
163
|
|
|
133
164
|
```
|
|
134
|
-
POST /
|
|
165
|
+
POST /api/capability/:capability_id/stream
|
|
135
166
|
|
|
136
167
|
请求体:
|
|
137
168
|
{
|
|
138
|
-
"action": "
|
|
169
|
+
"action": "chat",
|
|
139
170
|
"params": {
|
|
171
|
+
"message": "hello"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
响应(SSE 格式):
|
|
176
|
+
data: {"content":"Hello"}
|
|
177
|
+
data: {"content":" World"}
|
|
178
|
+
data: [DONE]
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Debug 调用(仅开发环境)
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
POST /__innerapi__/capability/debug/:capability_id
|
|
185
|
+
|
|
186
|
+
请求体(所有字段可选):
|
|
187
|
+
{
|
|
188
|
+
"action": "run", // 可选,默认使用插件第一个 action
|
|
189
|
+
"params": { // 可选,用户输入参数
|
|
140
190
|
"group_name": "测试群"
|
|
191
|
+
},
|
|
192
|
+
"capability": { // 可选,完整的 capability 配置(优先使用)
|
|
193
|
+
"id": "test",
|
|
194
|
+
"pluginID": "@test/plugin",
|
|
195
|
+
"pluginVersion": "1.0.0",
|
|
196
|
+
"name": "测试",
|
|
197
|
+
"formValue": {}
|
|
141
198
|
}
|
|
142
199
|
}
|
|
143
200
|
|
|
@@ -150,11 +207,30 @@ POST /__innerapi__/capability/debug/:capability_id
|
|
|
150
207
|
"capabilityConfig": { ... },
|
|
151
208
|
"resolvedParams": { ... },
|
|
152
209
|
"duration": 123,
|
|
153
|
-
"pluginID": "@xxx/plugin"
|
|
210
|
+
"pluginID": "@xxx/plugin",
|
|
211
|
+
"action": "run"
|
|
154
212
|
}
|
|
155
213
|
}
|
|
156
214
|
```
|
|
157
215
|
|
|
216
|
+
### Debug 流式调用(仅开发环境)
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
POST /__innerapi__/capability/debug/:capability_id/stream
|
|
220
|
+
|
|
221
|
+
请求体(所有字段可选):
|
|
222
|
+
{
|
|
223
|
+
"action": "chat",
|
|
224
|
+
"params": { "message": "hello" },
|
|
225
|
+
"capability": { ... }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
响应(SSE 格式):
|
|
229
|
+
data: {"content":"Hello"}
|
|
230
|
+
data: {"content":" World"}
|
|
231
|
+
data: [DONE]
|
|
232
|
+
```
|
|
233
|
+
|
|
158
234
|
### 列出所有能力(仅开发环境)
|
|
159
235
|
|
|
160
236
|
```
|
|
@@ -192,16 +268,30 @@ interface CapabilityService {
|
|
|
192
268
|
// 加载能力并返回执行器
|
|
193
269
|
load(capabilityId: string): CapabilityExecutor;
|
|
194
270
|
|
|
271
|
+
// 使用传入的配置加载能力执行器(用于 debug 场景)
|
|
272
|
+
loadWithConfig(config: CapabilityConfig): CapabilityExecutor;
|
|
273
|
+
|
|
195
274
|
// 设置自定义能力目录
|
|
196
275
|
setCapabilitiesDir(dir: string): void;
|
|
197
276
|
}
|
|
198
277
|
|
|
199
278
|
interface CapabilityExecutor {
|
|
279
|
+
// 调用能力(流式 action 会自动聚合结果)
|
|
200
280
|
call(
|
|
201
281
|
actionName: string,
|
|
202
282
|
input: unknown,
|
|
203
283
|
context?: Partial<PluginActionContext>
|
|
204
284
|
): Promise<unknown>;
|
|
285
|
+
|
|
286
|
+
// 流式调用能力(返回 AsyncIterable)
|
|
287
|
+
callStream(
|
|
288
|
+
actionName: string,
|
|
289
|
+
input: unknown,
|
|
290
|
+
context?: Partial<PluginActionContext>
|
|
291
|
+
): AsyncIterable<unknown>;
|
|
292
|
+
|
|
293
|
+
// 检查 action 是否为流式
|
|
294
|
+
isStream(actionName: string): Promise<boolean>;
|
|
205
295
|
}
|
|
206
296
|
```
|
|
207
297
|
|
|
@@ -257,10 +347,22 @@ interface CapabilityConfig {
|
|
|
257
347
|
|
|
258
348
|
```typescript
|
|
259
349
|
interface PluginInstance {
|
|
350
|
+
// 执行 action(必需)
|
|
260
351
|
run(actionName: string, context: PluginActionContext, input: unknown): Promise<unknown>;
|
|
352
|
+
|
|
353
|
+
// 流式执行 action(可选)
|
|
354
|
+
runStream?(actionName: string, context: PluginActionContext, input: unknown): AsyncIterable<unknown>;
|
|
355
|
+
|
|
356
|
+
// 检查是否为流式 action(可选)
|
|
357
|
+
isStreamAction?(actionName: string): boolean;
|
|
358
|
+
|
|
359
|
+
// 聚合流式结果(可选,默认返回 chunks 数组)
|
|
360
|
+
aggregate?(actionName: string, chunks: unknown[]): unknown;
|
|
361
|
+
|
|
362
|
+
// Action 相关
|
|
261
363
|
hasAction(actionName: string): boolean;
|
|
262
|
-
getActionSchema(actionName: string): ActionSchema | null;
|
|
263
364
|
listActions(): string[];
|
|
365
|
+
getActionSchema(actionName: string): ActionSchema | null;
|
|
264
366
|
getInputSchema(actionName: string, config?: unknown): ZodSchema | undefined;
|
|
265
367
|
getOutputSchema(actionName: string, input: unknown, config?: unknown): ZodSchema | undefined;
|
|
266
368
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -57,7 +57,10 @@ var TemplateEngineService = class {
|
|
|
57
57
|
static {
|
|
58
58
|
__name(this, "TemplateEngineService");
|
|
59
59
|
}
|
|
60
|
-
|
|
60
|
+
// 匹配 {{input.xxx}} 或 {{input.xxx.yyy}} 表达式
|
|
61
|
+
EXPR_REGEX = /\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}/g;
|
|
62
|
+
// 匹配整串单个表达式
|
|
63
|
+
WHOLE_STRING_EXPR_REGEX = /^\{\{input\.([a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)\}\}$/;
|
|
61
64
|
resolve(template, input) {
|
|
62
65
|
if (typeof template === "string") {
|
|
63
66
|
return this.resolveString(template, input);
|
|
@@ -71,12 +74,25 @@ var TemplateEngineService = class {
|
|
|
71
74
|
return template;
|
|
72
75
|
}
|
|
73
76
|
resolveString(template, input) {
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
77
|
+
const wholeMatch = template.match(this.WHOLE_STRING_EXPR_REGEX);
|
|
78
|
+
if (wholeMatch) {
|
|
79
|
+
const path2 = wholeMatch[1];
|
|
80
|
+
const value = this.getValueByPath(input, path2);
|
|
81
|
+
return value !== void 0 ? value : template;
|
|
82
|
+
}
|
|
83
|
+
this.EXPR_REGEX.lastIndex = 0;
|
|
84
|
+
if (!this.EXPR_REGEX.test(template)) {
|
|
76
85
|
return template;
|
|
77
86
|
}
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
this.EXPR_REGEX.lastIndex = 0;
|
|
88
|
+
const result = template.replace(this.EXPR_REGEX, (match, path2) => {
|
|
89
|
+
const value = this.getValueByPath(input, path2);
|
|
90
|
+
if (value === void 0) {
|
|
91
|
+
return match;
|
|
92
|
+
}
|
|
93
|
+
return String(value);
|
|
94
|
+
});
|
|
95
|
+
return result;
|
|
80
96
|
}
|
|
81
97
|
resolveObject(template, input) {
|
|
82
98
|
const result = {};
|
|
@@ -278,13 +294,44 @@ var CapabilityService = class _CapabilityService {
|
|
|
278
294
|
if (!config) {
|
|
279
295
|
throw new CapabilityNotFoundError(capabilityId);
|
|
280
296
|
}
|
|
297
|
+
return this.createExecutor(config);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* 使用传入的配置加载能力执行器
|
|
301
|
+
* 用于 debug 场景,支持用户传入自定义配置
|
|
302
|
+
*/
|
|
303
|
+
loadWithConfig(config) {
|
|
304
|
+
return this.createExecutor(config);
|
|
305
|
+
}
|
|
306
|
+
createExecutor(config) {
|
|
281
307
|
return {
|
|
282
308
|
call: /* @__PURE__ */ __name(async (actionName, input, contextOverride) => {
|
|
283
|
-
return this.
|
|
284
|
-
}, "call")
|
|
309
|
+
return this.executeCall(config, actionName, input, contextOverride);
|
|
310
|
+
}, "call"),
|
|
311
|
+
callStream: /* @__PURE__ */ __name((actionName, input, contextOverride) => {
|
|
312
|
+
return this.executeCallStream(config, actionName, input, contextOverride);
|
|
313
|
+
}, "callStream"),
|
|
314
|
+
isStream: /* @__PURE__ */ __name(async (actionName) => {
|
|
315
|
+
return this.checkIsStream(config, actionName);
|
|
316
|
+
}, "isStream")
|
|
285
317
|
};
|
|
286
318
|
}
|
|
287
|
-
|
|
319
|
+
/**
|
|
320
|
+
* 检查 action 是否为流式
|
|
321
|
+
*/
|
|
322
|
+
async checkIsStream(config, actionName) {
|
|
323
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);
|
|
324
|
+
if (!pluginInstance.hasAction(actionName)) {
|
|
325
|
+
throw new ActionNotFoundError(config.pluginID, actionName);
|
|
326
|
+
}
|
|
327
|
+
return pluginInstance.isStreamAction?.(actionName) ?? false;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* 执行 capability(始终返回 Promise)
|
|
331
|
+
* - unary action: 直接返回结果
|
|
332
|
+
* - stream action: 内部聚合所有 chunk 后返回
|
|
333
|
+
*/
|
|
334
|
+
async executeCall(config, actionName, input, contextOverride) {
|
|
288
335
|
const startTime = Date.now();
|
|
289
336
|
try {
|
|
290
337
|
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);
|
|
@@ -293,13 +340,24 @@ var CapabilityService = class _CapabilityService {
|
|
|
293
340
|
}
|
|
294
341
|
const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
|
|
295
342
|
const context = this.buildActionContext(contextOverride);
|
|
343
|
+
const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
|
|
296
344
|
this.logger.log({
|
|
297
345
|
message: "Executing capability",
|
|
298
346
|
capabilityId: config.id,
|
|
299
347
|
action: actionName,
|
|
300
|
-
pluginID: config.pluginID
|
|
348
|
+
pluginID: config.pluginID,
|
|
349
|
+
isStream
|
|
301
350
|
});
|
|
302
|
-
|
|
351
|
+
let result;
|
|
352
|
+
if (isStream && pluginInstance.runStream) {
|
|
353
|
+
const chunks = [];
|
|
354
|
+
for await (const chunk of pluginInstance.runStream(actionName, context, resolvedParams)) {
|
|
355
|
+
chunks.push(chunk);
|
|
356
|
+
}
|
|
357
|
+
result = pluginInstance.aggregate ? pluginInstance.aggregate(actionName, chunks) : chunks;
|
|
358
|
+
} else {
|
|
359
|
+
result = await pluginInstance.run(actionName, context, resolvedParams);
|
|
360
|
+
}
|
|
303
361
|
this.logger.log({
|
|
304
362
|
message: "Capability executed successfully",
|
|
305
363
|
capabilityId: config.id,
|
|
@@ -318,6 +376,51 @@ var CapabilityService = class _CapabilityService {
|
|
|
318
376
|
throw error;
|
|
319
377
|
}
|
|
320
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* 流式执行 capability
|
|
381
|
+
* - stream action: 返回原始 AsyncIterable
|
|
382
|
+
* - unary action: 包装为单次 yield
|
|
383
|
+
*/
|
|
384
|
+
async *executeCallStream(config, actionName, input, contextOverride) {
|
|
385
|
+
const startTime = Date.now();
|
|
386
|
+
try {
|
|
387
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(config.pluginID);
|
|
388
|
+
if (!pluginInstance.hasAction(actionName)) {
|
|
389
|
+
throw new ActionNotFoundError(config.pluginID, actionName);
|
|
390
|
+
}
|
|
391
|
+
const resolvedParams = this.templateEngineService.resolve(config.formValue, input);
|
|
392
|
+
const context = this.buildActionContext(contextOverride);
|
|
393
|
+
const isStream = pluginInstance.isStreamAction?.(actionName) ?? false;
|
|
394
|
+
this.logger.log({
|
|
395
|
+
message: "Executing capability (stream)",
|
|
396
|
+
capabilityId: config.id,
|
|
397
|
+
action: actionName,
|
|
398
|
+
pluginID: config.pluginID,
|
|
399
|
+
isStream
|
|
400
|
+
});
|
|
401
|
+
if (isStream && pluginInstance.runStream) {
|
|
402
|
+
yield* pluginInstance.runStream(actionName, context, resolvedParams);
|
|
403
|
+
} else {
|
|
404
|
+
const result = await pluginInstance.run(actionName, context, resolvedParams);
|
|
405
|
+
yield result;
|
|
406
|
+
}
|
|
407
|
+
this.logger.log({
|
|
408
|
+
message: "Capability stream completed",
|
|
409
|
+
capabilityId: config.id,
|
|
410
|
+
action: actionName,
|
|
411
|
+
duration: Date.now() - startTime
|
|
412
|
+
});
|
|
413
|
+
} catch (error) {
|
|
414
|
+
this.logger.error({
|
|
415
|
+
message: "Capability stream execution failed",
|
|
416
|
+
capabilityId: config.id,
|
|
417
|
+
action: actionName,
|
|
418
|
+
error: error instanceof Error ? error.message : String(error),
|
|
419
|
+
duration: Date.now() - startTime
|
|
420
|
+
});
|
|
421
|
+
throw error;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
321
424
|
buildActionContext(override) {
|
|
322
425
|
return {
|
|
323
426
|
logger: this.logger,
|
|
@@ -369,9 +472,11 @@ var DebugController = class {
|
|
|
369
472
|
__name(this, "DebugController");
|
|
370
473
|
}
|
|
371
474
|
capabilityService;
|
|
475
|
+
pluginLoaderService;
|
|
372
476
|
templateEngineService;
|
|
373
|
-
constructor(capabilityService, templateEngineService) {
|
|
477
|
+
constructor(capabilityService, pluginLoaderService, templateEngineService) {
|
|
374
478
|
this.capabilityService = capabilityService;
|
|
479
|
+
this.pluginLoaderService = pluginLoaderService;
|
|
375
480
|
this.templateEngineService = templateEngineService;
|
|
376
481
|
}
|
|
377
482
|
list() {
|
|
@@ -387,8 +492,14 @@ var DebugController = class {
|
|
|
387
492
|
}))
|
|
388
493
|
};
|
|
389
494
|
}
|
|
390
|
-
|
|
391
|
-
|
|
495
|
+
/**
|
|
496
|
+
* 获取 capability 配置
|
|
497
|
+
* 优先使用 body.capability,否则从服务获取
|
|
498
|
+
*/
|
|
499
|
+
getCapabilityConfig(capabilityId, bodyCapability) {
|
|
500
|
+
if (bodyCapability) {
|
|
501
|
+
return bodyCapability;
|
|
502
|
+
}
|
|
392
503
|
const config = this.capabilityService.getCapability(capabilityId);
|
|
393
504
|
if (!config) {
|
|
394
505
|
throw new import_common4.HttpException({
|
|
@@ -397,9 +508,35 @@ var DebugController = class {
|
|
|
397
508
|
error: "CAPABILITY_NOT_FOUND"
|
|
398
509
|
}, import_common4.HttpStatus.NOT_FOUND);
|
|
399
510
|
}
|
|
400
|
-
|
|
511
|
+
return config;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* 获取 action 名称
|
|
515
|
+
* 优先使用传入的 action,否则使用插件第一个 action
|
|
516
|
+
*/
|
|
517
|
+
async getActionName(pluginID, bodyAction) {
|
|
518
|
+
if (bodyAction) {
|
|
519
|
+
return bodyAction;
|
|
520
|
+
}
|
|
521
|
+
const pluginInstance = await this.pluginLoaderService.loadPlugin(pluginID);
|
|
522
|
+
const actions = pluginInstance.listActions();
|
|
523
|
+
if (actions.length === 0) {
|
|
524
|
+
throw new import_common4.HttpException({
|
|
525
|
+
code: 1,
|
|
526
|
+
message: `Plugin ${pluginID} has no actions`,
|
|
527
|
+
error: "NO_ACTIONS"
|
|
528
|
+
}, import_common4.HttpStatus.BAD_REQUEST);
|
|
529
|
+
}
|
|
530
|
+
return actions[0];
|
|
531
|
+
}
|
|
532
|
+
async debug(capabilityId, body) {
|
|
533
|
+
const startTime = Date.now();
|
|
534
|
+
const params = body.params ?? {};
|
|
535
|
+
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
536
|
+
const action = await this.getActionName(config.pluginID, body.action);
|
|
537
|
+
const resolvedParams = this.templateEngineService.resolve(config.formValue, params);
|
|
401
538
|
try {
|
|
402
|
-
const result = await this.capabilityService.
|
|
539
|
+
const result = await this.capabilityService.loadWithConfig(config).call(action, params);
|
|
403
540
|
return {
|
|
404
541
|
code: 0,
|
|
405
542
|
message: "success",
|
|
@@ -408,7 +545,8 @@ var DebugController = class {
|
|
|
408
545
|
capabilityConfig: config,
|
|
409
546
|
resolvedParams,
|
|
410
547
|
duration: Date.now() - startTime,
|
|
411
|
-
pluginID: config.pluginID
|
|
548
|
+
pluginID: config.pluginID,
|
|
549
|
+
action
|
|
412
550
|
}
|
|
413
551
|
};
|
|
414
552
|
} catch (error) {
|
|
@@ -430,7 +568,8 @@ var DebugController = class {
|
|
|
430
568
|
error: "PLUGIN_NOT_FOUND",
|
|
431
569
|
debug: {
|
|
432
570
|
duration,
|
|
433
|
-
pluginID: config.pluginID
|
|
571
|
+
pluginID: config.pluginID,
|
|
572
|
+
action
|
|
434
573
|
}
|
|
435
574
|
}, import_common4.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
436
575
|
}
|
|
@@ -441,7 +580,8 @@ var DebugController = class {
|
|
|
441
580
|
error: "ACTION_NOT_FOUND",
|
|
442
581
|
debug: {
|
|
443
582
|
duration,
|
|
444
|
-
pluginID: config.pluginID
|
|
583
|
+
pluginID: config.pluginID,
|
|
584
|
+
action
|
|
445
585
|
}
|
|
446
586
|
}, import_common4.HttpStatus.BAD_REQUEST);
|
|
447
587
|
}
|
|
@@ -452,11 +592,51 @@ var DebugController = class {
|
|
|
452
592
|
debug: {
|
|
453
593
|
duration,
|
|
454
594
|
pluginID: config.pluginID,
|
|
595
|
+
action,
|
|
455
596
|
resolvedParams
|
|
456
597
|
}
|
|
457
598
|
}, import_common4.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
458
599
|
}
|
|
459
600
|
}
|
|
601
|
+
async debugStream(capabilityId, body, res) {
|
|
602
|
+
const params = body.params ?? {};
|
|
603
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
604
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
605
|
+
res.setHeader("Connection", "keep-alive");
|
|
606
|
+
try {
|
|
607
|
+
const config = this.getCapabilityConfig(capabilityId, body.capability);
|
|
608
|
+
const action = await this.getActionName(config.pluginID, body.action);
|
|
609
|
+
const capability = this.capabilityService.loadWithConfig(config);
|
|
610
|
+
const stream = capability.callStream(action, params);
|
|
611
|
+
for await (const chunk of stream) {
|
|
612
|
+
res.write(`data: ${JSON.stringify(chunk)}
|
|
613
|
+
|
|
614
|
+
`);
|
|
615
|
+
}
|
|
616
|
+
res.write("data: [DONE]\n\n");
|
|
617
|
+
} catch (error) {
|
|
618
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
619
|
+
let errorCode = "EXECUTION_ERROR";
|
|
620
|
+
if (error instanceof CapabilityNotFoundError) {
|
|
621
|
+
errorCode = "CAPABILITY_NOT_FOUND";
|
|
622
|
+
} else if (error instanceof PluginNotFoundError) {
|
|
623
|
+
errorCode = "PLUGIN_NOT_FOUND";
|
|
624
|
+
} else if (error instanceof ActionNotFoundError) {
|
|
625
|
+
errorCode = "ACTION_NOT_FOUND";
|
|
626
|
+
} else if (error instanceof import_common4.HttpException) {
|
|
627
|
+
const response = error.getResponse();
|
|
628
|
+
errorCode = response.error ?? "EXECUTION_ERROR";
|
|
629
|
+
}
|
|
630
|
+
res.write(`data: ${JSON.stringify({
|
|
631
|
+
error: message,
|
|
632
|
+
code: errorCode
|
|
633
|
+
})}
|
|
634
|
+
|
|
635
|
+
`);
|
|
636
|
+
} finally {
|
|
637
|
+
res.end();
|
|
638
|
+
}
|
|
639
|
+
}
|
|
460
640
|
};
|
|
461
641
|
_ts_decorate4([
|
|
462
642
|
(0, import_common4.Get)("list"),
|
|
@@ -471,15 +651,29 @@ _ts_decorate4([
|
|
|
471
651
|
_ts_metadata2("design:type", Function),
|
|
472
652
|
_ts_metadata2("design:paramtypes", [
|
|
473
653
|
String,
|
|
474
|
-
typeof
|
|
654
|
+
typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody
|
|
475
655
|
]),
|
|
476
656
|
_ts_metadata2("design:returntype", Promise)
|
|
477
657
|
], DebugController.prototype, "debug", null);
|
|
658
|
+
_ts_decorate4([
|
|
659
|
+
(0, import_common4.Post)("debug/:capability_id/stream"),
|
|
660
|
+
_ts_param2(0, (0, import_common4.Param)("capability_id")),
|
|
661
|
+
_ts_param2(1, (0, import_common4.Body)()),
|
|
662
|
+
_ts_param2(2, (0, import_common4.Res)()),
|
|
663
|
+
_ts_metadata2("design:type", Function),
|
|
664
|
+
_ts_metadata2("design:paramtypes", [
|
|
665
|
+
String,
|
|
666
|
+
typeof DebugRequestBody === "undefined" ? Object : DebugRequestBody,
|
|
667
|
+
typeof Response === "undefined" ? Object : Response
|
|
668
|
+
]),
|
|
669
|
+
_ts_metadata2("design:returntype", Promise)
|
|
670
|
+
], DebugController.prototype, "debugStream", null);
|
|
478
671
|
DebugController = _ts_decorate4([
|
|
479
672
|
(0, import_common4.Controller)("__innerapi__/capability"),
|
|
480
673
|
_ts_metadata2("design:type", Function),
|
|
481
674
|
_ts_metadata2("design:paramtypes", [
|
|
482
675
|
typeof CapabilityService === "undefined" ? Object : CapabilityService,
|
|
676
|
+
typeof PluginLoaderService === "undefined" ? Object : PluginLoaderService,
|
|
483
677
|
typeof TemplateEngineService === "undefined" ? Object : TemplateEngineService
|
|
484
678
|
])
|
|
485
679
|
], DebugController);
|
|
@@ -562,6 +756,39 @@ var WebhookController = class {
|
|
|
562
756
|
}, import_common5.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
563
757
|
}
|
|
564
758
|
}
|
|
759
|
+
async executeStream(capabilityId, body, res) {
|
|
760
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
761
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
762
|
+
res.setHeader("Connection", "keep-alive");
|
|
763
|
+
try {
|
|
764
|
+
const capability = this.capabilityService.load(capabilityId);
|
|
765
|
+
const stream = capability.callStream(body.action, body.params);
|
|
766
|
+
for await (const chunk of stream) {
|
|
767
|
+
res.write(`data: ${JSON.stringify(chunk)}
|
|
768
|
+
|
|
769
|
+
`);
|
|
770
|
+
}
|
|
771
|
+
res.write("data: [DONE]\n\n");
|
|
772
|
+
} catch (error) {
|
|
773
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
774
|
+
let errorCode = "EXECUTION_ERROR";
|
|
775
|
+
if (error instanceof CapabilityNotFoundError) {
|
|
776
|
+
errorCode = "CAPABILITY_NOT_FOUND";
|
|
777
|
+
} else if (error instanceof PluginNotFoundError) {
|
|
778
|
+
errorCode = "PLUGIN_NOT_FOUND";
|
|
779
|
+
} else if (error instanceof ActionNotFoundError) {
|
|
780
|
+
errorCode = "ACTION_NOT_FOUND";
|
|
781
|
+
}
|
|
782
|
+
res.write(`data: ${JSON.stringify({
|
|
783
|
+
error: message,
|
|
784
|
+
code: errorCode
|
|
785
|
+
})}
|
|
786
|
+
|
|
787
|
+
`);
|
|
788
|
+
} finally {
|
|
789
|
+
res.end();
|
|
790
|
+
}
|
|
791
|
+
}
|
|
565
792
|
};
|
|
566
793
|
_ts_decorate5([
|
|
567
794
|
(0, import_common5.Get)("list"),
|
|
@@ -580,6 +807,19 @@ _ts_decorate5([
|
|
|
580
807
|
]),
|
|
581
808
|
_ts_metadata3("design:returntype", Promise)
|
|
582
809
|
], WebhookController.prototype, "execute", null);
|
|
810
|
+
_ts_decorate5([
|
|
811
|
+
(0, import_common5.Post)(":capability_id/stream"),
|
|
812
|
+
_ts_param3(0, (0, import_common5.Param)("capability_id")),
|
|
813
|
+
_ts_param3(1, (0, import_common5.Body)()),
|
|
814
|
+
_ts_param3(2, (0, import_common5.Res)()),
|
|
815
|
+
_ts_metadata3("design:type", Function),
|
|
816
|
+
_ts_metadata3("design:paramtypes", [
|
|
817
|
+
String,
|
|
818
|
+
typeof ExecuteRequestBody === "undefined" ? Object : ExecuteRequestBody,
|
|
819
|
+
typeof Response === "undefined" ? Object : Response
|
|
820
|
+
]),
|
|
821
|
+
_ts_metadata3("design:returntype", Promise)
|
|
822
|
+
], WebhookController.prototype, "executeStream", null);
|
|
583
823
|
WebhookController = _ts_decorate5([
|
|
584
824
|
(0, import_common5.Controller)("api/capability"),
|
|
585
825
|
_ts_metadata3("design:type", Function),
|