@zhin.js/core 1.5.2 → 1.5.4
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 +2 -2
- package/lib/adapter.d.ts +7 -1
- package/lib/adapter.js +28 -24
- package/lib/agent-prompt.d.ts +2 -3
- package/lib/agent-prompt.js +5 -0
- package/lib/built/ai-outbound/parse.d.ts +1 -1
- package/lib/built/ai-outbound/parse.js +2 -6
- package/lib/built/ai-outbound/plain-mention-rewrite.js +4 -4
- package/lib/built/ai-outbound/resolve.js +8 -8
- package/lib/built/ai-outbound/types.d.ts +3 -3
- package/lib/built/ai-trigger.d.ts +5 -0
- package/lib/built/ai-trigger.js +40 -13
- package/lib/built/authorization.js +4 -4
- package/lib/built/command.d.ts +2 -2
- package/lib/built/command.js +2 -2
- package/lib/built/common-adapter-tools.d.ts +11 -11
- package/lib/built/common-adapter-tools.js +13 -13
- package/lib/built/config.d.ts +0 -4
- package/lib/built/config.js +0 -4
- package/lib/built/dispatcher.d.ts +2 -0
- package/lib/built/dispatcher.js +1 -1
- package/lib/built/endpoint-commands.js +2 -2
- package/lib/built/endpoint-lifecycle-service.js +13 -13
- package/lib/built/endpoint-lifecycle.d.ts +3 -3
- package/lib/built/endpoint-lifecycle.js +2 -2
- package/lib/built/endpoint-manager.d.ts +1 -1
- package/lib/built/interactive-segments/index.d.ts +1 -1
- package/lib/built/interactive-segments/index.js +1 -1
- package/lib/built/interactive-segments/keyboard-segment.d.ts +0 -1
- package/lib/built/interactive-segments/keyboard-segment.js +0 -1
- package/lib/built/interactive-segments/onebot-keyboard.d.ts +0 -3
- package/lib/built/interactive-segments/onebot-keyboard.js +0 -2
- package/lib/built/interactive-segments/resolve.d.ts +0 -3
- package/lib/built/interactive-segments/resolve.js +0 -3
- package/lib/built/interactive-segments/types.d.ts +8 -20
- package/lib/built/interactive-segments/types.js +0 -4
- package/lib/built/login-assist.d.ts +2 -2
- package/lib/built/login-assist.js +2 -2
- package/lib/built/message-enrich.d.ts +1 -1
- package/lib/built/message-enrich.js +2 -7
- package/lib/built/permission.d.ts +0 -4
- package/lib/built/permission.js +0 -4
- package/lib/built/prepend-quote-context.js +5 -5
- package/lib/built/rich-segments/capabilities.js +0 -1
- package/lib/built/rich-segments/html-segment.js +1 -4
- package/lib/built/rich-segments/markdown-segment.js +1 -4
- package/lib/built/rich-segments/types.d.ts +0 -5
- package/lib/built/schema-endpoint-manager.js +6 -6
- package/lib/built/tool.d.ts +5 -3
- package/lib/built/tool.js +14 -23
- package/lib/command.d.ts +4 -4
- package/lib/command.js +8 -11
- package/lib/endpoint-capabilities.d.ts +2 -3
- package/lib/endpoint-capabilities.js +4 -4
- package/lib/endpoint.d.ts +2 -0
- package/lib/endpoint.js +1 -0
- package/lib/errors.d.ts +2 -2
- package/lib/errors.js +4 -4
- package/lib/host-plugin-registry.d.ts +6 -5
- package/lib/host-plugin-registry.js +9 -4
- package/lib/im-scene.d.ts +1 -1
- package/lib/im-scene.js +5 -5
- package/lib/im-session-id.d.ts +2 -2
- package/lib/im-session-id.js +4 -4
- package/lib/index.d.ts +1 -2
- package/lib/index.js +0 -2
- package/lib/jsx-runtime.d.ts +1 -0
- package/lib/jsx.d.ts +19 -21
- package/lib/message.d.ts +1 -1
- package/lib/message.js +1 -1
- package/lib/notice.d.ts +2 -2
- package/lib/plugin-context.d.ts +11 -13
- package/lib/plugin-context.js +21 -18
- package/lib/plugin-runtime/im/contracts.d.ts +91 -12
- package/lib/plugin-runtime/im/contracts.js +79 -1
- package/lib/plugin-runtime/im/im-runtime.d.ts +33 -23
- package/lib/plugin-runtime/im/im-runtime.js +104 -63
- package/lib/plugin-runtime/im/index.d.ts +2 -0
- package/lib/plugin-runtime/im/index.js +2 -0
- package/lib/plugin-runtime/im/message-bus.d.ts +38 -0
- package/lib/plugin-runtime/im/message-bus.js +40 -0
- package/lib/plugin-runtime/im/message-dispatcher.js +13 -73
- package/lib/plugin-runtime/im/outbound-renderer.d.ts +3 -2
- package/lib/plugin-runtime/im/outbound-renderer.js +44 -8
- package/lib/plugin-runtime/im/service-tokens.d.ts +18 -0
- package/lib/plugin-runtime/im/service-tokens.js +13 -0
- package/lib/plugin.d.ts +4 -7
- package/lib/plugin.js +7 -30
- package/lib/request.d.ts +2 -2
- package/lib/side-event/types.d.ts +0 -4
- package/lib/types.d.ts +6 -11
- package/lib/utils.js +3 -1
- package/package.json +13 -12
- package/lib/built/qrcode-segment.d.ts +0 -18
- package/lib/built/qrcode-segment.js +0 -78
- package/lib/types-generator.d.ts +0 -5
- package/lib/types-generator.js +0 -71
|
@@ -12,12 +12,10 @@ export const defaultCommandPrefixResolver = (message, snapshot) => {
|
|
|
12
12
|
const config = snapshot.config.get(ownerOfMessage(message));
|
|
13
13
|
if (!config)
|
|
14
14
|
return '';
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
: undefined;
|
|
18
|
-
if (endpointName && Array.isArray(config.endpoints)) {
|
|
15
|
+
const endpointId = message.endpointId;
|
|
16
|
+
if (endpointId && Array.isArray(config.endpoints)) {
|
|
19
17
|
const entry = config.endpoints.find((item) => !!item && typeof item === 'object'
|
|
20
|
-
&& item.
|
|
18
|
+
&& item.id === endpointId);
|
|
21
19
|
if (typeof entry?.commandPrefix === 'string')
|
|
22
20
|
return entry.commandPrefix;
|
|
23
21
|
}
|
|
@@ -31,79 +29,35 @@ export class MessageDispatcher {
|
|
|
31
29
|
async dispatch(message, snapshot) {
|
|
32
30
|
const prefix = this.resolvePrefix(message, snapshot);
|
|
33
31
|
let input = message.content.trim();
|
|
34
|
-
|
|
35
|
-
op: 'command_dispatch_start',
|
|
36
|
-
adapter: ownerOfMessage(message),
|
|
37
|
-
endpoint: typeof message.metadata?.endpoint === 'string'
|
|
38
|
-
? message.metadata.endpoint
|
|
39
|
-
: undefined,
|
|
40
|
-
prefix: prefix || '(none)',
|
|
41
|
-
preview: truncatePreview(input),
|
|
42
|
-
segments: summarizeSegmentTypes(message.segments),
|
|
43
|
-
}));
|
|
44
|
-
if (prefix) {
|
|
45
|
-
if (!input.startsWith(prefix)) {
|
|
46
|
-
logger.debug(formatCompact({
|
|
47
|
-
op: 'command_dispatch_miss',
|
|
48
|
-
reason: 'prefix_miss',
|
|
49
|
-
prefix,
|
|
50
|
-
preview: truncatePreview(input),
|
|
51
|
-
}));
|
|
52
|
-
return Object.freeze({ matched: false });
|
|
53
|
-
}
|
|
54
|
-
input = input.slice(prefix.length).trim();
|
|
55
|
-
}
|
|
56
|
-
if (!input) {
|
|
57
|
-
logger.debug(formatCompact({
|
|
58
|
-
op: 'command_dispatch_miss',
|
|
59
|
-
reason: 'empty_after_prefix',
|
|
60
|
-
prefix: prefix || '(none)',
|
|
61
|
-
}));
|
|
32
|
+
if (prefix && !input.startsWith(prefix)) {
|
|
62
33
|
return Object.freeze({ matched: false });
|
|
63
34
|
}
|
|
35
|
+
if (prefix)
|
|
36
|
+
input = input.slice(prefix.length).trim();
|
|
37
|
+
if (!input)
|
|
38
|
+
return Object.freeze({ matched: false });
|
|
64
39
|
const commands = snapshot.projections.get(commandFeatureId);
|
|
65
|
-
if (!isCommandIndex(commands))
|
|
66
|
-
logger.debug(formatCompact({
|
|
67
|
-
op: 'command_dispatch_miss',
|
|
68
|
-
reason: 'no_command_index',
|
|
69
|
-
}));
|
|
40
|
+
if (!isCommandIndex(commands))
|
|
70
41
|
return Object.freeze({ matched: false });
|
|
71
|
-
}
|
|
72
42
|
const structuredInput = message.segments
|
|
73
43
|
? stripCommandPrefix(message.segments, prefix)
|
|
74
44
|
: undefined;
|
|
75
|
-
if (message.segments && structuredInput === undefined) {
|
|
76
|
-
logger.debug(formatCompact({
|
|
77
|
-
op: 'command_dispatch_fallback_text',
|
|
78
|
-
reason: 'strip_prefix_failed',
|
|
79
|
-
prefix: prefix || '(none)',
|
|
80
|
-
segments: summarizeSegmentTypes(message.segments),
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
45
|
const matchInput = structuredInput ?? input;
|
|
84
|
-
logger.debug(formatCompact({
|
|
85
|
-
op: 'command_dispatch_match_input',
|
|
86
|
-
mode: typeof matchInput === 'string' ? 'text' : 'segments',
|
|
87
|
-
preview: typeof matchInput === 'string'
|
|
88
|
-
? truncatePreview(matchInput)
|
|
89
|
-
: summarizeSegmentTypes(matchInput),
|
|
90
|
-
}));
|
|
91
46
|
const result = await commands.dispatch(matchInput, message);
|
|
92
47
|
if (result.matched && result.value !== undefined) {
|
|
93
48
|
if (!result.owner)
|
|
94
49
|
throw new Error('Matched Command is missing its owner');
|
|
95
50
|
logger.debug(formatCompact({
|
|
96
|
-
op: '
|
|
51
|
+
op: 'dispatch_hit',
|
|
97
52
|
command: result.command,
|
|
98
53
|
owner: result.owner,
|
|
99
54
|
}));
|
|
100
55
|
await message.$replyFrom(result.owner, result.value);
|
|
101
56
|
}
|
|
102
|
-
else {
|
|
57
|
+
else if (!result.matched) {
|
|
103
58
|
logger.debug(formatCompact({
|
|
104
|
-
op: '
|
|
105
|
-
|
|
106
|
-
command: result.command,
|
|
59
|
+
op: 'dispatch_miss',
|
|
60
|
+
preview: truncatePreview(input),
|
|
107
61
|
}));
|
|
108
62
|
}
|
|
109
63
|
return result;
|
|
@@ -151,17 +105,3 @@ function stripCommandPrefix(segments, prefix) {
|
|
|
151
105
|
}
|
|
152
106
|
return pendingPrefix ? undefined : result;
|
|
153
107
|
}
|
|
154
|
-
function summarizeSegmentTypes(segments) {
|
|
155
|
-
if (!segments?.length)
|
|
156
|
-
return undefined;
|
|
157
|
-
return segments
|
|
158
|
-
.map((segment) => {
|
|
159
|
-
if (typeof segment.type === 'string')
|
|
160
|
-
return segment.type;
|
|
161
|
-
if (segment.type && typeof segment.type === 'object' && 'name' in segment.type) {
|
|
162
|
-
return String(segment.type.name);
|
|
163
|
-
}
|
|
164
|
-
return '?';
|
|
165
|
-
})
|
|
166
|
-
.join(',');
|
|
167
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PluginId, RuntimeSnapshot } from '@zhin.js/plugin-runtime';
|
|
2
|
-
import {
|
|
2
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
3
|
+
import { type IncomingContext, type SendContent } from './contracts.js';
|
|
3
4
|
export declare class OutboundRenderer {
|
|
4
5
|
#private;
|
|
5
|
-
render(content: SendContent, requester: PluginId, snapshot: RuntimeSnapshot): Promise<unknown>;
|
|
6
|
+
render(content: SendContent, requester: PluginId, snapshot: RuntimeSnapshot, conversation?: ConversationRef, incoming?: IncomingContext): Promise<unknown>;
|
|
6
7
|
}
|
|
@@ -1,30 +1,66 @@
|
|
|
1
|
+
import { componentHostToken } from '@zhin.js/plugin-runtime';
|
|
1
2
|
import { componentFeatureId, isComponentIndex, } from '@zhin.js/component';
|
|
2
3
|
import { isComponentCall, isRawContent, isSegmentContent, } from './contracts.js';
|
|
3
4
|
const maxComponentDepth = 32;
|
|
5
|
+
const TEMPLATE_MARKER = '${';
|
|
4
6
|
export class OutboundRenderer {
|
|
5
|
-
async render(content, requester, snapshot) {
|
|
6
|
-
|
|
7
|
+
async render(content, requester, snapshot, conversation, incoming) {
|
|
8
|
+
const host = resolveComponentHost(snapshot);
|
|
9
|
+
const ctx = conversation ? buildTemplateContext(conversation, incoming) : undefined;
|
|
10
|
+
return this.#render(content, requester, snapshot, host, ctx, 0);
|
|
7
11
|
}
|
|
8
|
-
async #render(content, requester, snapshot, depth) {
|
|
12
|
+
async #render(content, requester, snapshot, host, ctx, depth) {
|
|
9
13
|
if (depth > maxComponentDepth)
|
|
10
14
|
throw new Error('Component render depth exceeded 32');
|
|
11
15
|
if (typeof content === 'string')
|
|
12
|
-
return content;
|
|
16
|
+
return compileText(content, host, ctx);
|
|
13
17
|
if (Array.isArray(content)) {
|
|
14
|
-
return Promise.all(content.map((item) => this.#render(item, requester, snapshot, depth)));
|
|
18
|
+
return Promise.all(content.map((item) => this.#render(item, requester, snapshot, host, ctx, depth)));
|
|
15
19
|
}
|
|
16
20
|
if (isRawContent(content))
|
|
17
21
|
return content.payload;
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
if (isSegmentContent(content)) {
|
|
23
|
+
if (content.type === 'text') {
|
|
24
|
+
const text = content.data?.text;
|
|
25
|
+
if (typeof text === 'string' && text.includes(TEMPLATE_MARKER) && host && ctx) {
|
|
26
|
+
return { ...content, data: { ...content.data, text: host.compileTemplate(text, ctx) } };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
20
29
|
return content;
|
|
30
|
+
}
|
|
21
31
|
if (isComponentCall(content)) {
|
|
22
32
|
const rendered = await requireComponents(snapshot).render(requester, content.name, content.props);
|
|
23
|
-
return this.#render(rendered, requester, snapshot, depth + 1);
|
|
33
|
+
return this.#render(rendered, requester, snapshot, host, ctx, depth + 1);
|
|
24
34
|
}
|
|
25
35
|
throw new TypeError('Unsupported SendContent');
|
|
26
36
|
}
|
|
27
37
|
}
|
|
38
|
+
function compileText(text, host, ctx) {
|
|
39
|
+
if (!host || !ctx || !text.includes(TEMPLATE_MARKER))
|
|
40
|
+
return text;
|
|
41
|
+
return host.compileTemplate(text, ctx);
|
|
42
|
+
}
|
|
43
|
+
function buildTemplateContext(conversation, incoming) {
|
|
44
|
+
return {
|
|
45
|
+
adapter: conversation.endpoint.adapter,
|
|
46
|
+
endpoint: conversation.endpoint.id,
|
|
47
|
+
kind: conversation.kind,
|
|
48
|
+
conversationId: conversation.id,
|
|
49
|
+
sender: incoming?.sender,
|
|
50
|
+
content: incoming?.content,
|
|
51
|
+
segments: incoming?.segments,
|
|
52
|
+
messageId: incoming?.messageId,
|
|
53
|
+
timestamp: incoming?.timestamp,
|
|
54
|
+
endpointId: incoming?.endpointId,
|
|
55
|
+
mentioned: incoming?.mentioned,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function resolveComponentHost(snapshot) {
|
|
59
|
+
const host = snapshot.resources.get(snapshot.root)?.get(componentHostToken.id);
|
|
60
|
+
return host && typeof host.compileTemplate === 'function'
|
|
61
|
+
? host
|
|
62
|
+
: undefined;
|
|
63
|
+
}
|
|
28
64
|
function requireComponents(snapshot) {
|
|
29
65
|
const projection = snapshot.projections.get(componentFeatureId);
|
|
30
66
|
if (!isComponentIndex(projection)) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core service tokens — typed Token 替代 legacy string-based inject('x')。
|
|
3
|
+
*
|
|
4
|
+
* Slice 2:Token 指向当前 Feature 实例(双写窗口)。
|
|
5
|
+
* Slice 4:Feature 删除后,Token 类型改为 Runtime projection 接口。
|
|
6
|
+
*/
|
|
7
|
+
import type { CommandFeature } from '../../built/command.js';
|
|
8
|
+
import type { ComponentFeature } from '../../built/component.js';
|
|
9
|
+
import type { ScheduleFeature } from '../../built/schedule.js';
|
|
10
|
+
import type { ConfigFeature } from '../../built/config.js';
|
|
11
|
+
import type { SchemaFeature } from '../../built/schema-feature.js';
|
|
12
|
+
import type { MessageDispatcherService } from '../../built/dispatcher.js';
|
|
13
|
+
export declare const commandServiceToken: import("@zhin.js/plugin-runtime").Token<CommandFeature>;
|
|
14
|
+
export declare const componentServiceToken: import("@zhin.js/plugin-runtime").Token<ComponentFeature>;
|
|
15
|
+
export declare const schedulerServiceToken: import("@zhin.js/plugin-runtime").Token<ScheduleFeature>;
|
|
16
|
+
export declare const configServiceToken: import("@zhin.js/plugin-runtime").Token<ConfigFeature>;
|
|
17
|
+
export declare const schemaServiceToken: import("@zhin.js/plugin-runtime").Token<SchemaFeature>;
|
|
18
|
+
export declare const dispatcherServiceToken: import("@zhin.js/plugin-runtime").Token<MessageDispatcherService>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core service tokens — typed Token 替代 legacy string-based inject('x')。
|
|
3
|
+
*
|
|
4
|
+
* Slice 2:Token 指向当前 Feature 实例(双写窗口)。
|
|
5
|
+
* Slice 4:Feature 删除后,Token 类型改为 Runtime projection 接口。
|
|
6
|
+
*/
|
|
7
|
+
import { createToken } from '@zhin.js/plugin-runtime';
|
|
8
|
+
export const commandServiceToken = createToken('zhin.im.command-service');
|
|
9
|
+
export const componentServiceToken = createToken('zhin.im.component-service');
|
|
10
|
+
export const schedulerServiceToken = createToken('zhin.im.scheduler-service');
|
|
11
|
+
export const configServiceToken = createToken('zhin.im.config-service');
|
|
12
|
+
export const schemaServiceToken = createToken('zhin.im.schema-service');
|
|
13
|
+
export const dispatcherServiceToken = createToken('zhin.im.dispatcher-service');
|
package/lib/plugin.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { MessageMiddleware, RegisteredAdapter, MaybePromise, ArrayItem, SendOpti
|
|
|
10
10
|
import type { InteractiveHandler } from "./built/interactive-segments/types.js";
|
|
11
11
|
import { Adapter, Adapters } from "./adapter.js";
|
|
12
12
|
import { PluginBase, PluginBaseLifecycle, type PluginLike } from '@zhin.js/kernel';
|
|
13
|
-
export { getPlugin } from "./plugin-context.js";
|
|
13
|
+
export { getPlugin, markPluginRuntimeActive, isPluginRuntimeActive, resetPluginRuntimeFlag } from "./plugin-context.js";
|
|
14
14
|
export { storage, getCurrentFile } from "./plugin-context.js";
|
|
15
15
|
export { setHostRootPlugin, getHostRootPlugin } from "./host-plugin-registry.js";
|
|
16
16
|
declare const contextsKey: unique symbol;
|
|
@@ -22,11 +22,8 @@ export type DisposeFn<A> = (context: ArrayItem<A>) => MaybePromise<void>;
|
|
|
22
22
|
export type ContextList<CS extends (keyof Plugin.Contexts)[]> = CS extends [infer L, ...infer R] ? R extends (keyof Plugin.Contexts)[] ? [ContextItem<L>, ...ContextList<R>] : never[] : never[];
|
|
23
23
|
type ContextItem<L> = L extends keyof Plugin.Contexts ? Plugin.Contexts[L] : never;
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* @deprecated 仅 `zhin.js/node`(`bootstrapNode`)可用;`zhin runtime start` 下不工作。
|
|
29
|
-
* 新插件请用 `definePlugin` + 约定目录。见 `docs/contributing/public-api-surface.md`。
|
|
25
|
+
* @deprecated **已删除**。请使用 `definePlugin` + 约定目录(`zhin runtime start`)。
|
|
26
|
+
* @throws 总是抛出——仅保留签名供编译期过渡。
|
|
30
27
|
*/
|
|
31
28
|
export declare function usePlugin(): Plugin;
|
|
32
29
|
export interface Plugin extends Plugin.Extensions {
|
|
@@ -223,7 +220,7 @@ export declare namespace Plugin {
|
|
|
223
220
|
path?: 'chat' | 'fast' | 'agent' | 'multimodal' | 'rate_limited';
|
|
224
221
|
userId?: string;
|
|
225
222
|
platform?: string;
|
|
226
|
-
|
|
223
|
+
endpointKey?: string;
|
|
227
224
|
sceneId?: string;
|
|
228
225
|
messageId?: string;
|
|
229
226
|
scope?: string;
|
package/lib/plugin.js
CHANGED
|
@@ -14,9 +14,8 @@ import { compose, remove, resolveEntry } from "./utils.js";
|
|
|
14
14
|
import { ensureInteractiveMiddleware, registerInteractiveHandler as registerInteractiveHandlerCore, } from "./built/interactive-segments/handlers.js";
|
|
15
15
|
import { Adapter } from "./adapter.js";
|
|
16
16
|
import { Feature, PluginBase, resolvePluginResolveDir as _resolvePluginResolveDir, pluginCreateRequire as _pluginCreateRequire, getFileHash, watchFile, registerExtension, unregisterExtensions, installExtensionProxy } from '@zhin.js/kernel';
|
|
17
|
-
import { storage
|
|
18
|
-
|
|
19
|
-
export { getPlugin } from "./plugin-context.js";
|
|
17
|
+
import { storage } from "./plugin-context.js";
|
|
18
|
+
export { getPlugin, markPluginRuntimeActive, isPluginRuntimeActive, resetPluginRuntimeFlag } from "./plugin-context.js";
|
|
20
19
|
export { storage, getCurrentFile } from "./plugin-context.js";
|
|
21
20
|
export { setHostRootPlugin, getHostRootPlugin } from "./host-plugin-registry.js";
|
|
22
21
|
const contextsKey = Symbol("contexts");
|
|
@@ -27,34 +26,13 @@ const loadedModules = new Map();
|
|
|
27
26
|
function pluginCreateRequire() {
|
|
28
27
|
return _pluginCreateRequire();
|
|
29
28
|
}
|
|
30
|
-
// ============================================================================
|
|
31
|
-
// usePlugin — 获取或创建当前插件实例
|
|
32
|
-
// ============================================================================
|
|
33
29
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* @deprecated 仅 `zhin.js/node`(`bootstrapNode`)可用;`zhin runtime start` 下不工作。
|
|
38
|
-
* 新插件请用 `definePlugin` + 约定目录。见 `docs/contributing/public-api-surface.md`。
|
|
30
|
+
* @deprecated **已删除**。请使用 `definePlugin` + 约定目录(`zhin runtime start`)。
|
|
31
|
+
* @throws 总是抛出——仅保留签名供编译期过渡。
|
|
39
32
|
*/
|
|
40
33
|
export function usePlugin() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const callerFile = getCurrentFile(import.meta.url);
|
|
44
|
-
// 如果当前 store 已是同一文件创建的插件,直接返回
|
|
45
|
-
const current = storage.getStore();
|
|
46
|
-
if (current && current.filePath.replace(/\?t=\d+$/, '') === callerFile.replace(/\?t=\d+$/, '')) {
|
|
47
|
-
return current;
|
|
48
|
-
}
|
|
49
|
-
const parentPlugin = current;
|
|
50
|
-
const newPlugin = new Plugin(callerFile, parentPlugin);
|
|
51
|
-
try {
|
|
52
|
-
storage.enterWith(newPlugin);
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
// Cloudflare Workers 等环境未实现 enterWith;调用方须用 storage.run()
|
|
56
|
-
}
|
|
57
|
-
return newPlugin;
|
|
34
|
+
throw new Error('usePlugin() has been removed. Use `definePlugin` + convention directories instead. '
|
|
35
|
+
+ 'See docs/contributing/public-api-surface.md');
|
|
58
36
|
}
|
|
59
37
|
/**
|
|
60
38
|
* Plugin 类 - IM 特化插件,继承 PluginBase
|
|
@@ -210,10 +188,9 @@ export class Plugin extends PluginBase {
|
|
|
210
188
|
sideEffect.finished = false;
|
|
211
189
|
};
|
|
212
190
|
this.on('context.dispose', disposeFn);
|
|
213
|
-
// 确保 dispose 时清理监听器(只注册一次)
|
|
214
191
|
const cleanupOnDispose = () => {
|
|
215
192
|
this.off('context.dispose', disposeFn);
|
|
216
|
-
dispose(this.inject(
|
|
193
|
+
dispose(this.inject(contexts[0]));
|
|
217
194
|
};
|
|
218
195
|
this.once('dispose', cleanupOnDispose);
|
|
219
196
|
};
|
package/lib/request.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { MaybePromise } from './types.js';
|
|
|
2
2
|
import type { Adapters } from './adapter.js';
|
|
3
3
|
import type { RequestKind } from './side-event/types.js';
|
|
4
4
|
import type { SideEventBase } from './side-event/base.js';
|
|
5
|
-
export type { RequestKind, ComposedRequestName
|
|
5
|
+
export type { RequestKind, ComposedRequestName } from './side-event/types.js';
|
|
6
6
|
/**
|
|
7
7
|
* 请求基础结构 — 继承 SideEventBase,附加审批方法。
|
|
8
8
|
*
|
|
@@ -11,7 +11,7 @@ export type { RequestKind, ComposedRequestName, RequestType } from './side-event
|
|
|
11
11
|
* const request = Request.from(rawEvent, {
|
|
12
12
|
* $id: rawEvent.flag,
|
|
13
13
|
* $adapter: 'icqq',
|
|
14
|
-
* $endpoint:
|
|
14
|
+
* $endpoint: endpointKey,
|
|
15
15
|
* $type: 'request',
|
|
16
16
|
* $scene_id: groupId,
|
|
17
17
|
* $scene_type: 'group',
|
|
@@ -9,10 +9,6 @@ export type RequestKind = 'request';
|
|
|
9
9
|
/** 完整组合名(测试 / 文档 / 消费者匹配用) */
|
|
10
10
|
export type ComposedNoticeName = 'notice.group.member_increase' | 'notice.group.member_decrease' | 'notice.group.admin_change' | 'notice.group.ban' | 'notice.group.recall' | 'notice.group.poke' | 'notice.group.transfer' | 'notice.group.upload' | 'notice.group.emoji_reaction' | 'notice.group.card_change' | 'notice.group.essence_add' | 'notice.group.essence_delete' | 'notice.friend.recall' | 'notice.friend.increase' | 'notice.friend.poke' | 'notice.endpoint.lifecycle' | (string & {});
|
|
11
11
|
export type ComposedRequestName = 'request.friend.add' | 'request.group.add' | 'request.group.invite' | (string & {});
|
|
12
|
-
/** @deprecated 使用 ComposedNoticeName + formatSideEventName */
|
|
13
|
-
export type NoticeType = ComposedNoticeName;
|
|
14
|
-
/** @deprecated 使用 ComposedRequestName + formatSideEventName */
|
|
15
|
-
export type RequestType = ComposedRequestName;
|
|
16
12
|
export interface SideEventParts {
|
|
17
13
|
scene_type: string;
|
|
18
14
|
sub_type: string;
|
package/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MessageChannel, Message, MessageComponent } from './message.js';
|
|
1
|
+
import type { MessageChannel, Message, MessageComponent } from './message.js';
|
|
2
2
|
import { Adapter, Adapters } from './adapter.js';
|
|
3
3
|
import { Endpoint } from './endpoint.js';
|
|
4
4
|
import { SystemLog } from './models/system-log.js';
|
|
@@ -85,9 +85,6 @@ export interface EditMessageOptions {
|
|
|
85
85
|
type: 'private' | 'group' | 'channel';
|
|
86
86
|
content: SendContent;
|
|
87
87
|
}
|
|
88
|
-
export interface EditableEndpoint {
|
|
89
|
-
$editMessage?(options: EditMessageOptions): Promise<void>;
|
|
90
|
-
}
|
|
91
88
|
/** 出站回复来源(指令 / AI / proactive),仅当经 MessageDispatcher.replyWithPolish 或 runWithOutboundPolish 发出时由框架填入异步上下文 */
|
|
92
89
|
export type OutboundReplySource = 'command' | 'ai' | 'proactive';
|
|
93
90
|
export type OutboundReplyTrigger = 'inbound' | 'proactive';
|
|
@@ -125,7 +122,7 @@ export interface MessageSender {
|
|
|
125
122
|
/**
|
|
126
123
|
* 通用字典类型
|
|
127
124
|
*/
|
|
128
|
-
export type Dict
|
|
125
|
+
export type { Dict } from '@zhin.js/kernel';
|
|
129
126
|
/**
|
|
130
127
|
* 用户信息结构
|
|
131
128
|
*/
|
|
@@ -180,7 +177,7 @@ export type BeforeSendHandler = (options: SendOptions) => MaybePromise<SendOptio
|
|
|
180
177
|
* JSON Schema 定义,用于描述工具参数
|
|
181
178
|
*/
|
|
182
179
|
/** Message 通讯上下文上可经 resolveContextKey 自动注入的字段名 */
|
|
183
|
-
export type ContextInjectableKey = 'platform' | '
|
|
180
|
+
export type ContextInjectableKey = 'platform' | 'endpointKey' | 'sceneId' | 'senderId' | 'scope';
|
|
184
181
|
export interface ToolJsonSchema {
|
|
185
182
|
type: string;
|
|
186
183
|
properties?: Record<string, ToolJsonSchema & {
|
|
@@ -195,7 +192,7 @@ export interface ToolJsonSchema {
|
|
|
195
192
|
/**
|
|
196
193
|
* 自动从 Message 通讯上下文注入的字段名(经 resolveContextKey 映射 $ 字段)。
|
|
197
194
|
* 设置后该参数对 AI 隐藏,执行时自动从上下文填充。
|
|
198
|
-
* 例如: contextKey: '
|
|
195
|
+
* 例如: contextKey: 'endpointKey' → 执行时自动填入 message.$endpoint
|
|
199
196
|
*/
|
|
200
197
|
contextKey?: ContextInjectableKey;
|
|
201
198
|
[key: string]: any;
|
|
@@ -340,6 +337,8 @@ export interface Tool<TArgs extends Record<string, any> = Record<string, any>> {
|
|
|
340
337
|
* 执行此工具需要的权限列表
|
|
341
338
|
*/
|
|
342
339
|
permissions?: string[];
|
|
340
|
+
/** Per-tool approval policy; `on-risk` remains fail-closed at Agent boundaries. */
|
|
341
|
+
approval?: 'always' | 'once' | 'never' | 'on-risk';
|
|
343
342
|
/**
|
|
344
343
|
* 支持的平台列表
|
|
345
344
|
* 例如:['qq', 'telegram', 'discord']
|
|
@@ -372,10 +371,6 @@ export interface Tool<TArgs extends Record<string, any> = Record<string, any>> {
|
|
|
372
371
|
*/
|
|
373
372
|
command?: ToolCommandConfig | false;
|
|
374
373
|
}
|
|
375
|
-
/**
|
|
376
|
-
* @deprecated 使用 `Tool<TArgs>` 替代。Tool 已原生支持泛型。
|
|
377
|
-
*/
|
|
378
|
-
export type ToolDefinition<TArgs extends Record<string, any> = Record<string, any>> = Tool<TArgs>;
|
|
379
374
|
export declare namespace Tool {
|
|
380
375
|
/**
|
|
381
376
|
* 参数信息
|
package/lib/utils.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Generic utilities are re-exported from @zhin.js/kernel.
|
|
5
5
|
* IM-specific utilities (compose, segment) remain here.
|
|
6
6
|
*/
|
|
7
|
+
import { getLogger } from '@zhin.js/logger';
|
|
8
|
+
const logger = getLogger('Middleware');
|
|
7
9
|
// ── Re-export generic utils from kernel ──
|
|
8
10
|
export { evaluate, execute, clearEvalCache, getEvalCacheStats, getValueWithRuntime, compiler, remove, isEmpty, Time, supportedPluginExtensions, resolveEntry, sleep, } from '@zhin.js/kernel';
|
|
9
11
|
import { formatSegmentPreview } from "./built/segment-contract/preview.js";
|
|
@@ -39,7 +41,7 @@ export function compose(middlewares) {
|
|
|
39
41
|
return await fn(message, () => dispatch(i + 1));
|
|
40
42
|
}
|
|
41
43
|
catch (error) {
|
|
42
|
-
|
|
44
|
+
logger.error("Middleware error:", error);
|
|
43
45
|
throw error;
|
|
44
46
|
}
|
|
45
47
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/core",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "Zhin机器人核心框架",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -70,16 +70,17 @@
|
|
|
70
70
|
"segment-matcher": "^1.0.5",
|
|
71
71
|
"smol-toml": "^1.7.1",
|
|
72
72
|
"yaml": "^2.9.0",
|
|
73
|
-
"@zhin.js/
|
|
74
|
-
"@zhin.js/
|
|
75
|
-
"@zhin.js/component": "1.0.
|
|
76
|
-
"@zhin.js/database": "1.0.
|
|
77
|
-
"@zhin.js/im-contract": "1.0.
|
|
78
|
-
"@zhin.js/kernel": "1.0.
|
|
79
|
-
"@zhin.js/logger": "1.0.
|
|
80
|
-
"@zhin.js/middleware": "1.0.
|
|
81
|
-
"@zhin.js/
|
|
82
|
-
"@zhin.js/
|
|
73
|
+
"@zhin.js/command": "1.0.9",
|
|
74
|
+
"@zhin.js/adapter": "1.1.7",
|
|
75
|
+
"@zhin.js/component": "1.0.8",
|
|
76
|
+
"@zhin.js/database": "1.0.79",
|
|
77
|
+
"@zhin.js/im-contract": "1.0.3",
|
|
78
|
+
"@zhin.js/kernel": "1.0.7",
|
|
79
|
+
"@zhin.js/logger": "1.0.76",
|
|
80
|
+
"@zhin.js/middleware": "1.0.8",
|
|
81
|
+
"@zhin.js/permission": "1.0.1",
|
|
82
|
+
"@zhin.js/plugin-runtime": "1.1.5",
|
|
83
|
+
"@zhin.js/schema": "1.0.73"
|
|
83
84
|
},
|
|
84
85
|
"peerDependencies": {
|
|
85
86
|
"zod": "^4.0.0"
|
|
@@ -94,7 +95,7 @@
|
|
|
94
95
|
"@types/qrcode": "^1.5.6",
|
|
95
96
|
"ajv": "8.18.0",
|
|
96
97
|
"typescript": "^6.0.3",
|
|
97
|
-
"@zhin.js/ai": "1.5.
|
|
98
|
+
"@zhin.js/ai": "1.5.2"
|
|
98
99
|
},
|
|
99
100
|
"repository": {
|
|
100
101
|
"type": "git",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 出站 `qrcode` 消息段(legacy 导出;新代码请用 rich-segments)。
|
|
3
|
-
* @deprecated 出站渲染由 Adapter.renderSendMessage → resolveRichSegments 统一处理
|
|
4
|
-
*/
|
|
5
|
-
import type { SendContent } from '../types.js';
|
|
6
|
-
import { QrcodeSegment, readQrcodeSegmentData, type QrcodeSegmentData } from './rich-segments/qrcode-segment.js';
|
|
7
|
-
export type { QrcodeSegmentData };
|
|
8
|
-
export { QrcodeSegment, readQrcodeSegmentData };
|
|
9
|
-
export type QrcodeOutboundMode = 'image' | 'terminal' | 'text';
|
|
10
|
-
export declare function hasQrcodeSegment(content: SendContent | undefined): boolean;
|
|
11
|
-
/** 创建 qrcode 出站段 */
|
|
12
|
-
export declare function qrcodeSegment(text: string, options?: Omit<QrcodeSegmentData, 'text'>): QrcodeSegment;
|
|
13
|
-
/** IM 适配器:qrcode → image(data URL + base64) */
|
|
14
|
-
export declare function resolveQrcodeSegmentsToImages(content: SendContent | undefined): Promise<SendContent | undefined>;
|
|
15
|
-
/** process 适配器:终端 ASCII + 文本占位(legacy;process endpoint 现解释 origin qrcode) */
|
|
16
|
-
export declare function resolveQrcodeSegmentsToTerminal(content: SendContent | undefined): Promise<SendContent | undefined>;
|
|
17
|
-
/** 不支持图片的平台:仅输出链接文本 */
|
|
18
|
-
export declare function coerceQrcodeSegmentsToText(content: SendContent): SendContent;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { segment } from '../utils.js';
|
|
2
|
-
import { GeneratedQrCode } from './generated-qrcode.js';
|
|
3
|
-
import { QrcodeSegment, readQrcodeSegmentData, } from './rich-segments/qrcode-segment.js';
|
|
4
|
-
export { QrcodeSegment, readQrcodeSegmentData };
|
|
5
|
-
function asArray(content) {
|
|
6
|
-
return Array.isArray(content) ? content : [content];
|
|
7
|
-
}
|
|
8
|
-
function packSegments(out) {
|
|
9
|
-
if (out.length === 0)
|
|
10
|
-
return segment.text('');
|
|
11
|
-
if (out.length === 1)
|
|
12
|
-
return out[0];
|
|
13
|
-
return out;
|
|
14
|
-
}
|
|
15
|
-
export function hasQrcodeSegment(content) {
|
|
16
|
-
if (content == null)
|
|
17
|
-
return false;
|
|
18
|
-
return asArray(content).some((item) => typeof item !== 'string' && item?.type === 'qrcode');
|
|
19
|
-
}
|
|
20
|
-
/** 创建 qrcode 出站段 */
|
|
21
|
-
export function qrcodeSegment(text, options = {}) {
|
|
22
|
-
return new QrcodeSegment({ text, ...options });
|
|
23
|
-
}
|
|
24
|
-
const LEGACY_QRCODE_ONLY_POLICY = {
|
|
25
|
-
qrcode: 'image',
|
|
26
|
-
html: 'origin',
|
|
27
|
-
markdown: 'origin',
|
|
28
|
-
};
|
|
29
|
-
/** IM 适配器:qrcode → image(data URL + base64) */
|
|
30
|
-
export async function resolveQrcodeSegmentsToImages(content) {
|
|
31
|
-
if (content == null)
|
|
32
|
-
return content;
|
|
33
|
-
const { resolveRichSegments } = await import('./rich-segments/index.js');
|
|
34
|
-
return resolveRichSegments(content, LEGACY_QRCODE_ONLY_POLICY);
|
|
35
|
-
}
|
|
36
|
-
/** process 适配器:终端 ASCII + 文本占位(legacy;process endpoint 现解释 origin qrcode) */
|
|
37
|
-
export async function resolveQrcodeSegmentsToTerminal(content) {
|
|
38
|
-
if (content == null)
|
|
39
|
-
return content;
|
|
40
|
-
if (!hasQrcodeSegment(content))
|
|
41
|
-
return content;
|
|
42
|
-
const items = asArray(content);
|
|
43
|
-
const out = [];
|
|
44
|
-
for (const item of items) {
|
|
45
|
-
if (typeof item === 'string') {
|
|
46
|
-
out.push(item);
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
if (item.type !== 'qrcode') {
|
|
50
|
-
out.push(item);
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
const payload = readQrcodeSegmentData(item.data ?? {});
|
|
54
|
-
const qr = await GeneratedQrCode.generate(payload.text, payload);
|
|
55
|
-
await qr.printToTerminal({ small: payload.small ?? true });
|
|
56
|
-
out.push(segment.text(`[二维码] ${payload.text}`));
|
|
57
|
-
}
|
|
58
|
-
return packSegments(out);
|
|
59
|
-
}
|
|
60
|
-
/** 不支持图片的平台:仅输出链接文本 */
|
|
61
|
-
export function coerceQrcodeSegmentsToText(content) {
|
|
62
|
-
const items = asArray(content);
|
|
63
|
-
const out = [];
|
|
64
|
-
for (const item of items) {
|
|
65
|
-
if (typeof item === 'string') {
|
|
66
|
-
out.push(item);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (item?.type === 'qrcode') {
|
|
70
|
-
const text = typeof item.data?.text === 'string' ? item.data.text : '';
|
|
71
|
-
if (text)
|
|
72
|
-
out.push(segment.text(`[二维码] ${text}`));
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
out.push(item);
|
|
76
|
-
}
|
|
77
|
-
return packSegments(out);
|
|
78
|
-
}
|