@downcity/plugins 1.0.30 → 1.0.34
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/bin/BuiltinPlugins.js +2 -2
- package/bin/BuiltinPlugins.js.map +1 -1
- package/bin/asr/Config.d.ts +1 -1
- package/bin/asr/Config.d.ts.map +1 -1
- package/bin/auth/Plugin.d.ts +6 -6
- package/bin/auth/Plugin.d.ts.map +1 -1
- package/bin/auth/Plugin.js +29 -20
- package/bin/auth/Plugin.js.map +1 -1
- package/bin/auth/types/AuthPlugin.d.ts +19 -19
- package/bin/auth/types/AuthPlugin.d.ts.map +1 -1
- package/bin/auth/types/AuthPlugin.js +17 -17
- package/bin/auth/types/AuthPlugin.js.map +1 -1
- package/bin/chat/ChatPlugin.d.ts +1 -1
- package/bin/chat/ChatPlugin.d.ts.map +1 -1
- package/bin/chat/accounts/Store.d.ts +1 -1
- package/bin/chat/accounts/Store.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelConfig.d.ts +1 -1
- package/bin/chat/runtime/ChatChannelConfig.d.ts.map +1 -1
- package/bin/chat/runtime/ChatChannelCore.d.ts +1 -1
- package/bin/chat/runtime/ChatChannelCore.d.ts.map +1 -1
- package/bin/chat/runtime/ChatQueueWorker.d.ts.map +1 -1
- package/bin/chat/runtime/ChatQueueWorker.js +2 -3
- package/bin/chat/runtime/ChatQueueWorker.js.map +1 -1
- package/bin/chat/runtime/PluginDispatch.js.map +1 -1
- package/bin/chat/runtime/PluginPoints.d.ts +3 -3
- package/bin/chat/runtime/PluginPoints.js +3 -3
- package/bin/chat/types/ChannelAccount.d.ts +1 -1
- package/bin/chat/types/ChannelAccount.d.ts.map +1 -1
- package/bin/index.d.ts +3 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +2 -2
- package/bin/index.js.map +1 -1
- package/bin/shell/runtime/ShellActionRuntime.js +1 -1
- package/bin/shell/runtime/ShellActionRuntime.js.map +1 -1
- package/bin/shell/runtime/ShellRuntimeEnvironment.d.ts.map +1 -1
- package/bin/shell/runtime/ShellRuntimeEnvironment.js +5 -2
- package/bin/shell/runtime/ShellRuntimeEnvironment.js.map +1 -1
- package/bin/task/runtime/TaskRunnerRound.d.ts.map +1 -1
- package/bin/task/runtime/TaskRunnerRound.js +6 -3
- package/bin/task/runtime/TaskRunnerRound.js.map +1 -1
- package/bin/voice/Config.d.ts +1 -1
- package/bin/voice/Config.d.ts.map +1 -1
- package/bin/workboard/runtime/Collector.d.ts.map +1 -1
- package/bin/workboard/runtime/Collector.js +3 -5
- package/bin/workboard/runtime/Collector.js.map +1 -1
- package/bin/workboard/runtime/Normalizer.d.ts +3 -3
- package/bin/workboard/runtime/Normalizer.d.ts.map +1 -1
- package/bin/workboard/runtime/Normalizer.js.map +1 -1
- package/bin/workboard/runtime/SessionSummary.d.ts +47 -0
- package/bin/workboard/runtime/SessionSummary.d.ts.map +1 -0
- package/bin/workboard/runtime/SessionSummary.js +51 -0
- package/bin/workboard/runtime/SessionSummary.js.map +1 -0
- package/package.json +2 -2
- package/src/BuiltinPlugins.ts +2 -2
- package/src/asr/Config.ts +1 -1
- package/src/auth/Plugin.ts +151 -134
- package/src/auth/types/AuthPlugin.ts +24 -24
- package/src/chat/ChatPlugin.ts +1 -1
- package/src/chat/accounts/ChannelAccountManager.ts +2 -2
- package/src/chat/accounts/Store.ts +1 -1
- package/src/chat/runtime/ChatChannelConfig.ts +1 -1
- package/src/chat/runtime/ChatChannelCore.ts +1 -1
- package/src/chat/runtime/ChatQueueWorker.ts +1 -5
- package/src/chat/runtime/PluginDispatch.ts +2 -2
- package/src/chat/runtime/PluginPoints.ts +3 -3
- package/src/chat/types/ChannelAccount.ts +1 -1
- package/src/index.ts +6 -6
- package/src/shell/runtime/ShellActionRuntime.ts +1 -1
- package/src/shell/runtime/ShellRuntimeEnvironment.ts +6 -2
- package/src/task/runtime/TaskRunnerRound.ts +7 -3
- package/src/voice/Config.ts +1 -1
- package/src/workboard/runtime/Collector.ts +3 -5
- package/src/workboard/runtime/Normalizer.ts +5 -5
- package/src/workboard/runtime/SessionSummary.ts +92 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workboard session 摘要采集。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - workboard 只需要模糊运行态,不复用 Town control 视图模型。
|
|
6
|
+
* - 这里只读取消息数量、更新时间与执行中状态,不暴露消息内容。
|
|
7
|
+
*/
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
/**
|
|
11
|
+
* 采集 workboard 需要的 session 摘要。
|
|
12
|
+
*/
|
|
13
|
+
export async function listWorkboardSessionSummaries(params) {
|
|
14
|
+
const root_dir = params.context.paths.getDowncitySessionRootDirPath();
|
|
15
|
+
if (!(await fs.pathExists(root_dir)))
|
|
16
|
+
return [];
|
|
17
|
+
const entries = await fs.readdir(root_dir, { withFileTypes: true });
|
|
18
|
+
const items = [];
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
if (!entry.isDirectory())
|
|
21
|
+
continue;
|
|
22
|
+
const session_id = decodeMaybe(entry.name);
|
|
23
|
+
if (!session_id)
|
|
24
|
+
continue;
|
|
25
|
+
const messages_path = path.join(params.context.paths.getDowncitySessionDirPath(session_id), "messages", "messages.jsonl");
|
|
26
|
+
const stat = await fs.stat(messages_path).catch(() => null);
|
|
27
|
+
items.push({
|
|
28
|
+
sessionId: session_id,
|
|
29
|
+
messageCount: await countJsonlLines(messages_path),
|
|
30
|
+
...(stat ? { updatedAt: stat.mtimeMs } : {}),
|
|
31
|
+
...(params.executingSessionIds?.has(session_id) ? { executing: true } : {}),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
items.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
|
|
35
|
+
return items.slice(0, Math.max(1, params.limit));
|
|
36
|
+
}
|
|
37
|
+
async function countJsonlLines(file_path) {
|
|
38
|
+
const raw = await fs.readFile(file_path, "utf-8").catch(() => "");
|
|
39
|
+
if (!raw)
|
|
40
|
+
return 0;
|
|
41
|
+
return raw.split("\n").filter((line) => line.trim()).length;
|
|
42
|
+
}
|
|
43
|
+
function decodeMaybe(value) {
|
|
44
|
+
try {
|
|
45
|
+
return decodeURIComponent(String(value || "")).trim();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return String(value || "").trim();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=SessionSummary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionSummary.js","sourceRoot":"","sources":["../../../src/workboard/runtime/SessionSummary.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAyB7B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,MAanD;IACC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,CAAC;IACtE,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,KAAK,GAA8B,EAAE,CAAC;IAE5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QACnC,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAC7B,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,UAAU,CAAC,EAC1D,UAAU,EACV,gBAAgB,CACjB,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC5D,KAAK,CAAC,IAAI,CAAC;YACT,SAAS,EAAE,UAAU;YACrB,YAAY,EAAE,MAAM,eAAe,CAAC,aAAa,CAAC;YAClD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,mBAAmB,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,SAAiB;IAC9C,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAClE,IAAI,CAAC,GAAG;QAAE,OAAO,CAAC,CAAC;IACnB,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;AAC9D,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@downcity/plugins",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Downcity 内建 plugin 集合包",
|
|
6
6
|
"main": "./bin/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"node-cron": "^4.2.1",
|
|
23
23
|
"ws": "^8.21.0",
|
|
24
24
|
"zod": "^4.4.3",
|
|
25
|
-
"@downcity/agent": "^1.1.
|
|
25
|
+
"@downcity/agent": "^1.1.79"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/better-sqlite3": "^7.6.13",
|
package/src/BuiltinPlugins.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { AgentRuntime } from "@downcity/agent/internal/types/runtime/agent/AgentRuntime.js";
|
|
11
11
|
import type { BasePlugin } from "@downcity/agent/internal/plugin/core/BasePlugin.js";
|
|
12
|
-
import {
|
|
12
|
+
import { ChatAuthorizationPlugin } from "@/auth/Plugin.js";
|
|
13
13
|
import { SkillPlugin } from "@/skill/Plugin.js";
|
|
14
14
|
import { WebPlugin } from "@/web/Plugin.js";
|
|
15
15
|
import { AsrPlugin } from "@/asr/Plugin.js";
|
|
@@ -32,7 +32,7 @@ export type BuiltinPluginClass<T extends BasePlugin = BasePlugin> = new (
|
|
|
32
32
|
* 全部内建 plugin classes。
|
|
33
33
|
*/
|
|
34
34
|
export const BUILTIN_PLUGIN_CLASSES: BuiltinPluginClass[] = [
|
|
35
|
-
|
|
35
|
+
ChatAuthorizationPlugin,
|
|
36
36
|
SkillPlugin,
|
|
37
37
|
WebPlugin,
|
|
38
38
|
AsrPlugin,
|
package/src/asr/Config.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { VoicePluginConfig } from "@/voice/types/VoicePlugin.js";
|
|
10
|
-
import type { AgentPluginConfigRuntime } from "@downcity/agent/internal/types/
|
|
10
|
+
import type { AgentPluginConfigRuntime } from "@downcity/agent/internal/types/agent/AgentRuntimeAssembly.js";
|
|
11
11
|
import type { JsonObject, JsonValue } from "@downcity/agent/internal/types/common/Json.js";
|
|
12
12
|
|
|
13
13
|
/**
|
package/src/auth/Plugin.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ChatAuthorizationPlugin。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* -
|
|
5
|
+
* - chat-authorization 是内建且必需的 plugin,不走可选启停语义。
|
|
6
6
|
* - 静态授权配置与动态观测态都收敛在项目 `.downcity/chat/authorization/`。
|
|
7
|
-
* -
|
|
7
|
+
* - 它只负责聊天主体授权,不负责 Town HTTP Bearer token 或路由访问鉴权。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { AgentRuntime } from "@downcity/agent/internal/types/runtime/agent/AgentRuntime.js";
|
|
@@ -13,10 +13,12 @@ import type { Plugin } from "@downcity/agent/internal/plugin/types/Plugin.js";
|
|
|
13
13
|
import type { JsonValue } from "@downcity/agent/internal/types/common/Json.js";
|
|
14
14
|
import { CHAT_PLUGIN_POINTS } from "@/chat/runtime/PluginPoints.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
type
|
|
16
|
+
CHAT_AUTHORIZATION_ACTIONS,
|
|
17
|
+
CHAT_AUTHORIZATION_CATALOG,
|
|
18
|
+
CHAT_AUTHORIZATION_PLUGIN_NAME,
|
|
19
|
+
type ChatAuthorizationObservePrincipalPayload,
|
|
20
|
+
type ChatAuthorizationSetUserRolePayload,
|
|
21
|
+
type ChatAuthorizationWriteConfigPayload,
|
|
20
22
|
type ChatAuthorizationConfig,
|
|
21
23
|
type ChatAuthorizationEvaluateInput,
|
|
22
24
|
type ChatAuthorizationSnapshot,
|
|
@@ -50,7 +52,7 @@ function toRecord(value: unknown): Record<string, unknown> {
|
|
|
50
52
|
function toEvaluateInput(payload: Record<string, unknown>): ChatAuthorizationEvaluateInput {
|
|
51
53
|
const channel = toChannel(payload.channel);
|
|
52
54
|
if (!channel) {
|
|
53
|
-
throw new Error("
|
|
55
|
+
throw new Error("chat-authorization.authorize_incoming requires a valid channel");
|
|
54
56
|
}
|
|
55
57
|
return {
|
|
56
58
|
channel,
|
|
@@ -64,158 +66,173 @@ function toEvaluateInput(payload: Record<string, unknown>): ChatAuthorizationEva
|
|
|
64
66
|
|
|
65
67
|
function toSnapshotData(snapshot: ChatAuthorizationSnapshot): JsonValue {
|
|
66
68
|
return {
|
|
69
|
+
catalog: CHAT_AUTHORIZATION_CATALOG as unknown as JsonValue,
|
|
67
70
|
config: snapshot.config as unknown as JsonValue,
|
|
68
71
|
users: snapshot.users as unknown as JsonValue,
|
|
69
72
|
chats: snapshot.chats as unknown as JsonValue,
|
|
70
73
|
};
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
function
|
|
76
|
+
function createChatAuthorizationPluginDefinition(): Plugin {
|
|
74
77
|
return {
|
|
75
|
-
name:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
},
|
|
86
|
-
hooks: {
|
|
87
|
-
guard: {
|
|
88
|
-
[CHAT_PLUGIN_POINTS.authorizeIncoming]: [
|
|
89
|
-
async ({ context, value }) => {
|
|
90
|
-
const input =
|
|
91
|
-
value && typeof value === "object" && !Array.isArray(value)
|
|
92
|
-
? (value as Record<string, unknown>)
|
|
93
|
-
: {};
|
|
94
|
-
const evaluateInput = toEvaluateInput(input);
|
|
95
|
-
const authorizationConfig = readChatAuthorizationConfig(context);
|
|
96
|
-
const result = evaluateIncomingChatAuthorization({
|
|
97
|
-
config: context.config,
|
|
98
|
-
channel: evaluateInput.channel,
|
|
99
|
-
input: evaluateInput,
|
|
100
|
-
authorizationConfig,
|
|
101
|
-
});
|
|
102
|
-
if (result.decision !== "allow") {
|
|
103
|
-
throw new Error(result.reason || "chat authorization blocked");
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
},
|
|
108
|
-
effect: {
|
|
109
|
-
[CHAT_PLUGIN_POINTS.observePrincipal]: [
|
|
110
|
-
async ({ context, value }) => {
|
|
111
|
-
const input = toRecord(value) as unknown as AuthObservePrincipalPayload;
|
|
112
|
-
const channel = toChannel(input.channel);
|
|
113
|
-
if (!channel) {
|
|
114
|
-
throw new Error("chat.observePrincipal requires a valid channel");
|
|
115
|
-
}
|
|
116
|
-
await recordObservedAuthorizationPrincipal({
|
|
117
|
-
context,
|
|
118
|
-
channel,
|
|
119
|
-
chatId: String(input.chatId || "").trim(),
|
|
120
|
-
...(typeof input.chatType === "string" ? { chatType: input.chatType.trim() } : {}),
|
|
121
|
-
...(typeof input.chatTitle === "string" ? { chatTitle: input.chatTitle.trim() } : {}),
|
|
122
|
-
...(typeof input.userId === "string" ? { userId: input.userId.trim() } : {}),
|
|
123
|
-
...(typeof input.username === "string" ? { username: input.username.trim() } : {}),
|
|
124
|
-
});
|
|
125
|
-
},
|
|
126
|
-
],
|
|
78
|
+
name: CHAT_AUTHORIZATION_PLUGIN_NAME,
|
|
79
|
+
title: "Chat Authorization",
|
|
80
|
+
description:
|
|
81
|
+
"Controls who can talk to the agent in chat channels, records observed users and chats, and resolves each user's effective role for downstream service decisions.",
|
|
82
|
+
availability() {
|
|
83
|
+
return {
|
|
84
|
+
enabled: true,
|
|
85
|
+
available: true,
|
|
86
|
+
reasons: [],
|
|
87
|
+
};
|
|
127
88
|
},
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
execute: async ({ context }) => {
|
|
150
|
-
const snapshot = await readAuthorizationSnapshot({
|
|
151
|
-
context,
|
|
152
|
-
});
|
|
153
|
-
return {
|
|
154
|
-
success: true,
|
|
155
|
-
data: toSnapshotData(snapshot),
|
|
156
|
-
};
|
|
89
|
+
hooks: {
|
|
90
|
+
guard: {
|
|
91
|
+
[CHAT_PLUGIN_POINTS.authorizeIncoming]: [
|
|
92
|
+
async ({ context, value }) => {
|
|
93
|
+
const input =
|
|
94
|
+
value && typeof value === "object" && !Array.isArray(value)
|
|
95
|
+
? (value as Record<string, unknown>)
|
|
96
|
+
: {};
|
|
97
|
+
const evaluateInput = toEvaluateInput(input);
|
|
98
|
+
const authorizationConfig = readChatAuthorizationConfig(context);
|
|
99
|
+
const result = evaluateIncomingChatAuthorization({
|
|
100
|
+
config: context.config,
|
|
101
|
+
channel: evaluateInput.channel,
|
|
102
|
+
input: evaluateInput,
|
|
103
|
+
authorizationConfig,
|
|
104
|
+
});
|
|
105
|
+
if (result.decision !== "allow") {
|
|
106
|
+
throw new Error(result.reason || "chat authorization blocked");
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
],
|
|
157
110
|
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
111
|
+
effect: {
|
|
112
|
+
[CHAT_PLUGIN_POINTS.observePrincipal]: [
|
|
113
|
+
async ({ context, value }) => {
|
|
114
|
+
const input = toRecord(
|
|
115
|
+
value,
|
|
116
|
+
) as unknown as ChatAuthorizationObservePrincipalPayload;
|
|
117
|
+
const channel = toChannel(input.channel);
|
|
118
|
+
if (!channel) {
|
|
119
|
+
throw new Error("chat.observePrincipal requires a valid channel");
|
|
120
|
+
}
|
|
121
|
+
await recordObservedAuthorizationPrincipal({
|
|
122
|
+
context,
|
|
123
|
+
channel,
|
|
124
|
+
chatId: String(input.chatId || "").trim(),
|
|
125
|
+
...(typeof input.chatType === "string"
|
|
126
|
+
? { chatType: input.chatType.trim() }
|
|
127
|
+
: {}),
|
|
128
|
+
...(typeof input.chatTitle === "string"
|
|
129
|
+
? { chatTitle: input.chatTitle.trim() }
|
|
130
|
+
: {}),
|
|
131
|
+
...(typeof input.userId === "string"
|
|
132
|
+
? { userId: input.userId.trim() }
|
|
133
|
+
: {}),
|
|
134
|
+
...(typeof input.username === "string"
|
|
135
|
+
? { username: input.username.trim() }
|
|
136
|
+
: {}),
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
],
|
|
165
140
|
},
|
|
166
141
|
},
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
? (body.config as ChatAuthorizationConfig)
|
|
142
|
+
resolves: {
|
|
143
|
+
[CHAT_PLUGIN_POINTS.resolveUserRole]: async ({ context, value }) => {
|
|
144
|
+
const input =
|
|
145
|
+
value && typeof value === "object" && !Array.isArray(value)
|
|
146
|
+
? (value as Record<string, unknown>)
|
|
173
147
|
: {};
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
148
|
+
const channel = toChannel(input.channel);
|
|
149
|
+
if (!channel) {
|
|
150
|
+
throw new Error("chat.resolveUserRole requires a valid channel");
|
|
151
|
+
}
|
|
152
|
+
const role = resolveAuthorizedUserRole({
|
|
153
|
+
channel,
|
|
154
|
+
userId: String(input.userId || "").trim(),
|
|
155
|
+
rootPath: context.rootPath,
|
|
177
156
|
});
|
|
178
|
-
return
|
|
179
|
-
success: true,
|
|
180
|
-
data: readChatAuthorizationConfig(context) as unknown as JsonValue,
|
|
181
|
-
};
|
|
157
|
+
return ((role || null) as unknown) as JsonValue;
|
|
182
158
|
},
|
|
183
159
|
},
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
160
|
+
actions: {
|
|
161
|
+
[CHAT_AUTHORIZATION_ACTIONS.snapshot]: {
|
|
162
|
+
execute: async ({ context }) => {
|
|
163
|
+
const snapshot = await readAuthorizationSnapshot({
|
|
164
|
+
context,
|
|
165
|
+
});
|
|
189
166
|
return {
|
|
190
|
-
success:
|
|
191
|
-
|
|
192
|
-
message: "set-user-role requires a valid channel",
|
|
167
|
+
success: true,
|
|
168
|
+
data: toSnapshotData(snapshot),
|
|
193
169
|
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
[CHAT_AUTHORIZATION_ACTIONS.readConfig]: {
|
|
173
|
+
execute: async ({ context }) => {
|
|
174
|
+
return {
|
|
175
|
+
success: true,
|
|
176
|
+
data: readChatAuthorizationConfig(context) as unknown as JsonValue,
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
[CHAT_AUTHORIZATION_ACTIONS.writeConfig]: {
|
|
181
|
+
execute: async ({ context, payload }) => {
|
|
182
|
+
const body = toRecord(
|
|
183
|
+
payload,
|
|
184
|
+
) as unknown as ChatAuthorizationWriteConfigPayload;
|
|
185
|
+
const nextConfig =
|
|
186
|
+
body.config && typeof body.config === "object" && !Array.isArray(body.config)
|
|
187
|
+
? (body.config as ChatAuthorizationConfig)
|
|
188
|
+
: {};
|
|
189
|
+
await writeChatAuthorizationConfig({
|
|
190
|
+
context,
|
|
191
|
+
nextConfig,
|
|
192
|
+
});
|
|
193
|
+
return {
|
|
194
|
+
success: true,
|
|
195
|
+
data: readChatAuthorizationConfig(context) as unknown as JsonValue,
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
[CHAT_AUTHORIZATION_ACTIONS.setUserRole]: {
|
|
200
|
+
execute: async ({ context, payload }) => {
|
|
201
|
+
const body = toRecord(
|
|
202
|
+
payload,
|
|
203
|
+
) as unknown as ChatAuthorizationSetUserRolePayload;
|
|
204
|
+
const channel = toChannel(body.channel);
|
|
205
|
+
if (!channel) {
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
error: "set-user-role requires a valid channel",
|
|
209
|
+
message: "set-user-role requires a valid channel",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
await setChatAuthorizationUserRole({
|
|
213
|
+
context,
|
|
214
|
+
channel,
|
|
215
|
+
userId: String(body.userId || "").trim(),
|
|
216
|
+
roleId: String(body.roleId || "").trim(),
|
|
217
|
+
});
|
|
218
|
+
return {
|
|
219
|
+
success: true,
|
|
220
|
+
data: readChatAuthorizationConfig(context) as unknown as JsonValue,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
205
223
|
},
|
|
206
224
|
},
|
|
207
|
-
},
|
|
208
225
|
};
|
|
209
226
|
}
|
|
210
227
|
|
|
211
228
|
/**
|
|
212
|
-
*
|
|
229
|
+
* ChatAuthorizationPlugin:统一承载聊天用户授权能力。
|
|
213
230
|
*/
|
|
214
|
-
export class
|
|
215
|
-
readonly name =
|
|
231
|
+
export class ChatAuthorizationPlugin extends BasePlugin {
|
|
232
|
+
readonly name = CHAT_AUTHORIZATION_PLUGIN_NAME;
|
|
216
233
|
|
|
217
234
|
constructor(agent: AgentRuntime | null = null) {
|
|
218
235
|
super(agent);
|
|
219
|
-
Object.assign(this,
|
|
236
|
+
Object.assign(this, createChatAuthorizationPluginDefinition());
|
|
220
237
|
}
|
|
221
238
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* ChatAuthorizationPlugin 类型与契约定义。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* -
|
|
5
|
+
* - 统一维护聊天授权 plugin 的领域类型、扩展点/action 名称、payload 契约。
|
|
6
6
|
* - 业务层不应散落硬编码字符串,如 `chat.authorizeIncoming`、`set-user-role`。
|
|
7
7
|
* - chat / console / plugin 执行链路都从这里共享同一份边界定义。
|
|
8
8
|
*/
|
|
@@ -11,12 +11,12 @@ import type { ChatDispatchChannel } from "@/chat/types/ChatDispatcher.js";
|
|
|
11
11
|
import { CHAT_PLUGIN_POINTS } from "@/chat/runtime/PluginPoints.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* 聊天授权 plugin 稳定名称。
|
|
15
15
|
*/
|
|
16
|
-
export const
|
|
16
|
+
export const CHAT_AUTHORIZATION_PLUGIN_NAME = "chat-authorization";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* 聊天授权支持的渠道目录。
|
|
20
20
|
*/
|
|
21
21
|
export const CHAT_AUTHORIZATION_CHANNELS = ["telegram", "feishu", "qq"] as const;
|
|
22
22
|
|
|
@@ -26,18 +26,18 @@ export const CHAT_AUTHORIZATION_CHANNELS = ["telegram", "feishu", "qq"] as const
|
|
|
26
26
|
export type ChatAuthorizationChannel = (typeof CHAT_AUTHORIZATION_CHANNELS)[number];
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
* 聊天授权扩展点名称集合。
|
|
30
30
|
*/
|
|
31
|
-
export const
|
|
31
|
+
export const CHAT_AUTHORIZATION_PLUGIN_POINTS = {
|
|
32
32
|
observePrincipal: CHAT_PLUGIN_POINTS.observePrincipal,
|
|
33
33
|
authorizeIncoming: CHAT_PLUGIN_POINTS.authorizeIncoming,
|
|
34
34
|
resolveUserRole: CHAT_PLUGIN_POINTS.resolveUserRole,
|
|
35
35
|
} as const;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* 聊天授权 action 名称集合。
|
|
39
39
|
*/
|
|
40
|
-
export const
|
|
40
|
+
export const CHAT_AUTHORIZATION_ACTIONS = {
|
|
41
41
|
snapshot: "snapshot",
|
|
42
42
|
readConfig: "read-config",
|
|
43
43
|
writeConfig: "write-config",
|
|
@@ -50,8 +50,8 @@ export const AUTH_ACTIONS = {
|
|
|
50
50
|
export const CHAT_AUTHORIZATION_PERMISSIONS = [
|
|
51
51
|
"chat.dm.use",
|
|
52
52
|
"chat.group.use",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
53
|
+
"chat.authorization.manage.users",
|
|
54
|
+
"chat.authorization.manage.roles",
|
|
55
55
|
"agent.view.logs",
|
|
56
56
|
"agent.manage",
|
|
57
57
|
] as const;
|
|
@@ -70,8 +70,8 @@ export const CHAT_AUTHORIZATION_PERMISSION_LABELS: Record<
|
|
|
70
70
|
> = {
|
|
71
71
|
"chat.dm.use": "DM",
|
|
72
72
|
"chat.group.use": "Group",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
73
|
+
"chat.authorization.manage.users": "Users",
|
|
74
|
+
"chat.authorization.manage.roles": "Roles",
|
|
75
75
|
"agent.view.logs": "Logs",
|
|
76
76
|
"agent.manage": "Agent",
|
|
77
77
|
};
|
|
@@ -85,8 +85,8 @@ export const CHAT_AUTHORIZATION_PERMISSION_DESCRIPTIONS: Record<
|
|
|
85
85
|
> = {
|
|
86
86
|
"chat.dm.use": "允许用户在私聊场景中直接向 agent 发送请求并得到响应。",
|
|
87
87
|
"chat.group.use": "允许用户在群聊或频道场景中触发 agent 执行对话与任务。",
|
|
88
|
-
"
|
|
89
|
-
"
|
|
88
|
+
"chat.authorization.manage.users": "允许修改聊天用户与权限组之间的绑定关系。",
|
|
89
|
+
"chat.authorization.manage.roles": "允许编辑聊天权限组定义,以及调整各渠道的新用户默认组。",
|
|
90
90
|
"agent.view.logs": "允许查看当前 agent 的运行日志与排障信息。",
|
|
91
91
|
"agent.manage": "允许执行高权限管理动作,例如变更配置、操作服务与任务。",
|
|
92
92
|
};
|
|
@@ -112,11 +112,11 @@ export interface ChatAuthorizationPermissionMeta {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
115
|
+
* 聊天授权目录快照。
|
|
116
116
|
*/
|
|
117
117
|
export interface ChatAuthorizationCatalog {
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
119
|
+
* 聊天授权支持的渠道列表。
|
|
120
120
|
*/
|
|
121
121
|
channels: ChatAuthorizationChannel[];
|
|
122
122
|
|
|
@@ -137,7 +137,7 @@ export interface ChatAuthorizationCatalog {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
*
|
|
140
|
+
* 聊天授权统一目录常量。
|
|
141
141
|
*/
|
|
142
142
|
export const CHAT_AUTHORIZATION_CATALOG: ChatAuthorizationCatalog = {
|
|
143
143
|
channels: [...CHAT_AUTHORIZATION_CHANNELS],
|
|
@@ -207,7 +207,7 @@ export function createDefaultChatAuthorizationRoles(): Record<string, ChatAuthor
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
210
|
-
*
|
|
210
|
+
* 判断给定值是否为聊天授权支持的渠道。
|
|
211
211
|
*/
|
|
212
212
|
export function isChatAuthorizationChannel(
|
|
213
213
|
value: unknown,
|
|
@@ -465,7 +465,7 @@ export interface ChatAuthorizationStateFile {
|
|
|
465
465
|
/**
|
|
466
466
|
* plugin effect 输入:记录观测主体。
|
|
467
467
|
*/
|
|
468
|
-
export interface
|
|
468
|
+
export interface ChatAuthorizationObservePrincipalPayload {
|
|
469
469
|
/**
|
|
470
470
|
* 当前渠道。
|
|
471
471
|
*/
|
|
@@ -495,7 +495,7 @@ export interface AuthObservePrincipalPayload {
|
|
|
495
495
|
/**
|
|
496
496
|
* plugin effect 输出:记录观测主体结果。
|
|
497
497
|
*/
|
|
498
|
-
export interface
|
|
498
|
+
export interface ChatAuthorizationObservePrincipalResult {
|
|
499
499
|
/**
|
|
500
500
|
* 是否成功落盘。
|
|
501
501
|
*/
|
|
@@ -505,7 +505,7 @@ export interface AuthObservePrincipalResult {
|
|
|
505
505
|
/**
|
|
506
506
|
* plugin resolve 输入:查询用户角色。
|
|
507
507
|
*/
|
|
508
|
-
export interface
|
|
508
|
+
export interface ChatAuthorizationResolveUserRolePayload {
|
|
509
509
|
/**
|
|
510
510
|
* 当前渠道。
|
|
511
511
|
*/
|
|
@@ -519,7 +519,7 @@ export interface AuthResolveUserRolePayload {
|
|
|
519
519
|
/**
|
|
520
520
|
* action: 覆盖写入配置输入。
|
|
521
521
|
*/
|
|
522
|
-
export interface
|
|
522
|
+
export interface ChatAuthorizationWriteConfigPayload {
|
|
523
523
|
/**
|
|
524
524
|
* 新配置。
|
|
525
525
|
*/
|
|
@@ -529,7 +529,7 @@ export interface AuthWriteConfigPayload {
|
|
|
529
529
|
/**
|
|
530
530
|
* action: 设置用户角色输入。
|
|
531
531
|
*/
|
|
532
|
-
export interface
|
|
532
|
+
export interface ChatAuthorizationSetUserRolePayload {
|
|
533
533
|
/**
|
|
534
534
|
* 当前渠道。
|
|
535
535
|
*/
|
package/src/chat/ChatPlugin.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { BasePlugin } from "@downcity/agent/internal/plugin/core/BasePlugin.js";
|
|
|
13
13
|
import type { PluginActions } from "@downcity/agent/internal/plugin/types/Plugin.js";
|
|
14
14
|
import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
|
|
15
15
|
import type { ChatChannelState } from "@/chat/types/ChatRuntime.js";
|
|
16
|
-
import type { StoredChannelAccount } from "@downcity/agent/internal/types/
|
|
16
|
+
import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
|
|
17
17
|
import type { ChatQueueWorkerConfig } from "@/chat/types/ChatQueueWorker.js";
|
|
18
18
|
import type {
|
|
19
19
|
ChatPluginFeishuOptions,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import crypto from "node:crypto";
|
|
11
|
-
import type { StoredChannelAccountChannel } from "@downcity/agent/internal/types/
|
|
11
|
+
import type { StoredChannelAccountChannel } from "@downcity/agent/internal/types/platform/Store.js";
|
|
12
12
|
import { resolveChatChannelBotInfo } from "@/chat/channels/BotInfoProvider.js";
|
|
13
13
|
import {
|
|
14
14
|
getStoredChannelAccountSync,
|
|
@@ -24,7 +24,7 @@ import type {
|
|
|
24
24
|
ChatChannelAccountProbeResult,
|
|
25
25
|
ChatChannelAccountUpsertInput,
|
|
26
26
|
} from "@/chat/types/ChannelAccount.js";
|
|
27
|
-
import type { StoredChannelAccount } from "@downcity/agent/internal/types/
|
|
27
|
+
import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
|
|
28
28
|
|
|
29
29
|
const SUPPORTED_CHANNELS: readonly StoredChannelAccountChannel[] = [
|
|
30
30
|
"telegram",
|
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
StoredChannelAccount,
|
|
21
21
|
StoredChannelAccountChannel,
|
|
22
22
|
UpsertChannelAccountInput,
|
|
23
|
-
} from "@downcity/agent/internal/types/
|
|
23
|
+
} from "@downcity/agent/internal/types/platform/Store.js";
|
|
24
24
|
|
|
25
25
|
function nowIso(): string {
|
|
26
26
|
return new Date().toISOString();
|
|
@@ -11,7 +11,7 @@ import fs from "node:fs/promises";
|
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import type { JsonObject, JsonValue } from "@downcity/agent/internal/types/common/Json.js";
|
|
13
13
|
import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
|
|
14
|
-
import type { StoredChannelAccount } from "@downcity/agent/internal/types/
|
|
14
|
+
import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
|
|
15
15
|
import type {
|
|
16
16
|
ChatChannelName,
|
|
17
17
|
ChatChannelStateSnapshot,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { AgentContext } from "@downcity/agent/internal/types/runtime/agent/AgentContext.js";
|
|
11
|
-
import type { StoredChannelAccount } from "@downcity/agent/internal/types/
|
|
11
|
+
import type { StoredChannelAccount } from "@downcity/agent/internal/types/platform/Store.js";
|
|
12
12
|
import type { ChatChannelName } from "@/chat/types/ChannelStatus.js";
|
|
13
13
|
import type { ChatChannelState } from "@/chat/types/ChatRuntime.js";
|
|
14
14
|
import { getStoredChannelAccountSync } from "@/chat/accounts/Store.js";
|