@aalis/plugin-tools 0.10.0 → 0.12.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/dist/background-tools.d.ts.map +1 -1
- package/dist/background-tools.js +22 -17
- package/dist/background-tools.js.map +1 -1
- package/dist/background.d.ts +36 -27
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +75 -42
- package/dist/background.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -23
- package/dist/index.js.map +1 -1
- package/dist/locales/en.d.ts +22 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/en.js +22 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/texts.d.ts +43 -0
- package/dist/texts.d.ts.map +1 -0
- package/dist/texts.js +26 -0
- package/dist/texts.js.map +1 -0
- package/dist/tools.d.ts +27 -7
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +106 -51
- package/dist/tools.js.map +1 -1
- package/package.json +17 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-tools.d.ts","sourceRoot":"","sources":["../src/background-tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"background-tools.d.ts","sourceRoot":"","sources":["../src/background-tools.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAkB,cAAc,EAAwC,MAAM,kBAAkB,CAAC;AAC7G,OAAO,EAAE,KAAK,eAAe,EAAiC,MAAM,iBAAiB,CAAC;AAEtF,KAAK,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;AAqC/C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,EAAE,CAsFlE"}
|
package/dist/background-tools.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// ════════════════════════════════════════════════════════════
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// 四个后台任务工具(执行器提供):列出、取输出、等待、停止本会话里的后台任务。按会话放行:本会话里的后台任务谁都能查,不论
|
|
3
|
+
// 是谁起的;别的会话里的回「不存在」。列出、取输出与等待不设 restricted 与 risk,也不另设等级闸:任务的输出与结果本来就在这个
|
|
4
|
+
// 会话里,与前台调用的结果一样谁在场谁看得到。停与子任务、编排、定时任务同一规则,2 级加确认(risk 'dangerous'),不另判是谁
|
|
5
|
+
// 起的:别人单独发起的没人能批即拒,有 owner 在的一轮出卡给她批,owner 一个人的回合在免确认白名单里不问。
|
|
6
|
+
// 结束通知开的那一轮仍按起它的人的身份运行。
|
|
5
7
|
// ════════════════════════════════════════════════════════════
|
|
6
8
|
import { DEFAULT_YIELD_SECONDS, viewOf } from './background.js';
|
|
7
9
|
const error = (message) => JSON.stringify({ error: message });
|
|
@@ -66,20 +68,23 @@ export function backgroundTaskTools(tasks) {
|
|
|
66
68
|
const settled = taskIds.flatMap(id => find(ctx, id) ?? []);
|
|
67
69
|
return withResults({ tasks: settled.map(task => ({ ...viewOf(task), ...resultOf(task) })) }, settled, ctx);
|
|
68
70
|
}),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
71
|
+
{
|
|
72
|
+
...tool('background_stop', '停掉一个后台任务,等它停下后如实回报(最多等 3 秒)。被停掉的任务不再通知你。', { taskId }, ['taskId'], async (args, ctx) => {
|
|
73
|
+
const task = find(ctx, args.taskId);
|
|
74
|
+
if (!task)
|
|
75
|
+
return missing(args.taskId);
|
|
76
|
+
if (task.status !== 'running')
|
|
77
|
+
return JSON.stringify({ ...viewOf(task), message: '任务已结束' });
|
|
78
|
+
const after = await tasks.stop(task.id);
|
|
79
|
+
if (!after)
|
|
80
|
+
return missing(args.taskId);
|
|
81
|
+
return JSON.stringify({
|
|
82
|
+
...viewOf(after),
|
|
83
|
+
message: after.status === 'running' ? '已发出停止,3 秒内还没停下;它停下后记为已停止,不会通知你' : '已停止',
|
|
84
|
+
});
|
|
85
|
+
}),
|
|
86
|
+
risk: 'dangerous',
|
|
87
|
+
},
|
|
83
88
|
];
|
|
84
89
|
}
|
|
85
90
|
//# sourceMappingURL=background-tools.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-tools.js","sourceRoot":"","sources":["../src/background-tools.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,6DAA6D;AAC7D,
|
|
1
|
+
{"version":3,"file":"background-tools.js","sourceRoot":"","sources":["../src/background-tools.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAC/D,yEAAyE;AACzE,yEAAyE;AACzE,6DAA6D;AAC7D,wBAAwB;AACxB,+DAA+D;AAG/D,OAAO,EAAwB,qBAAqB,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAItF,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AACtE,MAAM,OAAO,GAAG,CAAC,EAAW,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;AAEnE,kCAAkC;AAClC,SAAS,WAAW,CAClB,MAA+B,EAC/B,KAAuB,EACvB,GAAoB;IAEpB,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACvF,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,IAAoB,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAEhG,SAAS,IAAI,CACX,IAAY,EACZ,WAAmB,EACnB,UAAmC,EACnC,QAAkB,EAClB,OAAwB;IAExB,OAAO;QACL,UAAU,EAAE;YACV,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,IAAI;gBACJ,WAAW;gBACX,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,KAAK,EAAE;aAClF;SACF;QACD,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAsB;IACxD,MAAM,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;IACxC,MAAM,SAAS,GAAG,CAAC,GAAoB,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;IACrF,MAAM,IAAI,GAAG,CAAC,GAAoB,EAAE,EAAW,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAChG,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE,CAAC;IAE1E,OAAO;QACL,IAAI,CACF,iBAAiB,EACjB,4DAA4D;YAC1D,mBAAmB,EACrB,EAAE,EACF,EAAE,EACF,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAC5E;QAED,IAAI,CACF,mBAAmB,EACnB,gEAAgE;YAC9D,8CAA8C,EAChD,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,wBAAwB,EAAE,EAAE,EAC7E,CAAC,QAAQ,CAAC,EACV,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAClB,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;YACvB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAK,KAAgB,IAAI,CAAC,CAAC,EAAE,CAAC;gBAChF,OAAO,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,KAA2B,CAAC,CAAC;YAC1E,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClD,OAAO,WAAW,CAChB,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,EACzG,CAAC,IAAI,CAAC,EACN,GAAG,CACJ,CAAC;QACJ,CAAC,CACF;QAED,IAAI,CACF,iBAAiB,EACjB,oCAAoC,qBAAqB,OAAO,cAAc,eAAe;YAC3F,qDAAqD,EACvD;YACE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE;YAC9E,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,aAAa,qBAAqB,OAAO,cAAc,GAAG;aACxE;SACF,EACD,CAAC,SAAS,CAAC,EACX,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAClB,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,qBAAqB,EAAE,GAAG,IAAI,CAAC;YAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3F,IAAI,CAAC,CAAC,OAAO,WAAW,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC3F,OAAO,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC1C,CAAC;YACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,MAAM,KAAK,CAAC,IAAI,CAAC,OAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3D,OAAO,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QAC7G,CAAC,CACF;QAED;YACE,GAAG,IAAI,CACL,iBAAiB,EACjB,0CAA0C,EAC1C,EAAE,MAAM,EAAE,EACV,CAAC,QAAQ,CAAC,EACV,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;gBAClB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBACpC,IAAI,CAAC,IAAI;oBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;oBAAE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC5F,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACxC,IAAI,CAAC,KAAK;oBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxC,OAAO,IAAI,CAAC,SAAS,CAAC;oBACpB,GAAG,MAAM,CAAC,KAAK,CAAC;oBAChB,OAAO,EACL,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,KAAK;iBACxE,CAAC,CAAC;YACL,CAAC,CACF;YACD,IAAI,EAAE,WAAW;SAClB;KACF,CAAC;AACJ,CAAC"}
|
package/dist/background.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type
|
|
1
|
+
import type { UserIdentity, Verdict } from '@aalis/api-authority';
|
|
2
|
+
import { type PluginDirStorage } from '@aalis/api-storage';
|
|
3
|
+
import { type BackgroundTask, type BackgroundTaskOutput, type BackgroundTaskService, type ToolCallContext, type ToolCallRequest, type ToolDisplay, type ToolExecutionResult } from '@aalis/api-tools';
|
|
3
4
|
import type { Events, Logger } from '@aalis/core';
|
|
5
|
+
import type { FromTurn } from '@aalis/schema-message';
|
|
4
6
|
/** 让出时限的缺省(秒),工具可以声明自己的 */
|
|
5
7
|
export declare const DEFAULT_YIELD_SECONDS = 30;
|
|
6
8
|
interface BackgroundLimits {
|
|
@@ -11,13 +13,11 @@ interface BackgroundLimits {
|
|
|
11
13
|
}
|
|
12
14
|
/** 两项上限的缺省,插件配置的默认值取这里 */
|
|
13
15
|
export declare const DEFAULT_LIMITS: BackgroundLimits;
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/** 对话回合里的调用:有 turnId 与 callId,转到后台后有可以通知的对话 */
|
|
20
|
-
export declare function inTurn(ctx: ToolCallContext): ctx is ToolCallContext & {
|
|
16
|
+
/**
|
|
17
|
+
* 对话回合里的调用:在入站回合里(inbound 在)、有 turnId 与 callId,转到后台后有可以通知的对话。结束通知带着起它的那一轮,
|
|
18
|
+
* 只有入站回合里的调用给得出它
|
|
19
|
+
*/
|
|
20
|
+
export declare function inTurn<C extends ToolCallRequest>(ctx: C): ctx is C & {
|
|
21
21
|
turnId: string;
|
|
22
22
|
callId: string;
|
|
23
23
|
};
|
|
@@ -52,19 +52,18 @@ interface Call {
|
|
|
52
52
|
readonly plan: Plan;
|
|
53
53
|
readonly controller: AbortController;
|
|
54
54
|
readonly output: OutputTail;
|
|
55
|
+
/** 处理函数里在等的取用判定(approveFor):有就不转后台 */
|
|
56
|
+
readonly approving: Set<Promise<unknown>>;
|
|
55
57
|
record?: TaskRecord;
|
|
56
58
|
/** 被停止(stop):落定时记为 stopped,不通知 */
|
|
57
59
|
stopRequested?: boolean;
|
|
58
60
|
}
|
|
59
61
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
+
* 结束通知带着的起它的那一轮(结束通知开的那一轮与它同一类别、按它的参与者运行,平台同它)与回复时引用哪条消息:起它那次调用
|
|
63
|
+
* 上下文的快照,会话取任务的。只在本次运行里有,不落盘:读回的任务不通知
|
|
62
64
|
*/
|
|
63
65
|
interface NoticeTarget {
|
|
64
|
-
|
|
65
|
-
/** 起它的那次调用的授权身份:结束通知开的那一轮按它的身份运行 */
|
|
66
|
-
actor: Identity;
|
|
67
|
-
callerUserId?: string;
|
|
66
|
+
fromTurn: FromTurn;
|
|
68
67
|
replyTo?: string;
|
|
69
68
|
}
|
|
70
69
|
interface TaskRecord {
|
|
@@ -84,10 +83,12 @@ interface RunSpec {
|
|
|
84
83
|
tool: string;
|
|
85
84
|
/** 模型给的参数(含执行器取出的两项),记进任务的 call */
|
|
86
85
|
args: Record<string, unknown>;
|
|
87
|
-
ctx:
|
|
86
|
+
ctx: ToolCallRequest;
|
|
88
87
|
/** 结局按它取退出码 */
|
|
89
88
|
display?: ToolDisplay;
|
|
90
|
-
/**
|
|
89
|
+
/** 取用判定(ToolCallContext.approveFor),按交来的上下文判;asks 为假时只按参与者都过判、不出审批 */
|
|
90
|
+
approve(ctx: ToolCallRequest, check: (who: UserIdentity) => Verdict, asks: boolean): Promise<Verdict>;
|
|
91
|
+
/** 带上这次调用的中止信号、输出口与取用判定跑工具;不拒绝 */
|
|
91
92
|
invoke(ctx: ToolCallContext): Promise<ToolExecutionResult>;
|
|
92
93
|
}
|
|
93
94
|
interface BackgroundTasksDeps {
|
|
@@ -96,6 +97,10 @@ interface BackgroundTasksDeps {
|
|
|
96
97
|
events: Pick<Events, 'emit'>;
|
|
97
98
|
limits: BackgroundLimits;
|
|
98
99
|
}
|
|
100
|
+
/** 结果里的 error 原文(不是字符串的写成 JSON);结果不是 JSON 对象或没有 error 时没有 */
|
|
101
|
+
export declare function errorIn(content: string): string | undefined;
|
|
102
|
+
/** 命令类工具的退出码:按展示种类写明的键从结果里取,别的种类没有 */
|
|
103
|
+
export declare function exitCodeOf(display: ToolDisplay | undefined, content: string): number | undefined;
|
|
99
104
|
/**
|
|
100
105
|
* 后台任务登记与可转后台调用的运行。执行器(ToolRegistry)经它占位置、跑调用、撤回;四个后台任务工具经它查、取输出、
|
|
101
106
|
* 等待与停止;插件把会话删除、停机、停用与存储接到它上面
|
|
@@ -125,19 +130,20 @@ export declare class BackgroundTasks implements BackgroundTaskService {
|
|
|
125
130
|
stop(id: string): Promise<BackgroundTask | undefined>;
|
|
126
131
|
/** 等这些任务都落定,最多等 ms,中止信号到达即返回 */
|
|
127
132
|
wait(ids: string[], ms: number, signal?: AbortSignal): Promise<void>;
|
|
128
|
-
/**
|
|
129
|
-
outputFor(ctx:
|
|
133
|
+
/** 不可转后台的调用的输出口:对话回合里的转成 tool:output */
|
|
134
|
+
outputFor(ctx: ToolCallRequest): (text: string) => void;
|
|
130
135
|
/**
|
|
131
136
|
* 占一个位置。同一会话里对话回合中在跑的可转后台调用(前台与后台一起数,等审批的也算)满了时,回拒绝的结果(JSON),
|
|
132
137
|
* 列出这个会话在跑的后台任务,不执行、不过守卫。不在回合里的调用不会转后台,不占名额、不受上限挡
|
|
133
138
|
*/
|
|
134
|
-
admit(ctx:
|
|
139
|
+
admit(ctx: ToolCallRequest, owner: object, plan: Plan): Call | string;
|
|
135
140
|
/** 占了位置却没执行(守卫拒绝、回合已中止):放回去 */
|
|
136
141
|
release(call: Call): void;
|
|
137
142
|
/**
|
|
138
143
|
* 跑一次占到位置、过了守卫的可转后台调用。让出时限从这里算起,前台时回合中止一并中止它。到时没结束或要求立即转后台:
|
|
139
|
-
* 对话回合里的调用登记成后台任务、摘掉与回合的联动,先回给模型任务 id
|
|
140
|
-
*
|
|
144
|
+
* 对话回合里的调用登记成后台任务、摘掉与回合的联动,先回给模型任务 id 与已有输出的末尾;不在对话回合里的(没有可通知的对话)
|
|
145
|
+
* 中止并回报已有输出。处理函数里的取用判定在前台时可能等一道审批,等着时不让出,到了让出时限还在等的,等审批都结了重新计一个
|
|
146
|
+
* 让出时限;转到后台之后(要求立即转的从一开始)只按参与者都过判、不出审批:回合结束时没结的审批会被撤掉。审批随这次调用中止撤销
|
|
141
147
|
*/
|
|
142
148
|
run(call: Call, spec: RunSpec): Promise<ToolExecutionResult>;
|
|
143
149
|
/** 工具撤回登记(所属插件停用):这个登记在跑的调用一并中止,后台的落成 aborted */
|
|
@@ -147,15 +153,17 @@ export declare class BackgroundTasks implements BackgroundTaskService {
|
|
|
147
153
|
* 变了就写。文件不存在按没有记录起步;内容读不懂告警后同样起步,下次写盘时覆盖;读不出来(权限、存储不可用)告警,
|
|
148
154
|
* 本次运行只记在内存里,不覆盖它
|
|
149
155
|
*/
|
|
150
|
-
restore(storage: Pick<
|
|
156
|
+
restore(storage: Pick<PluginDirStorage, 'readFile' | 'writeFile' | 'uri'>): Promise<void>;
|
|
151
157
|
/** 会话删除:停掉它的调用与任务、删掉登记,不通知 */
|
|
152
158
|
deleteSession(sessionId: string): void;
|
|
153
159
|
/** 收到 app:stopping:此后结束的不通知 */
|
|
154
160
|
shutdown(): void;
|
|
155
161
|
/** 停用(收尾):在跑的调用一并中止,后台的落成 aborted,等写盘落定 */
|
|
156
162
|
close(): Promise<void>;
|
|
163
|
+
/** 处理函数里在等的一次取用判定:等着时这次调用不转后台 */
|
|
164
|
+
private approving;
|
|
157
165
|
/**
|
|
158
|
-
*
|
|
166
|
+
* 推给界面:对话回合里的调用转成 tool:output。sent 是这次调用此前写过的字数,推出的总量不超过 OUTPUT_LIMIT:
|
|
159
167
|
* 界面按条目累加输出,前台最多要等 maxWaitSeconds,持续大量输出的命令不能把它撑满
|
|
160
168
|
*/
|
|
161
169
|
private stream;
|
|
@@ -169,15 +177,16 @@ export declare class BackgroundTasks implements BackgroundTaskService {
|
|
|
169
177
|
*/
|
|
170
178
|
private finish;
|
|
171
179
|
private land;
|
|
180
|
+
/** 中止匹配的调用,后台的落成 aborted;原因随登记落盘,参数截短 */
|
|
172
181
|
private abortWhere;
|
|
173
182
|
private remove;
|
|
174
183
|
/** 每个会话留在跑的与最近 MAX_ENDED_PER_SESSION 条结束的 */
|
|
175
184
|
private prune;
|
|
176
185
|
private changed;
|
|
177
186
|
/**
|
|
178
|
-
* 结束通知只放宿主取得的事实:任务 id
|
|
179
|
-
*
|
|
180
|
-
*
|
|
187
|
+
* 结束通知只放宿主取得的事实:任务 id、工具名、结局与退出码、用时,正文写给模型,同样的事实另给界面,给人看的那句另写
|
|
188
|
+
* (不带给模型的用法提示)。参数由模型写出(可能受过注入),输出与结果受外部内容左右,都不进通知(通知以 system 呈现且
|
|
189
|
+
* 会归档);它们由模型用 background_output 取,以 tool 角色进上下文。只有正常结束(completed、failed)的通知
|
|
181
190
|
*/
|
|
182
191
|
private notify;
|
|
183
192
|
/** 并进读回的登记:读回之前起的任务照留,id 相同的以内存为准 */
|
package/dist/background.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../src/background.ts"],"names":[],"mappings":"AAMA,OAAO,EAAqB,KAAK,
|
|
1
|
+
{"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../src/background.ts"],"names":[],"mappings":"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"}
|
package/dist/background.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
// ════════════════════════════════════════════════════════════
|
|
6
6
|
import { isStorageNotFound } from '@aalis/api-storage';
|
|
7
7
|
import { BACKGROUND_TASK_NOTICE, integerIn, toolFailed, } from '@aalis/api-tools';
|
|
8
|
+
import { asText, toSource, truncateParams } from '@aalis/schema-i18n';
|
|
8
9
|
import { truncateChars } from '@aalis/util-text-normalize';
|
|
10
|
+
import { t } from './texts.js';
|
|
9
11
|
/** 让出时限的缺省(秒),工具可以声明自己的 */
|
|
10
12
|
export const DEFAULT_YIELD_SECONDS = 30;
|
|
11
13
|
/** 两项上限的缺省,插件配置的默认值取这里 */
|
|
@@ -20,13 +22,11 @@ const LINE_SCAN = 1024;
|
|
|
20
22
|
const MAX_ENDED_PER_SESSION = 20;
|
|
21
23
|
/** 停止后等落定的宽限:进程服务的中止契约在宽限后整组强制结束(2 秒),再留 1 秒收尾 */
|
|
22
24
|
const STOP_GRACE_MS = 3000;
|
|
23
|
-
/**
|
|
25
|
+
/** 原因最多多少字:失败的(结果里的 error)整句截到它,宿主写的文字对象把参数截到它 */
|
|
24
26
|
const REASON_MAX = 200;
|
|
25
27
|
const NOTICE_SOURCE_PREFIX = 'bg:';
|
|
26
28
|
/** 私有目录下的后台任务登记 */
|
|
27
29
|
const STORE = 'background-tasks.json';
|
|
28
|
-
const RESTART_REASON = 'Aalis 重启时还在跑';
|
|
29
|
-
const CLOSED_REASON = '工具注册表停用时还在跑';
|
|
30
30
|
const STATUSES = new Set([
|
|
31
31
|
'running',
|
|
32
32
|
'completed',
|
|
@@ -34,13 +34,12 @@ const STATUSES = new Set([
|
|
|
34
34
|
'stopped',
|
|
35
35
|
'aborted',
|
|
36
36
|
]);
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/** 对话回合里的调用:有 turnId 与 callId,转到后台后有可以通知的对话 */
|
|
37
|
+
/**
|
|
38
|
+
* 对话回合里的调用:在入站回合里(inbound 在)、有 turnId 与 callId,转到后台后有可以通知的对话。结束通知带着起它的那一轮,
|
|
39
|
+
* 只有入站回合里的调用给得出它
|
|
40
|
+
*/
|
|
42
41
|
export function inTurn(ctx) {
|
|
43
|
-
return ctx.turnId !== undefined && ctx.callId !== undefined;
|
|
42
|
+
return ctx.inbound !== undefined && ctx.turnId !== undefined && ctx.callId !== undefined;
|
|
44
43
|
}
|
|
45
44
|
/** text 的末尾 n 字,不从代理对中间切开 */
|
|
46
45
|
function tailOf(text, n) {
|
|
@@ -72,7 +71,7 @@ export function viewOf(task) {
|
|
|
72
71
|
...(task.endedAt !== undefined ? { endedAt: iso(task.endedAt) } : {}),
|
|
73
72
|
...(task.lastLine !== undefined ? { lastLine: task.lastLine } : {}),
|
|
74
73
|
...(task.lastOutputAt !== undefined ? { lastOutputAt: iso(task.lastOutputAt) } : {}),
|
|
75
|
-
...(task.reason !== undefined ? { reason: task.reason } : {}),
|
|
74
|
+
...(task.reason !== undefined ? { reason: toSource(task.reason) } : {}),
|
|
76
75
|
...(task.exitCode !== undefined ? { exitCode: task.exitCode } : {}),
|
|
77
76
|
};
|
|
78
77
|
}
|
|
@@ -134,7 +133,7 @@ function parseStored(value) {
|
|
|
134
133
|
const endedAt = optionalOf(value.endedAt, 'number');
|
|
135
134
|
const lastLine = optionalOf(value.lastLine, 'string');
|
|
136
135
|
const lastOutputAt = optionalOf(value.lastOutputAt, 'number');
|
|
137
|
-
const reason =
|
|
136
|
+
const reason = asText(value.reason);
|
|
138
137
|
const exitCode = Number.isInteger(value.exitCode) ? value.exitCode : undefined;
|
|
139
138
|
return {
|
|
140
139
|
id,
|
|
@@ -151,18 +150,22 @@ function parseStored(value) {
|
|
|
151
150
|
...(exitCode !== undefined ? { exitCode } : {}),
|
|
152
151
|
};
|
|
153
152
|
}
|
|
154
|
-
/** 结果里的 error
|
|
155
|
-
function
|
|
153
|
+
/** 结果里的 error 原文(不是字符串的写成 JSON);结果不是 JSON 对象或没有 error 时没有 */
|
|
154
|
+
export function errorIn(content) {
|
|
156
155
|
try {
|
|
157
156
|
const error = Reflect.get(JSON.parse(content), 'error');
|
|
158
157
|
if (error === undefined)
|
|
159
158
|
return undefined;
|
|
160
|
-
return
|
|
159
|
+
return typeof error === 'string' ? error : JSON.stringify(error);
|
|
161
160
|
}
|
|
162
161
|
catch {
|
|
163
162
|
return undefined;
|
|
164
163
|
}
|
|
165
164
|
}
|
|
165
|
+
/** 命令类工具的退出码:按展示种类写明的键从结果里取,别的种类没有 */
|
|
166
|
+
export function exitCodeOf(display, content) {
|
|
167
|
+
return display?.kind === 'command' && display.result ? integerIn(content, display.result.exitCode) : undefined;
|
|
168
|
+
}
|
|
166
169
|
/** 等 promise 落定,最多等 ms,中止信号到达即返回 */
|
|
167
170
|
function within(promise, ms, signal) {
|
|
168
171
|
return new Promise(resolve => {
|
|
@@ -187,6 +190,8 @@ function settleWithin(promise, ms, signal) {
|
|
|
187
190
|
resolve(undefined);
|
|
188
191
|
}, ms);
|
|
189
192
|
signal.addEventListener('abort', stopTimer, { once: true });
|
|
193
|
+
if (signal.aborted)
|
|
194
|
+
stopTimer();
|
|
190
195
|
void promise.then(value => {
|
|
191
196
|
stopTimer();
|
|
192
197
|
signal.removeEventListener('abort', stopTimer);
|
|
@@ -247,7 +252,7 @@ export class BackgroundTasks {
|
|
|
247
252
|
return within(Promise.all(ids.flatMap(id => this.records.get(id)?.ended ?? [])), ms, signal);
|
|
248
253
|
}
|
|
249
254
|
// ---- 执行器 ----
|
|
250
|
-
/**
|
|
255
|
+
/** 不可转后台的调用的输出口:对话回合里的转成 tool:output */
|
|
251
256
|
outputFor(ctx) {
|
|
252
257
|
let sent = 0;
|
|
253
258
|
return text => {
|
|
@@ -278,6 +283,7 @@ export class BackgroundTasks {
|
|
|
278
283
|
plan,
|
|
279
284
|
controller: new AbortController(),
|
|
280
285
|
output: new OutputTail(),
|
|
286
|
+
approving: new Set(),
|
|
281
287
|
};
|
|
282
288
|
this.calls.add(call);
|
|
283
289
|
return call;
|
|
@@ -288,8 +294,9 @@ export class BackgroundTasks {
|
|
|
288
294
|
}
|
|
289
295
|
/**
|
|
290
296
|
* 跑一次占到位置、过了守卫的可转后台调用。让出时限从这里算起,前台时回合中止一并中止它。到时没结束或要求立即转后台:
|
|
291
|
-
* 对话回合里的调用登记成后台任务、摘掉与回合的联动,先回给模型任务 id
|
|
292
|
-
*
|
|
297
|
+
* 对话回合里的调用登记成后台任务、摘掉与回合的联动,先回给模型任务 id 与已有输出的末尾;不在对话回合里的(没有可通知的对话)
|
|
298
|
+
* 中止并回报已有输出。处理函数里的取用判定在前台时可能等一道审批,等着时不让出,到了让出时限还在等的,等审批都结了重新计一个
|
|
299
|
+
* 让出时限;转到后台之后(要求立即转的从一开始)只按参与者都过判、不出审批:回合结束时没结的审批会被撤掉。审批随这次调用中止撤销
|
|
293
300
|
*/
|
|
294
301
|
async run(call, spec) {
|
|
295
302
|
const { ctx } = spec;
|
|
@@ -298,11 +305,20 @@ export class BackgroundTasks {
|
|
|
298
305
|
ctx.signal?.addEventListener('abort', onTurnAbort, { once: true });
|
|
299
306
|
const unlink = () => ctx.signal?.removeEventListener('abort', onTurnAbort);
|
|
300
307
|
const startedAt = Date.now();
|
|
301
|
-
const settled = spec.invoke({ ...ctx, signal, output: text => this.write(call, ctx, text) });
|
|
302
|
-
void settled.then(() => this.calls.delete(call));
|
|
303
308
|
const { waitSeconds, immediate } = call.plan;
|
|
309
|
+
const own = { ...ctx, signal };
|
|
310
|
+
const settled = spec.invoke({
|
|
311
|
+
...own,
|
|
312
|
+
output: text => this.write(call, ctx, text),
|
|
313
|
+
approveFor: check => this.approving(call, spec.approve(own, check, !immediate && !call.record)),
|
|
314
|
+
});
|
|
315
|
+
void settled.then(() => this.calls.delete(call));
|
|
304
316
|
if (!immediate) {
|
|
305
|
-
|
|
317
|
+
let finished = await settleWithin(settled, waitSeconds * 1000, signal);
|
|
318
|
+
while (!finished && call.approving.size > 0) {
|
|
319
|
+
await Promise.race([settled, Promise.allSettled(call.approving)]);
|
|
320
|
+
finished = await settleWithin(settled, waitSeconds * 1000, signal);
|
|
321
|
+
}
|
|
306
322
|
if (finished) {
|
|
307
323
|
unlink();
|
|
308
324
|
return finished.value;
|
|
@@ -328,7 +344,7 @@ export class BackgroundTasks {
|
|
|
328
344
|
}
|
|
329
345
|
/** 工具撤回登记(所属插件停用):这个登记在跑的调用一并中止,后台的落成 aborted */
|
|
330
346
|
withdraw(owner, name) {
|
|
331
|
-
this.abortWhere(call => call.owner === owner,
|
|
347
|
+
this.abortWhere(call => call.owner === owner, t('withdrawn', { name }));
|
|
332
348
|
}
|
|
333
349
|
// ---- 插件接线 ----
|
|
334
350
|
/**
|
|
@@ -372,12 +388,19 @@ export class BackgroundTasks {
|
|
|
372
388
|
}
|
|
373
389
|
/** 停用(收尾):在跑的调用一并中止,后台的落成 aborted,等写盘落定 */
|
|
374
390
|
async close() {
|
|
375
|
-
this.abortWhere(() => true, this.shuttingDown ?
|
|
391
|
+
this.abortWhere(() => true, t(this.shuttingDown ? 'restarted' : 'closed'));
|
|
376
392
|
await this.writing;
|
|
377
393
|
}
|
|
378
394
|
// ---- 内部 ----
|
|
395
|
+
/** 处理函数里在等的一次取用判定:等着时这次调用不转后台 */
|
|
396
|
+
approving(call, verdict) {
|
|
397
|
+
call.approving.add(verdict);
|
|
398
|
+
const done = () => call.approving.delete(verdict);
|
|
399
|
+
void verdict.then(done, done);
|
|
400
|
+
return verdict;
|
|
401
|
+
}
|
|
379
402
|
/**
|
|
380
|
-
*
|
|
403
|
+
* 推给界面:对话回合里的调用转成 tool:output。sent 是这次调用此前写过的字数,推出的总量不超过 OUTPUT_LIMIT:
|
|
381
404
|
* 界面按条目累加输出,前台最多要等 maxWaitSeconds,持续大量输出的命令不能把它撑满
|
|
382
405
|
*/
|
|
383
406
|
stream(ctx, text, sent) {
|
|
@@ -431,14 +454,18 @@ export class BackgroundTasks {
|
|
|
431
454
|
...(lastAt !== undefined ? { lastOutputAt: lastAt } : {}),
|
|
432
455
|
},
|
|
433
456
|
output: call.output,
|
|
434
|
-
//
|
|
457
|
+
// 起它的那一轮就是这次调用所在那一轮:平台、发言者、这次调用的参与者(批过的是批的人)、来源,以及那一轮自己的 fromTurn
|
|
435
458
|
...(chained
|
|
436
459
|
? {}
|
|
437
460
|
: {
|
|
438
461
|
notice: {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
462
|
+
fromTurn: {
|
|
463
|
+
platform: ctx.platform ?? 'unknown',
|
|
464
|
+
userId: ctx.userId,
|
|
465
|
+
participants: ctx.participants,
|
|
466
|
+
source: ctx.inbound?.source,
|
|
467
|
+
fromTurn: ctx.inbound?.fromTurn,
|
|
468
|
+
},
|
|
442
469
|
...(ctx.inbound?.messageId !== undefined ? { replyTo: ctx.inbound.messageId } : {}),
|
|
443
470
|
},
|
|
444
471
|
}),
|
|
@@ -462,14 +489,15 @@ export class BackgroundTasks {
|
|
|
462
489
|
// 已经落成 aborted(撤回、停用)或随会话删掉的不再改
|
|
463
490
|
if (!call || this.records.get(record.task.id) !== record)
|
|
464
491
|
return;
|
|
465
|
-
const exitCode = display
|
|
492
|
+
const exitCode = exitCodeOf(display, result.content);
|
|
466
493
|
const ending = { result, ...(exitCode !== undefined ? { exitCode } : {}) };
|
|
467
494
|
if (call.stopRequested) {
|
|
468
495
|
this.land(record, 'stopped', ending);
|
|
469
496
|
return;
|
|
470
497
|
}
|
|
471
498
|
const status = toolFailed(result.content, exitCode) ? 'failed' : 'completed';
|
|
472
|
-
const
|
|
499
|
+
const error = status === 'failed' ? errorIn(result.content) : undefined;
|
|
500
|
+
const reason = error === undefined ? undefined : truncateChars(error, REASON_MAX, '…');
|
|
473
501
|
this.land(record, status, { ...ending, ...(reason !== undefined ? { reason } : {}) });
|
|
474
502
|
if (record.notice && !this.shuttingDown)
|
|
475
503
|
this.notify(record, status, record.notice);
|
|
@@ -482,7 +510,9 @@ export class BackgroundTasks {
|
|
|
482
510
|
this.prune(record.task.sessionId);
|
|
483
511
|
this.persist();
|
|
484
512
|
}
|
|
485
|
-
|
|
513
|
+
/** 中止匹配的调用,后台的落成 aborted;原因随登记落盘,参数截短 */
|
|
514
|
+
abortWhere(match, why) {
|
|
515
|
+
const reason = truncateParams(why, REASON_MAX);
|
|
486
516
|
for (const call of this.calls) {
|
|
487
517
|
if (!match(call))
|
|
488
518
|
continue;
|
|
@@ -509,18 +539,21 @@ export class BackgroundTasks {
|
|
|
509
539
|
void this.events.emit('background:changed', { task: { ...record.task } });
|
|
510
540
|
}
|
|
511
541
|
/**
|
|
512
|
-
* 结束通知只放宿主取得的事实:任务 id
|
|
513
|
-
*
|
|
514
|
-
*
|
|
542
|
+
* 结束通知只放宿主取得的事实:任务 id、工具名、结局与退出码、用时,正文写给模型,同样的事实另给界面,给人看的那句另写
|
|
543
|
+
* (不带给模型的用法提示)。参数由模型写出(可能受过注入),输出与结果受外部内容左右,都不进通知(通知以 system 呈现且
|
|
544
|
+
* 会归档);它们由模型用 background_output 取,以 tool 角色进上下文。只有正常结束(completed、failed)的通知
|
|
515
545
|
*/
|
|
516
546
|
notify({ task }, status, target) {
|
|
517
547
|
const durationMs = (task.endedAt ?? task.startedAt) - task.startedAt;
|
|
518
548
|
const { exitCode } = task;
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
549
|
+
const failedExit = status === 'failed' && exitCode !== undefined && exitCode !== 0;
|
|
550
|
+
const ending = status === 'completed' ? '已完成' : failedExit ? `失败:退出码 ${exitCode}` : '失败';
|
|
551
|
+
const said = { id: task.id, tool: task.label, ms: durationMs };
|
|
552
|
+
const text = status === 'completed'
|
|
553
|
+
? t('noticeCompleted', said)
|
|
554
|
+
: failedExit
|
|
555
|
+
? t('noticeFailedExit', { ...said, code: exitCode })
|
|
556
|
+
: t('noticeFailed', said);
|
|
524
557
|
const facts = {
|
|
525
558
|
tool: task.label,
|
|
526
559
|
status,
|
|
@@ -530,15 +563,15 @@ export class BackgroundTasks {
|
|
|
530
563
|
const message = {
|
|
531
564
|
content: `后台任务 ${task.id}(${task.label})${ending},用时 ${formatDuration(durationMs)}。结果与输出用 background_output 查看。`,
|
|
532
565
|
sessionId: task.sessionId,
|
|
533
|
-
platform: target.platform,
|
|
566
|
+
platform: target.fromTurn.platform,
|
|
534
567
|
source: `${NOTICE_SOURCE_PREFIX}${task.id}`,
|
|
535
|
-
|
|
568
|
+
fromTurn: target.fromTurn,
|
|
536
569
|
hostNotice: {
|
|
537
570
|
kind: BACKGROUND_TASK_NOTICE,
|
|
538
571
|
id: task.id,
|
|
539
|
-
...(target.callerUserId !== undefined ? { callerUserId: target.callerUserId } : {}),
|
|
540
572
|
...(target.replyTo !== undefined ? { replyTo: target.replyTo } : {}),
|
|
541
573
|
facts,
|
|
574
|
+
text,
|
|
542
575
|
},
|
|
543
576
|
};
|
|
544
577
|
this.logger.info(`后台任务 ${task.id} 已结束,结束通知注入会话 ${task.sessionId}`);
|
|
@@ -570,7 +603,7 @@ export class BackgroundTasks {
|
|
|
570
603
|
if (task.status === 'running') {
|
|
571
604
|
Object.assign(task, {
|
|
572
605
|
status: 'aborted',
|
|
573
|
-
reason:
|
|
606
|
+
reason: t('restarted'),
|
|
574
607
|
endedAt: task.lastOutputAt ?? task.startedAt,
|
|
575
608
|
});
|
|
576
609
|
}
|