@zhin.js/core 1.5.13 → 1.5.15

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/lib/adapter.d.ts CHANGED
@@ -41,9 +41,10 @@ export declare abstract class Adapter<R extends Endpoint = Endpoint, const Caps
41
41
  /** 当前正在处理的消息数 */
42
42
  get pendingMessages(): number;
43
43
  /**
44
- * 构造函数
44
+ * 创建一个适配器运行实例。
45
+ * @param plugin 拥有该适配器的插件实例
45
46
  * @param name 适配器名称(如 'process'、'qq' 等)
46
- * @param endpointFactory Bot工厂函数或构造器
47
+ * @param config Endpoint 配置列表
47
48
  */
48
49
  constructor(plugin: Plugin, name: keyof Plugin.Contexts, config: Adapter.EndpointConfig<R>[]);
49
50
  /** 入站消息管线(替代 emit override 的隐式管线) */
package/lib/adapter.js CHANGED
@@ -55,9 +55,10 @@ export class Adapter extends EventEmitter {
55
55
  return this.#pendingMessages;
56
56
  }
57
57
  /**
58
- * 构造函数
58
+ * 创建一个适配器运行实例。
59
+ * @param plugin 拥有该适配器的插件实例
59
60
  * @param name 适配器名称(如 'process'、'qq' 等)
60
- * @param endpointFactory Bot工厂函数或构造器
61
+ * @param config Endpoint 配置列表
61
62
  */
62
63
  constructor(plugin, name, config) {
63
64
  super();
@@ -80,7 +80,7 @@ export type AITriggerMatcher = (message: Message<any>) => {
80
80
  */
81
81
  export type GroupPassiveContextHandler = (message: Message<any>) => MaybePromise<void>;
82
82
  export type GuardrailMiddleware = MessageMiddleware<RegisteredAdapter>;
83
- /** @alias OutboundReplySource:出站回复来源(指令 / AI */
83
+ /** Backward-compatible name for the command or AI outbound reply source. */
84
84
  export type ReplySource = OutboundReplySource;
85
85
  /** replyWithPolish 可选参数 */
86
86
  export interface ReplyWithPolishOptions {
@@ -1,10 +1,52 @@
1
1
  /** Authoring API for Handler Feature — implementation in `@zhin.js/handler`. */
2
- export { defineHandler, parseHandlerDefinition, HandlerIndex, isHandlerIndex, handlerFeatureId, handlerFeature, handlerEventFromLocalName, resolveHandlerEvent, type HandlerEventMap, type HandlerDefinition, type HandlerDescriptor, type HandlerContext, type HandlerDispatchOptions, } from '@zhin.js/handler';
2
+ export { parseHandlerDefinition, HandlerIndex, isHandlerIndex, handlerFeatureId, handlerFeature, handlerEventFromLocalName, resolveHandlerEvent, type HandlerEventMap, type HandlerDefinition, type HandlerDescriptor, type HandlerContext, type HandlerDispatchOptions, } from '@zhin.js/handler';
3
+ import { type HandlerContext, type HandlerDefinition, type HandlerEventMap } from '@zhin.js/handler';
3
4
  import type { Plugin } from '../plugin.js';
5
+ import type { Message } from '../plugin-runtime/im/contracts.js';
6
+ import type { Notice } from '../notice.js';
7
+ import type { Request } from '../request.js';
8
+ import type { SystemEvent } from '../system-event.js';
9
+ import type { AdapterClient, AdapterEvents, EndpointEvent, EndpointIdentity, PlatformEvent, RegisteredAdapterName } from '@zhin.js/adapter';
4
10
  type KnownKeys<T> = {
5
11
  [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
6
12
  };
7
13
  declare module '@zhin.js/handler' {
8
- interface HandlerEventMap extends KnownKeys<Plugin.Lifecycle> {
14
+ interface HandlerEventMap extends KnownKeys<Omit<Plugin.Lifecycle, 'message.receive' | 'notice.receive' | 'request.receive' | 'system.receive'>> {
15
+ 'message.receive': [event: EndpointEvent<Message>];
16
+ 'notice.receive': [event: EndpointEvent<Notice>];
17
+ 'request.receive': [event: EndpointEvent<Request>];
18
+ 'system.receive': [event: EndpointEvent<SystemEvent>];
19
+ 'platform.receive': [event: EndpointEvent<PlatformEvent>];
9
20
  }
10
21
  }
22
+ type NativeEventName<TAdapter extends RegisteredAdapterName> = Extract<keyof AdapterEvents<TAdapter>, string>;
23
+ /** Fully inferred native platform event exposed to plugin handlers. */
24
+ export interface ClientHandlerEvent<TAdapter extends RegisteredAdapterName, TName extends NativeEventName<TAdapter> = NativeEventName<TAdapter>> {
25
+ readonly name: TName;
26
+ readonly event: AdapterEvents<TAdapter>[TName];
27
+ readonly endpoint: EndpointIdentity;
28
+ readonly client: AdapterClient<TAdapter>;
29
+ }
30
+ export interface ClientHandlerOptions<TAdapter extends RegisteredAdapterName, TName extends NativeEventName<TAdapter>> {
31
+ readonly adapter: TAdapter;
32
+ readonly event: TName;
33
+ handle(this: HandlerContext, event: ClientHandlerEvent<TAdapter, TName>): void | Promise<void>;
34
+ }
35
+ export interface ClientHandlerWildcardEvent<TAdapter extends RegisteredAdapterName> {
36
+ readonly name: string;
37
+ readonly event: unknown;
38
+ readonly endpoint: EndpointIdentity;
39
+ readonly client: AdapterClient<TAdapter>;
40
+ }
41
+ export interface ClientHandlerWildcardOptions<TAdapter extends RegisteredAdapterName> {
42
+ readonly adapter: TAdapter;
43
+ readonly event: '*';
44
+ handle(this: HandlerContext, event: ClientHandlerWildcardEvent<TAdapter>): void | Promise<void>;
45
+ }
46
+ export declare function defineHandler<TAdapter extends RegisteredAdapterName, TName extends NativeEventName<TAdapter>>(options: ClientHandlerOptions<TAdapter, TName>): Readonly<HandlerDefinition<'platform.receive'>>;
47
+ /** Handle every native event from one Client without pretending unknown payloads are typed. */
48
+ export declare function defineHandler<TAdapter extends RegisteredAdapterName>(options: ClientHandlerWildcardOptions<TAdapter>): Readonly<HandlerDefinition<'platform.receive'>>;
49
+ export declare function defineHandler<K extends keyof HandlerEventMap & string>(options: {
50
+ readonly event: K;
51
+ handle(this: HandlerContext, ...args: HandlerEventMap[K] extends unknown[] ? HandlerEventMap[K] : unknown[]): void | Promise<void>;
52
+ }): Readonly<HandlerDefinition<K>>;
@@ -1,2 +1,26 @@
1
1
  /** Authoring API for Handler Feature — implementation in `@zhin.js/handler`. */
2
- export { defineHandler, parseHandlerDefinition, HandlerIndex, isHandlerIndex, handlerFeatureId, handlerFeature, handlerEventFromLocalName, resolveHandlerEvent, } from '@zhin.js/handler';
2
+ export { parseHandlerDefinition, HandlerIndex, isHandlerIndex, handlerFeatureId, handlerFeature, handlerEventFromLocalName, resolveHandlerEvent, } from '@zhin.js/handler';
3
+ import { defineHandler as defineHandlerFeature, } from '@zhin.js/handler';
4
+ export function defineHandler(options) {
5
+ if (!('adapter' in options) || typeof options.adapter !== 'string') {
6
+ return defineHandlerFeature(options);
7
+ }
8
+ const adapter = options.adapter;
9
+ const expectedName = options.event === '*' ? undefined : options.event;
10
+ return defineHandlerFeature({
11
+ event: 'platform.receive',
12
+ async handle(source) {
13
+ if (source.endpoint.adapter !== adapter)
14
+ return;
15
+ if (expectedName !== undefined && source.payload.name !== expectedName)
16
+ return;
17
+ const event = Object.freeze({
18
+ name: source.payload.name,
19
+ event: source.payload.event,
20
+ endpoint: source.endpoint,
21
+ client: source.client,
22
+ });
23
+ await options.handle.call(this, event);
24
+ },
25
+ });
26
+ }
package/lib/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Canonical IM messages, Endpoints, rendering, and plugin-facing core types.
3
+ * @module @zhin.js/core
4
+ */
1
5
  export * from './endpoint.js';
2
6
  export * from './endpoint-capabilities.js';
3
7
  export * from './plugin.js';
@@ -13,7 +17,6 @@ export * from './side-event/index.js';
13
17
  export * from './schema-interaction.js';
14
18
  export type * from '@zhin.js/interaction';
15
19
  export * from './types.js';
16
- export * from './agent-prompt.js';
17
20
  export * from './utils.js';
18
21
  export * from './errors.js';
19
22
  export * from './built/config.js';
package/lib/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Canonical IM messages, Endpoints, rendering, and plugin-facing core types.
3
+ * @module @zhin.js/core
4
+ */
1
5
  // ── Core 类模块 ──────────────────────────────────────────────────────
2
6
  export * from './endpoint.js';
3
7
  export * from './endpoint-capabilities.js';
@@ -13,7 +17,6 @@ export * from './system-event.js';
13
17
  export * from './side-event/index.js';
14
18
  export * from './schema-interaction.js';
15
19
  export * from './types.js';
16
- export * from './agent-prompt.js';
17
20
  export * from './utils.js';
18
21
  export * from './errors.js';
19
22
  // ── Built 模块 ──────────────────────────────────────────────────────
package/lib/message.d.ts CHANGED
@@ -49,6 +49,7 @@ export interface MessageBase {
49
49
  * 完整消息类型,支持扩展
50
50
  */
51
51
  export type Message<T extends object = {}> = MessageBase & T;
52
+ /** @internal Legacy static helpers; not part of Agent resource authoring. */
52
53
  export declare namespace Message {
53
54
  /**
54
55
  * 工具方法:合并自定义字段与基础消息结构
package/lib/message.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isActionMessage as isActionMessageImpl } from "./built/interactive-segments/action.js";
2
+ /** @internal Legacy static helpers; not part of Agent resource authoring. */
2
3
  export var Message;
3
4
  (function (Message) {
4
5
  /**
@@ -81,10 +81,14 @@ export interface OutboundEnvelope {
81
81
  readonly requester: PluginId;
82
82
  readonly generation: number;
83
83
  readonly payload: unknown;
84
+ /** Native platform Client for the Endpoint selected by `conversation`. */
85
+ readonly $client: unknown;
86
+ /** Literal adapter name used to validate adapter-bound middleware. */
87
+ readonly clientAdapter?: string;
84
88
  replace(payload: unknown): void;
85
89
  }
86
- export interface MessageGateway {
87
- receive(input: IncomingMessage): Promise<MessageDispatchResult>;
90
+ /** @public Stable IM gateway contract resolved through `outboundMessageToken`. */
91
+ export interface OutboundMessageService {
88
92
  send(request: SendRequest): Promise<DeliveryReceipt>;
89
93
  /**
90
94
  * 注册 interactive action 回跳 handler(prefix 最长匹配;返回注销函数)。
@@ -100,6 +104,7 @@ export interface MessageDispatchResult {
100
104
  readonly value?: unknown;
101
105
  }
102
106
  export declare class Message {
107
+ #private;
103
108
  readonly conversation: ConversationRef;
104
109
  readonly content: string;
105
110
  readonly generation: number;
@@ -117,6 +122,8 @@ export declare class Message {
117
122
  readonly replyTo?: {
118
123
  readonly id: string;
119
124
  } | undefined;
125
+ readonly clientAdapter?: string | undefined;
126
+ /** @internal Constructed only by the generation-owned IM Runtime. */
120
127
  constructor(conversation: ConversationRef, content: string, generation: number, reply: (content: SendContent, requester?: PluginId, targetConversation?: ConversationAddress) => Promise<DeliveryReceipt>, sender?: MessageSenderRef | undefined, metadata?: Readonly<Record<string, unknown>>,
121
128
  /**
122
129
  * 结构化段视图(与 `content` 纯文本视图同源,见 IncomingMessage.segments)。
@@ -126,10 +133,15 @@ export declare class Message {
126
133
  /** 结构化入站消息身份(平台原生 message id 经 MessageRef 传递)。 */
127
134
  message?: MessageRef | undefined, endpointId?: string | undefined, mentioned?: boolean | undefined, replyTo?: {
128
135
  readonly id: string;
129
- } | undefined);
136
+ } | undefined, client?: () => unknown, clientAdapter?: string | undefined);
130
137
  /** 平台原生消息 id(`message` 未提供时为 undefined)。 */
131
138
  get id(): string | undefined;
132
139
  readonly $reply: (content: SendContent) => Promise<DeliveryReceipt>;
140
+ /**
141
+ * Platform-native Client that received this message. The getter is
142
+ * generation-scoped; retaining the returned Client after dispatch is invalid.
143
+ */
144
+ get $client(): unknown;
133
145
  readonly $replyFrom: (requester: PluginId, content: SendContent) => Promise<DeliveryReceipt>;
134
146
  /**
135
147
  * 向同 Endpoint 的另一个通道发送消息(通用)。
@@ -176,4 +188,4 @@ export declare class Message {
176
188
  */
177
189
  readonly $replyToChannel: (channelId: string, guildId: string, content: SendContent, threadId?: string) => Promise<DeliveryReceipt>;
178
190
  }
179
- export declare function createOutboundEnvelope(request: Omit<OutboundEnvelope, 'payload' | 'replace'>, initialPayload: unknown): OutboundEnvelope;
191
+ export declare function createOutboundEnvelope(request: Omit<OutboundEnvelope, 'payload' | '$client' | 'replace'>, initialPayload: unknown, resolveClient?: () => unknown): OutboundEnvelope;
@@ -43,6 +43,9 @@ export class Message {
43
43
  endpointId;
44
44
  mentioned;
45
45
  replyTo;
46
+ clientAdapter;
47
+ #resolveClient;
48
+ /** @internal Constructed only by the generation-owned IM Runtime. */
46
49
  constructor(conversation, content, generation, reply, sender, metadata = Object.freeze({}),
47
50
  /**
48
51
  * 结构化段视图(与 `content` 纯文本视图同源,见 IncomingMessage.segments)。
@@ -50,7 +53,9 @@ export class Message {
50
53
  */
51
54
  segments,
52
55
  /** 结构化入站消息身份(平台原生 message id 经 MessageRef 传递)。 */
53
- message, endpointId, mentioned, replyTo) {
56
+ message, endpointId, mentioned, replyTo, client = () => {
57
+ throw new Error('Message has no Endpoint Client context');
58
+ }, clientAdapter) {
54
59
  this.conversation = conversation;
55
60
  this.content = content;
56
61
  this.generation = generation;
@@ -61,6 +66,8 @@ export class Message {
61
66
  this.endpointId = endpointId;
62
67
  this.mentioned = mentioned;
63
68
  this.replyTo = replyTo;
69
+ this.clientAdapter = clientAdapter;
70
+ this.#resolveClient = client;
64
71
  this.$reply = (content) => reply(content);
65
72
  this.$replyFrom = (requester, content) => reply(content, requester);
66
73
  this.$sendTo = (target, content) => reply(content, undefined, target);
@@ -101,6 +108,13 @@ export class Message {
101
108
  return this.message?.id;
102
109
  }
103
110
  $reply;
111
+ /**
112
+ * Platform-native Client that received this message. The getter is
113
+ * generation-scoped; retaining the returned Client after dispatch is invalid.
114
+ */
115
+ get $client() {
116
+ return this.#resolveClient();
117
+ }
104
118
  $replyFrom;
105
119
  /**
106
120
  * 向同 Endpoint 的另一个通道发送消息(通用)。
@@ -144,11 +158,12 @@ export class Message {
144
158
  */
145
159
  $replyToChannel;
146
160
  }
147
- export function createOutboundEnvelope(request, initialPayload) {
161
+ export function createOutboundEnvelope(request, initialPayload, resolveClient = () => undefined) {
148
162
  let payload = initialPayload;
149
163
  return Object.freeze({
150
164
  ...request,
151
165
  get payload() { return payload; },
166
+ get $client() { return resolveClient(); },
152
167
  replace(next) { payload = next; },
153
168
  });
154
169
  }
@@ -1,19 +1,19 @@
1
1
  import { Scope, generationAdmissionBinder, type GenerationAdmissionGate, type PluginId, type RuntimeSnapshot, type SnapshotLease, type SnapshotReader } from '@zhin.js/plugin-runtime';
2
2
  import { MessageBus } from './message-bus.js';
3
- import { type AdapterOperation, type EndpointManagement, type EndpointManagementCapability, type AdapterEndpointPhase, type EndpointContentResolveContext } from '@zhin.js/adapter';
4
- import { type ConversationEventStore, type ConversationContextBlock, type ConversationReference, type ConversationResolution, type ConversationRef, type DeliveryReceipt, type MessageRef } from '@zhin.js/im-contract';
5
- import { Message, type ConversationAddress, type IncomingMessage, type MessageDispatchResult, type MessageGateway, type MessageSenderRef, type SendRequest } from './contracts.js';
3
+ import { type AdapterOperation, type EndpointManagement, type EndpointManagementCapability, type AdapterEndpointPhase, type EndpointContentResolveContext, type EndpointEvent, type EndpointEventGateway } from '@zhin.js/adapter';
4
+ import { type ConversationEventStore, type ConversationContextBlock, type ConversationReference, type ConversationResolution, type ConversationRef, type DeliveryReceipt, type EndpointCapabilities, type MessageRef } from '@zhin.js/im-contract';
5
+ import { Message, type ConversationAddress, type IncomingMessage, type OutboundMessageService, type MessageSenderRef, type SendRequest } from './contracts.js';
6
6
  import { LoginAssist } from '../../built/login-assist.js';
7
- import type { Notice } from '../../notice.js';
8
- import type { Request } from '../../request.js';
9
- import type { SystemEvent } from '../../system-event.js';
10
7
  import type { UserInteraction } from '@zhin.js/interaction';
11
8
  import { OutboundRenderer } from './outbound-renderer.js';
12
9
  import { type RuntimeInteractiveHandler } from './interactive.js';
13
- export declare const messageGatewayToken: import("@zhin.js/plugin-runtime").Token<MessageGateway>;
10
+ /** @public Stable inbound and outbound IM gateway token for Adapter integrations. */
11
+ export declare const outboundMessageToken: import("@zhin.js/plugin-runtime").Token<OutboundMessageService>;
14
12
  /** Generation-owned ingress hooks before ordinary dispatch and after it misses. */
15
13
  export interface IngressRoute {
16
14
  preRoute?(message: Message, lease: SnapshotLease, requester: PluginId, conversationSequence: number | undefined): Promise<boolean>;
15
+ /** A live pre-route handoff that must run before handlers and commands. */
16
+ shouldRouteBeforeDispatch?(message: Message): boolean;
17
17
  route(message: Message, lease: SnapshotLease, requester: PluginId, conversationSequence: number | undefined): Promise<boolean>;
18
18
  }
19
19
  export declare const ingressRouteToken: import("@zhin.js/plugin-runtime").Token<IngressRoute>;
@@ -49,12 +49,14 @@ export interface ImRuntimeOptions {
49
49
  */
50
50
  readonly enrichSender?: (sender: MessageSenderRef | undefined, conversation: IncomingMessage['conversation'], snapshot: RuntimeSnapshot) => MessageSenderRef | undefined;
51
51
  }
52
- export declare class ImRuntime implements MessageGateway {
52
+ export declare class ImRuntime implements OutboundMessageService {
53
53
  #private;
54
54
  conversationEvents: ConversationEventStore;
55
55
  constructor(options?: ImRuntimeOptions);
56
56
  /** Process composition replaces the bootstrap memory store after required DB activation. */
57
57
  replaceConversationEventStore(store: ConversationEventStore): void;
58
+ /** Pins all nested IM operations to the snapshot current at operation ingress. */
59
+ runWithSnapshotView<T>(operation: () => Promise<T>): Promise<T>;
58
60
  resolveConversationReference(lease: SnapshotLease, reference: ConversationReference, context: EndpointContentResolveContext): Promise<ConversationResolution>;
59
61
  readConversationContext(conversation: ConversationRef, consumer: string, throughSequence: number, limit?: number, excludeMessageId?: string): Promise<Readonly<{
60
62
  blocks: readonly ConversationContextBlock[];
@@ -66,7 +68,11 @@ export declare class ImRuntime implements MessageGateway {
66
68
  readonly messageBus: MessageBus;
67
69
  readonly loginAssist: LoginAssist;
68
70
  install(resources: Scope): void;
69
- [generationAdmissionBinder](gate: GenerationAdmissionGate): MessageGateway;
71
+ /** The sole Adapter ingress, also installed as endpointEventGatewayToken. */
72
+ readonly endpointEvents: EndpointEventGateway & {
73
+ [generationAdmissionBinder](gate: GenerationAdmissionGate): EndpointEventGateway;
74
+ };
75
+ [generationAdmissionBinder](gate: GenerationAdmissionGate): OutboundMessageService;
70
76
  /**
71
77
  * 注册 interactive action 回跳 handler(prefix 最长匹配;返回注销函数)。
72
78
  * 在 Command dispatch 之前路由:action 段 / 数字回跳 / 指令预填 payload。
@@ -84,11 +90,10 @@ export declare class ImRuntime implements MessageGateway {
84
90
  * 返回注销函数。listener 抛错不会阻断消息链路。
85
91
  */
86
92
  onMessage(listener: (event: RuntimeMessageEvent) => void): () => void;
87
- receive(input: IncomingMessage): Promise<MessageDispatchResult>;
88
93
  send(request: SendRequest): Promise<DeliveryReceipt>;
89
- receiveNotice(notice: Notice): Promise<void>;
90
- receiveRequest(request: Request): Promise<void>;
91
- receiveSystem(event: SystemEvent): Promise<void>;
94
+ /** Sends through the exact generation lease that admitted the current operation. */
95
+ sendWithSnapshotLease(lease: SnapshotLease, request: SendRequest): Promise<DeliveryReceipt>;
96
+ receiveEndpointEvent(event: EndpointEvent, admission?: GenerationAdmissionGate): Promise<unknown>;
92
97
  /** Console `endpoint.list` — empty until Adapter Feature projection is ready. */
93
98
  listEndpoints(): readonly {
94
99
  readonly id: string;
@@ -101,6 +106,11 @@ export declare class ImRuntime implements MessageGateway {
101
106
  readonly operations: readonly AdapterOperation[];
102
107
  readonly managementCapabilities: readonly EndpointManagementCapability[];
103
108
  }[];
109
+ /** Exact operation capabilities for one concrete live Endpoint. */
110
+ endpointCapabilities(input: {
111
+ readonly adapter: string;
112
+ readonly endpointKey: string;
113
+ }): EndpointCapabilities | undefined;
104
114
  /**
105
115
  * Console `GET /api/stats` 同源计数:非 root 插件节点 + AdapterIndex endpoints。
106
116
  * 供命令 / 状态卡等在 Plugin Runtime 下读取(legacy `root.adapters` / `root.children` 已不存在)。
@@ -1,14 +1,14 @@
1
1
  import { createToken, generationAdmissionBinder, htmlRendererToken, } from '@zhin.js/plugin-runtime';
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
3
  import { createPermissionHost, permissionHostToken } from '@zhin.js/permission';
3
4
  import { MessageBus, messageBusToken } from './message-bus.js';
4
- import { adapterFeatureId, isAdapterIndex, resolveEndpointManagement, } from '@zhin.js/adapter';
5
+ import { adapterFeatureId, isAdapterIndex, resolveEndpointManagement, endpointEventGatewayToken, } from '@zhin.js/adapter';
5
6
  import { MemoryConversationEventStore, conversationRefKey, messageRefKey, } from '@zhin.js/im-contract';
6
7
  import { segmentsToPlainText } from '../../built/segment-contract/text.js';
7
8
  import { isMiddlewareIndex, middlewareFeatureId } from '@zhin.js/middleware';
8
9
  import { isHandlerIndex, handlerFeatureId } from '../../feature/handler.js';
9
10
  import { formatCompact, getLogger, truncatePreview } from '@zhin.js/logger';
10
11
  import { Message, createOutboundEnvelope, } from './contracts.js';
11
- import { sideEventGatewayToken, } from './side-event-gateway.js';
12
12
  import { loginAssistToken } from './login-assist-host.js';
13
13
  import { LoginAssist } from '../../built/login-assist.js';
14
14
  import { sideEventSendChannel } from '../../side-event/base.js';
@@ -20,7 +20,8 @@ import { keyboardFallbackStore } from '../../built/interactive-segments/fallback
20
20
  import { assertUserInteractionRequest, parseUserInteractionAnswer, projectUserInteraction, renderUserInteraction, } from '../../built/user-interaction.js';
21
21
  import { findRuntimeInteractiveHandler, resolveRuntimeInteractivePayload, runtimeInteractiveConversationKey, } from './interactive.js';
22
22
  const logger = getLogger('im');
23
- export const messageGatewayToken = createToken('zhin.im.message-gateway');
23
+ /** @public Stable inbound and outbound IM gateway token for Adapter integrations. */
24
+ export const outboundMessageToken = createToken('zhin.im.outbound-message');
24
25
  export const ingressRouteToken = createToken('zhin.im.ingress-route');
25
26
  export const messagePreviewLimit = 200;
26
27
  class UserInteractionTimeoutError extends Error {
@@ -47,6 +48,7 @@ export class ImRuntime {
47
48
  #messageListeners = new Set();
48
49
  #interactiveHandlers = [];
49
50
  #interactionClaims = new Map();
51
+ #operationSnapshot = new AsyncLocalStorage();
50
52
  #snapshots;
51
53
  #inboundClaim;
52
54
  #enrichSender;
@@ -64,6 +66,21 @@ export class ImRuntime {
64
66
  replaceConversationEventStore(store) {
65
67
  this.conversationEvents = store;
66
68
  }
69
+ /** Pins all nested IM operations to the snapshot current at operation ingress. */
70
+ async runWithSnapshotView(operation) {
71
+ const inherited = this.#operationSnapshot.getStore();
72
+ if (inherited?.active)
73
+ return operation();
74
+ if (!this.#snapshots)
75
+ throw new Error('ImRuntime is not attached to a Root');
76
+ const lease = this.#snapshots.acquire();
77
+ try {
78
+ return await this.#operationSnapshot.run(lease, operation);
79
+ }
80
+ finally {
81
+ lease.release();
82
+ }
83
+ }
67
84
  async resolveConversationReference(lease, reference, context) {
68
85
  if (!this.#snapshots?.owns(lease) || !lease.active) {
69
86
  return Object.freeze({ status: 'expired', code: 'generation_lease_expired' });
@@ -102,29 +119,20 @@ export class ImRuntime {
102
119
  messageBus = new MessageBus();
103
120
  loginAssist = new LoginAssist();
104
121
  install(resources) {
105
- resources.provide(messageGatewayToken, this);
106
- resources.provide(sideEventGatewayToken, this.#sideEventGateway);
122
+ resources.provide(outboundMessageToken, this);
123
+ resources.provide(endpointEventGatewayToken, this.endpointEvents);
107
124
  resources.provide(loginAssistToken, this.loginAssist);
108
125
  resources.provide(permissionHostToken, this.permissionHost);
109
126
  resources.provide(messageBusToken, this.messageBus);
110
127
  }
111
- #sideEventGateway = (() => {
128
+ /** The sole Adapter ingress, also installed as endpointEventGatewayToken. */
129
+ endpointEvents = (() => {
112
130
  const self = this;
113
131
  const gateway = {
114
- receiveNotice: (notice) => self.receiveNotice(notice),
115
- receiveRequest: (request) => self.receiveRequest(request),
116
- receiveSystem: (event) => self.receiveSystem(event),
132
+ receive: (event) => self.receiveEndpointEvent(event),
117
133
  [generationAdmissionBinder](gate) {
118
134
  return Object.freeze({
119
- receiveNotice: async (notice) => {
120
- await gate.enter(() => self.receiveNotice(notice));
121
- },
122
- receiveRequest: async (request) => {
123
- await gate.enter(() => self.receiveRequest(request));
124
- },
125
- receiveSystem: async (event) => {
126
- await gate.enter(() => self.receiveSystem(event));
127
- },
135
+ receive: async (event) => gate.enter(() => self.receiveEndpointEvent(event, gate)),
128
136
  });
129
137
  },
130
138
  };
@@ -132,8 +140,6 @@ export class ImRuntime {
132
140
  })();
133
141
  [generationAdmissionBinder](gate) {
134
142
  const gateway = {
135
- receive: async (input) => gate.enter(() => this.#receive(input, gate))
136
- ?? Object.freeze({ matched: false }),
137
143
  send: async (request) => gate.enter(() => this.send(request))
138
144
  ?? failedReceipt('generation_not_admitted'),
139
145
  registerInteractiveHandler: (prefix, handler) => this.#registerInteractiveHandler(prefix, handler, gate),
@@ -315,10 +321,8 @@ export class ImRuntime {
315
321
  }
316
322
  }
317
323
  }
318
- async receive(input) {
319
- return this.#receive(input);
320
- }
321
- async #receive(input, admission) {
324
+ async #receive(source, admission) {
325
+ const input = source.payload;
322
326
  const lease = this.#acquire();
323
327
  let active = true;
324
328
  try {
@@ -354,7 +358,11 @@ export class ImRuntime {
354
358
  mentioned: input.mentioned,
355
359
  },
356
360
  }, lease.value);
357
- }, enrichedSender, Object.freeze({ ...input.metadata }), input.segments ? Object.freeze([...input.segments]) : undefined, input.message, input.endpointId, input.mentioned, input.replyTo);
361
+ }, enrichedSender, Object.freeze({ ...input.metadata }), input.segments ? Object.freeze([...input.segments]) : undefined, input.message, input.endpointId, input.mentioned, input.replyTo, () => {
362
+ if (!active)
363
+ throw new Error('Message Client scope has ended');
364
+ return source.client;
365
+ }, source.endpoint.adapter);
358
366
  let conversationSequence;
359
367
  if (input.message?.id) {
360
368
  const appended = await this.conversationEvents.append(Object.freeze({
@@ -394,7 +402,16 @@ export class ImRuntime {
394
402
  result = Object.freeze({ matched: true, command: 'pre-route', owner: requester });
395
403
  return;
396
404
  }
397
- await this.#runHandlers(lease.value, 'message.receive', [message]);
405
+ if (ingressRoute?.shouldRouteBeforeDispatch?.(message) === true) {
406
+ const handled = await ingressRoute.route(message, lease, requester, conversationSequence);
407
+ if (handled) {
408
+ result = Object.freeze({ matched: true, command: 'ai', owner: requester });
409
+ return;
410
+ }
411
+ }
412
+ await this.#runHandlers(lease.value, 'message.receive', [
413
+ withEndpointEventPayload(source, message),
414
+ ]);
398
415
  result = await this.#dispatchInteractive(message, requester, admission)
399
416
  ?? await this.#dispatcher.dispatch(message, lease.value, interactionFactory);
400
417
  if (!result.matched && ingressRoute) {
@@ -425,7 +442,7 @@ export class ImRuntime {
425
442
  }
426
443
  finally {
427
444
  active = false;
428
- lease.release();
445
+ this.#release(lease);
429
446
  }
430
447
  }
431
448
  async send(request) {
@@ -434,18 +451,26 @@ export class ImRuntime {
434
451
  return await this.#sendWithSnapshot(request, lease.value);
435
452
  }
436
453
  finally {
437
- lease.release();
454
+ this.#release(lease);
438
455
  }
439
456
  }
440
- async receiveNotice(notice) {
457
+ /** Sends through the exact generation lease that admitted the current operation. */
458
+ async sendWithSnapshotLease(lease, request) {
459
+ if (!this.#snapshots?.owns(lease) || !lease.active) {
460
+ throw new Error('Outbound message generation lease expired');
461
+ }
462
+ return this.#sendWithSnapshot(request, lease.value);
463
+ }
464
+ async #receiveNotice(source) {
465
+ const notice = source.payload;
441
466
  const event = conversationEventFromNotice(notice);
442
467
  if (event)
443
468
  await this.conversationEvents.append(event);
444
- await this.#receiveSideEvent('notice.receive', notice);
469
+ await this.#receiveSideEvent(withEndpointEventPayload(source, notice));
445
470
  }
446
- async receiveRequest(request) {
447
- await this.#withRequestActionScope(request, async (scoped) => {
448
- await this.#receiveSideEvent('request.receive', scoped);
471
+ async #receiveRequest(source) {
472
+ await this.#withRequestActionScope(source.payload, async (scoped) => {
473
+ await this.#receiveSideEvent(withEndpointEventPayload(source, scoped));
449
474
  });
450
475
  }
451
476
  async #withRequestActionScope(request, dispatch) {
@@ -471,16 +496,38 @@ export class ImRuntime {
471
496
  await Promise.allSettled([...actions]);
472
497
  }
473
498
  }
474
- async receiveSystem(event) {
475
- await this.#receiveSideEvent('system.receive', event);
499
+ async #receiveSystem(source) {
500
+ await this.#receiveSideEvent(source);
476
501
  }
477
- async #receiveSideEvent(event, payload) {
502
+ async #receiveSideEvent(event) {
478
503
  const lease = this.#acquire();
479
504
  try {
480
- await this.#runHandlers(lease.value, event, [payload]);
505
+ await this.#runHandlers(lease.value, event.name, [event]);
481
506
  }
482
507
  finally {
483
- lease.release();
508
+ this.#release(lease);
509
+ }
510
+ }
511
+ async receiveEndpointEvent(event, admission) {
512
+ switch (event.name) {
513
+ case 'message.receive':
514
+ return this.#receive(event, admission);
515
+ case 'notice.receive':
516
+ return this.#receiveNotice(event);
517
+ case 'request.receive':
518
+ return this.#receiveRequest(event);
519
+ case 'system.receive':
520
+ return this.#receiveSystem(event);
521
+ default: {
522
+ const lease = this.#acquire();
523
+ try {
524
+ await this.#runHandlers(lease.value, event.name, [event]);
525
+ return undefined;
526
+ }
527
+ finally {
528
+ this.#release(lease);
529
+ }
530
+ }
484
531
  }
485
532
  }
486
533
  /**
@@ -518,7 +565,8 @@ export class ImRuntime {
518
565
  return;
519
566
  const options = {
520
567
  resolveInteraction: (name, interactionArgs) => {
521
- const payload = interactionArgs[0];
568
+ const context = interactionArgs[0];
569
+ const payload = context?.payload;
522
570
  if (name === 'message.receive' && payload instanceof Message) {
523
571
  return this.createInteraction(payload);
524
572
  }
@@ -551,13 +599,30 @@ export class ImRuntime {
551
599
  }));
552
600
  }
553
601
  finally {
554
- lease.release();
602
+ this.#release(lease);
555
603
  }
556
604
  }
557
605
  catch {
558
606
  return Object.freeze([]);
559
607
  }
560
608
  }
609
+ /** Exact operation capabilities for one concrete live Endpoint. */
610
+ endpointCapabilities(input) {
611
+ try {
612
+ const lease = this.#acquire();
613
+ try {
614
+ const index = requireAdapters(lease.value);
615
+ const id = index.resolve(input.adapter, input.endpointKey);
616
+ return id ? index.capabilities(id) : undefined;
617
+ }
618
+ finally {
619
+ this.#release(lease);
620
+ }
621
+ }
622
+ catch {
623
+ return undefined;
624
+ }
625
+ }
561
626
  /**
562
627
  * Console `GET /api/stats` 同源计数:非 root 插件节点 + AdapterIndex endpoints。
563
628
  * 供命令 / 状态卡等在 Plugin Runtime 下读取(legacy `root.adapters` / `root.children` 已不存在)。
@@ -578,7 +643,7 @@ export class ImRuntime {
578
643
  });
579
644
  }
580
645
  finally {
581
- lease.release();
646
+ this.#release(lease);
582
647
  }
583
648
  }
584
649
  catch {
@@ -612,7 +677,7 @@ export class ImRuntime {
612
677
  });
613
678
  }
614
679
  finally {
615
- lease.release();
680
+ this.#release(lease);
616
681
  }
617
682
  }
618
683
  catch {
@@ -640,7 +705,7 @@ export class ImRuntime {
640
705
  return { messageId: result.message?.id ?? '' };
641
706
  }
642
707
  finally {
643
- lease.release();
708
+ this.#release(lease);
644
709
  }
645
710
  }
646
711
  /** Activity-feedback: add a message reaction when the live Endpoint supports it. */
@@ -678,7 +743,7 @@ export class ImRuntime {
678
743
  return control ? await run(control) : fallback;
679
744
  }
680
745
  finally {
681
- lease.release();
746
+ this.#release(lease);
682
747
  }
683
748
  }
684
749
  /** Run one management operation while the Endpoint generation stays leased. */
@@ -691,13 +756,13 @@ export class ImRuntime {
691
756
  return null;
692
757
  }
693
758
  try {
694
- const endpoint = requireAdapters(lease.value).instance(adapter, endpointKey);
759
+ const endpoint = requireAdapters(lease.value).connection(adapter, endpointKey);
695
760
  if (!endpoint)
696
761
  return null;
697
762
  return await run(resolveEndpointManagement(endpoint) ?? Object.freeze({}));
698
763
  }
699
764
  finally {
700
- lease.release();
765
+ this.#release(lease);
701
766
  }
702
767
  }
703
768
  async #sendWithSnapshot(request, snapshot) {
@@ -710,11 +775,19 @@ export class ImRuntime {
710
775
  catch {
711
776
  return rejectedReceipt('outbound_payload_rejected');
712
777
  }
778
+ let adapters;
779
+ try {
780
+ adapters = requireAdapters(snapshot);
781
+ }
782
+ catch (error) {
783
+ return receiptFromEndpointError(error);
784
+ }
713
785
  const envelope = createOutboundEnvelope({
714
786
  conversation: request.conversation,
715
787
  requester: request.requester,
716
788
  generation: snapshot.generation,
717
- }, initialPayload);
789
+ clientAdapter: adapters.clientAdapter(adapter),
790
+ }, initialPayload, () => adapters.clientById(adapter));
718
791
  let terminalEntered = false;
719
792
  let receipt;
720
793
  try {
@@ -787,10 +860,18 @@ export class ImRuntime {
787
860
  return receipt ?? failedReceipt('outbound_delivery_incomplete');
788
861
  }
789
862
  #acquire() {
863
+ const inherited = this.#operationSnapshot.getStore();
864
+ if (inherited?.active)
865
+ return inherited;
790
866
  if (!this.#snapshots)
791
867
  throw new Error('ImRuntime is not attached to a Root');
792
868
  return this.#snapshots.acquire();
793
869
  }
870
+ #release(lease) {
871
+ if (this.#operationSnapshot.getStore() === lease)
872
+ return;
873
+ lease.release();
874
+ }
794
875
  /**
795
876
  * interactive 回跳分发(Command dispatch 之前):action 段 / 中央 fallback
796
877
  * 数字回跳 / 指令预填 payload → prefix 最长匹配 handler。
@@ -1113,3 +1194,11 @@ function abortError(signal, fallback) {
1113
1194
  return signal.reason;
1114
1195
  return new Error(fallback);
1115
1196
  }
1197
+ function withEndpointEventPayload(source, payload) {
1198
+ return Object.freeze({
1199
+ name: source.name,
1200
+ payload,
1201
+ endpoint: source.endpoint,
1202
+ client: source.client,
1203
+ });
1204
+ }
@@ -7,4 +7,3 @@ export * from './message-dispatcher.js';
7
7
  export * from './outbound-renderer.js';
8
8
  export * from './outbound-segments.js';
9
9
  export * from './service-tokens.js';
10
- export * from './side-event-gateway.js';
@@ -7,4 +7,3 @@ export * from './message-dispatcher.js';
7
7
  export * from './outbound-renderer.js';
8
8
  export * from './outbound-segments.js';
9
9
  export * from './service-tokens.js';
10
- export * from './side-event-gateway.js';
@@ -1,6 +1,6 @@
1
1
  import { LoginAssist } from '../../built/login-assist.js';
2
2
  /**
3
- * Plugin Runtime login-assist port(与 messageGatewayToken / sideEventGatewayToken 并列)。
3
+ * Plugin Runtime login-assist port(与出站消息服务并列)。
4
4
  * 适配器 waitForInput;Console / stdin 经 listPending + submit 消费。
5
5
  */
6
6
  export declare const loginAssistToken: import("@zhin.js/plugin-runtime").Token<LoginAssist>;
@@ -1,6 +1,6 @@
1
1
  import { createToken } from '@zhin.js/plugin-runtime';
2
2
  /**
3
- * Plugin Runtime login-assist port(与 messageGatewayToken / sideEventGatewayToken 并列)。
3
+ * Plugin Runtime login-assist port(与出站消息服务并列)。
4
4
  * 适配器 waitForInput;Console / stdin 经 listPending + submit 消费。
5
5
  */
6
6
  export const loginAssistToken = createToken('zhin.im.login-assist');
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Public IM gateway contract exposed from `zhin.js/core/runtime`.
3
+ * @module zhin.js/core/runtime
4
+ */
5
+ export { outboundMessageToken } from './im-runtime.js';
6
+ export { Message, type ComponentCall, type ConversationAddress, type IncomingContext, type IncomingMessage, type MessageDispatchResult, type OutboundMessageService, type MessageSenderRef, type OutboundEnvelope, type RawContent, type SendContent, type SendRequest, } from './contracts.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Public IM gateway contract exposed from `zhin.js/core/runtime`.
3
+ * @module zhin.js/core/runtime
4
+ */
5
+ export { outboundMessageToken } from './im-runtime.js';
6
+ export { Message, } from './contracts.js';
@@ -1,4 +1,4 @@
1
- import type { SideEventGateway } from '../plugin-runtime/im/side-event-gateway.js';
1
+ import type { EndpointEventEmitter } from '@zhin.js/adapter';
2
2
  import { type OneBotLikeRawEvent, type SideEventPlatform } from './normalize.js';
3
3
  export interface OneBotLikeSideEventInput {
4
4
  readonly adapter: string;
@@ -9,7 +9,7 @@ export interface OneBotLikeSideEventInput {
9
9
  readonly reject?: (flag: string, reason?: string) => void | Promise<void>;
10
10
  }
11
11
  /**
12
- * Normalize OneBot / icqq-style notice|request|meta payloads and forward to SideEventGateway.
12
+ * Normalize OneBot / icqq-style notice|request|meta payloads and feed Endpoint.emit().
13
13
  * Returns which kind was dispatched, or null when the payload is not a side event.
14
14
  */
15
- export declare function receiveOneBotLikeSideEvent(gateway: SideEventGateway, input: OneBotLikeSideEventInput): Promise<'notice' | 'request' | 'system' | null>;
15
+ export declare function receiveOneBotLikeSideEvent(emit: EndpointEventEmitter, input: OneBotLikeSideEventInput): Promise<'notice' | 'request' | 'system' | null>;
@@ -1,9 +1,9 @@
1
1
  import { buildNotice, buildRequest, buildSystem, mapNoticeParts, mapRequestParts, resolveSideEventDedupeKey, senderFromId, } from './normalize.js';
2
2
  /**
3
- * Normalize OneBot / icqq-style notice|request|meta payloads and forward to SideEventGateway.
3
+ * Normalize OneBot / icqq-style notice|request|meta payloads and feed Endpoint.emit().
4
4
  * Returns which kind was dispatched, or null when the payload is not a side event.
5
5
  */
6
- export async function receiveOneBotLikeSideEvent(gateway, input) {
6
+ export async function receiveOneBotLikeSideEvent(emit, input) {
7
7
  const raw = input.raw;
8
8
  const platform = input.platform ?? 'onebot';
9
9
  const postType = String(raw.post_type ?? raw.type ?? '');
@@ -47,7 +47,7 @@ export async function receiveOneBotLikeSideEvent(gateway, input) {
47
47
  ? { $role: 'admin', $enabled: String(raw.sub_type ?? '') === 'set' }
48
48
  : {}),
49
49
  });
50
- await gateway.receiveNotice(notice);
50
+ await emit('notice.receive', notice);
51
51
  return 'notice';
52
52
  }
53
53
  if (postType === 'request' || postType.startsWith('request.')) {
@@ -96,7 +96,7 @@ export async function receiveOneBotLikeSideEvent(gateway, input) {
96
96
  },
97
97
  });
98
98
  try {
99
- await gateway.receiveRequest(request);
99
+ await emit('request.receive', request);
100
100
  }
101
101
  finally {
102
102
  active = false;
@@ -127,7 +127,7 @@ export async function receiveOneBotLikeSideEvent(gateway, input) {
127
127
  $sub_type: subType ?? metaType,
128
128
  $timestamp: toMillis(raw.time),
129
129
  });
130
- await gateway.receiveSystem(system);
130
+ await emit('system.receive', system);
131
131
  return 'system';
132
132
  }
133
133
  return null;
package/lib/utils.d.ts CHANGED
@@ -70,7 +70,7 @@ export declare namespace segment {
70
70
  backgroundColor?: string;
71
71
  fileName?: string;
72
72
  }): HtmlSegment;
73
- /** @alias htmlCard */
73
+ /** Short alias for {@link htmlCard}. */
74
74
  const html: typeof htmlCard;
75
75
  /** 出站 Markdown 段(Adapter policy 决定 image/text/origin) */
76
76
  function markdown(content: string, options?: Omit<MarkdownSegment['data'], 'content'>): MarkdownSegment;
package/lib/utils.js CHANGED
@@ -98,7 +98,7 @@ export function segment(type, data) {
98
98
  return new HtmlSegment(options);
99
99
  }
100
100
  segment.htmlCard = htmlCard;
101
- /** @alias htmlCard */
101
+ /** Short alias for {@link htmlCard}. */
102
102
  segment.html = htmlCard;
103
103
  /** 出站 Markdown 段(Adapter policy 决定 image/text/origin) */
104
104
  function markdown(content, options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/core",
3
- "version": "1.5.13",
3
+ "version": "1.5.15",
4
4
  "description": "Zhin机器人核心框架",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -75,18 +75,18 @@
75
75
  "segment-matcher": "^1.0.5",
76
76
  "smol-toml": "^1.7.1",
77
77
  "yaml": "^2.9.0",
78
- "@zhin.js/adapter": "1.2.0",
79
- "@zhin.js/component": "1.0.12",
80
- "@zhin.js/command": "1.0.15",
81
- "@zhin.js/database": "1.0.79",
82
- "@zhin.js/handler": "1.0.3",
78
+ "@zhin.js/adapter": "1.2.1",
79
+ "@zhin.js/command": "1.0.16",
80
+ "@zhin.js/component": "1.0.13",
81
+ "@zhin.js/handler": "1.0.4",
82
+ "@zhin.js/database": "1.0.81",
83
83
  "@zhin.js/im-contract": "1.0.4",
84
84
  "@zhin.js/interaction": "1.0.1",
85
- "@zhin.js/kernel": "1.0.7",
86
- "@zhin.js/logger": "1.0.76",
87
- "@zhin.js/middleware": "1.0.12",
88
- "@zhin.js/plugin-runtime": "1.1.7",
89
- "@zhin.js/permission": "1.0.3",
85
+ "@zhin.js/kernel": "1.0.8",
86
+ "@zhin.js/logger": "1.0.77",
87
+ "@zhin.js/middleware": "1.0.13",
88
+ "@zhin.js/permission": "1.0.4",
89
+ "@zhin.js/plugin-runtime": "1.1.8",
90
90
  "@zhin.js/schema": "1.0.73"
91
91
  },
92
92
  "peerDependencies": {
@@ -102,7 +102,7 @@
102
102
  "@types/qrcode": "^1.5.6",
103
103
  "ajv": "8.18.0",
104
104
  "typescript": "^6.0.3",
105
- "@zhin.js/ai": "1.5.6"
105
+ "@zhin.js/ai": "1.5.7"
106
106
  },
107
107
  "repository": {
108
108
  "type": "git",
@@ -1,39 +0,0 @@
1
- /**
2
- * Agent system-prompt extension contract (per IM platform / adapter).
3
- *
4
- * Implementations live in adapter plugins; resolution runs in @zhin.js/agent.
5
- */
6
- export type AgentPromptSlot = 'orchestrator' | 'deferred_worker';
7
- /** Minimal tool shape for deferred catalog selection (no @zhin.js/ai import). */
8
- export interface DeferredToolCatalogItem {
9
- name: string;
10
- description: string;
11
- }
12
- export interface AgentPromptBuildContext {
13
- slot: AgentPromptSlot;
14
- /** Authenticated IM platform projected by the ingress adapter. */
15
- platform: string;
16
- /** Truncated user message for intent hints (~500 chars). */
17
- userMessagePreview?: string;
18
- deferred?: {
19
- goal: string;
20
- toolQuery?: string;
21
- domainStats?: string;
22
- };
23
- }
24
- export interface AgentPromptSection {
25
- /** Stable id for debug / logs (e.g. platform.icqq.orchestrator). */
26
- id: string;
27
- title?: string;
28
- body: string;
29
- /** Lower sorts earlier; default 100. */
30
- priority?: number;
31
- }
32
- export interface AgentPromptContributor {
33
- readonly platform: string;
34
- buildSections(ctx: AgentPromptBuildContext): Promise<AgentPromptSection[] | null>;
35
- /** When true, platform may supply selectDeferredTools for this task. */
36
- matchesDeferredTask?(ctx: AgentPromptBuildContext): boolean;
37
- /** Non-null replaces default TF-IDF deferred tool selection. */
38
- selectDeferredTools?(query: string, goal: string, catalog: DeferredToolCatalogItem[], maxTools: number): DeferredToolCatalogItem[] | null;
39
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Agent system-prompt extension contract (per IM platform / adapter).
3
- *
4
- * Implementations live in adapter plugins; resolution runs in @zhin.js/agent.
5
- */
6
- export {};
@@ -1,13 +0,0 @@
1
- import type { Notice } from '../../notice.js';
2
- import type { Request } from '../../request.js';
3
- import type { SystemEvent } from '../../system-event.js';
4
- /**
5
- * Plugin Runtime 侧事件入站口(与 messageGatewayToken 并列)。
6
- * 适配器归一 Notice / Request / SystemEvent 后调用,由 ImRuntime 分发给 HandlerIndex。
7
- */
8
- export interface SideEventGateway {
9
- receiveNotice(notice: Notice): Promise<void>;
10
- receiveRequest(request: Request): Promise<void>;
11
- receiveSystem(event: SystemEvent): Promise<void>;
12
- }
13
- export declare const sideEventGatewayToken: import("@zhin.js/plugin-runtime").Token<SideEventGateway>;
@@ -1,2 +0,0 @@
1
- import { createToken } from '@zhin.js/plugin-runtime';
2
- export const sideEventGatewayToken = createToken('zhin.im.side-event-gateway');