@zhin.js/adapter-lark 7.0.0 → 7.0.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @zhin.js/adapter-lark
2
2
 
3
+ ## 7.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [736fa04]
8
+ - @zhin.js/agent@1.1.17
9
+ - zhin.js@6.0.14
10
+
11
+ ## 7.0.1
12
+
13
+ ### Patch Changes
14
+
15
+ - 1fc78bc: Unify native platform Client access behind the literal `adapter` discriminant. Handlers infer both native events and Clients, while command, inbound/outbound middleware, and both Agent tool authoring surfaces expose the exact operation-scoped Client through a lazy `$client` getter. Definitions without `adapter` keep `$client` typed as `unknown`, and runtime dispatch rejects adapter mismatches before resolving the Client. Bundled platform tools now use this single path instead of model-provided endpoint ids and adapter-specific dependency wrappers. Every adapter registers one Client/EventMap contract, and protocol adapters including NapCat, Milky, OneBot and Satori now produce transport-independent Client objects rather than letting Endpoint instances impersonate Clients.
16
+ - Updated dependencies [e9c6a73]
17
+ - Updated dependencies [4e8117c]
18
+ - Updated dependencies [902fa35]
19
+ - Updated dependencies [54bfd6b]
20
+ - Updated dependencies [12025ee]
21
+ - Updated dependencies [09b14d6]
22
+ - Updated dependencies [1fc78bc]
23
+ - @zhin.js/agent@1.1.16
24
+ - @zhin.js/adapter@1.2.1
25
+ - @zhin.js/core@1.5.14
26
+ - @zhin.js/host-http@1.0.13
27
+ - @zhin.js/command@1.0.16
28
+ - @zhin.js/logger@1.0.77
29
+ - zhin.js@6.0.14
30
+ - @zhin.js/feature-kit@1.0.13
31
+ - @zhin.js/permission@1.0.4
32
+
3
33
  ## 7.0.0
4
34
 
5
35
  ### Patch Changes
package/README.md CHANGED
@@ -20,7 +20,7 @@ pnpm add @zhin.js/adapter-lark
20
20
  ## Plugin Runtime
21
21
 
22
22
  - `@zhin.js/adapter` — 约定式 `adapters/lark.ts`(`defineAdapter`)
23
- - `@zhin.js/core` — `messageGatewayToken` 入站/出站
23
+ - `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
24
24
  - `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
25
25
  - `zhin.js` — `plugin.ts`(`definePlugin`)
26
26
  - 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
@@ -79,7 +79,7 @@ plugins:
79
79
 
80
80
  ## Agent 工具
81
81
 
82
- `agent/` 目录保留(get_user、群聊、管理员、上传文件等)。Endpoint 在 `start` 时自注册到 `lark-agent-deps`。
82
+ `agent/` 目录保留(get_user、群聊、管理员、上传文件等)。工具声明 `adapter: 'lark'` 后,通过惰性的 `context.$client` 自动取得当前操作的 `LarkClient`;无需把 Endpoint id 暴露给模型。
83
83
 
84
84
  ## 平台权限(platform permit)
85
85
 
@@ -91,3 +91,12 @@ plugins:
91
91
  pnpm --filter @zhin.js/adapter-lark build
92
92
  pnpm --filter @zhin.js/adapter-lark test
93
93
  ```
94
+
95
+ ## 故障排查
96
+
97
+ | 现象 | 排查 |
98
+ | --- | --- |
99
+ | URL 验证失败 | 检查公网 HTTPS、`webhookPath`、verification token 与 encrypt key |
100
+ | Tenant Token 获取失败 | 检查 `appId`、`appSecret` 与应用版本是否已发布 |
101
+ | 群里 @机器人不触发 AI | 当前无法可靠判定 bot open_id;使用显式 AI 前缀 |
102
+ | 能收不能发 | 检查机器人消息权限、可见范围与应用是否已加入群聊 |
package/adapters/lark.js CHANGED
@@ -3,7 +3,6 @@
3
3
  * Convention entry: discover `adapters/lark.ts` → defineAdapter.
4
4
  */
5
5
  import { defineAdapter } from 'zhin.js/adapter';
6
- import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
7
6
  import { httpHostToken } from '@zhin.js/host-http';
8
7
  import { LarkEndpoint } from "../lib/endpoint.js";
9
8
  import { resolveLarkConfig, } from "../lib/protocol.js";
@@ -30,8 +29,6 @@ export default defineAdapter({
30
29
  });
31
30
  return new LarkEndpoint({
32
31
  id: context.id,
33
- gateway: context.use(messageGatewayToken),
34
- sideEvents: context.use(sideEventGatewayToken),
35
32
  http: context.use(httpHostToken),
36
33
  config,
37
34
  });
package/adapters/lark.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  * Convention entry: discover `adapters/lark.ts` → defineAdapter.
3
3
  */
4
4
  import { defineAdapter } from 'zhin.js/adapter';
5
- import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
6
5
  import { httpHostToken } from '@zhin.js/host-http';
7
6
  import { LarkEndpoint } from '../src/endpoint.js';
8
7
  import {
@@ -35,8 +34,6 @@ export default defineAdapter<LarkAdapterConfig>({
35
34
  });
36
35
  return new LarkEndpoint({
37
36
  id: context.id,
38
- gateway: context.use(messageGatewayToken),
39
- sideEvents: context.use(sideEventGatewayToken),
40
37
  http: context.use(httpHostToken),
41
38
  config,
42
39
  });
@@ -1,20 +1,18 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
3
  import { platformPermit } from '../../src/platform-permit.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; chat_id: string; user_ids: string }>({
5
+ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
7
6
  description: '添加飞书群成员',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  chat_id: z.string().describe('群聊 ID'),
11
9
  user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
12
10
  }),
13
- platforms: ['lark'],
11
+ adapter: 'lark',
14
12
  tags: ['lark'],
15
13
  permissions: [platformPermit('chat_admin')],
16
- async execute({ endpoint_id, chat_id, user_ids }: { endpoint_id: string; chat_id: string; user_ids: string }) {
17
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
14
+ async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
15
+ const endpoint = context.$client;
18
16
  const success = await endpoint.addChatMembers(chat_id, user_ids.split(','));
19
17
  return { success, message: success ? '成员添加成功' : '添加失败' };
20
18
  },
@@ -1,18 +1,16 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
- export default defineAgentTool<{ endpoint_id: string; name: string; members: string; owner?: string }>({
3
+ export default defineAgentTool<{ name: string; members: string; owner?: string }>({
5
4
  description: '创建飞书群聊',
6
5
  inputSchema: z.object({
7
- endpoint_id: z.string().describe('Endpoint 名称'),
8
6
  name: z.string().describe('群名'),
9
7
  members: z.string().describe('成员 open_id 列表,逗号分隔'),
10
8
  owner: z.string().optional().describe('群主 open_id(可选)'),
11
9
  }),
12
- platforms: ['lark'],
10
+ adapter: 'lark',
13
11
  tags: ['lark'],
14
- async execute({ endpoint_id, name, members, owner }: { endpoint_id: string; name: string; members: string; owner?: string }) {
15
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
12
+ async execute({ name, members, owner }: { name: string; members: string; owner?: string }, context) {
13
+ const endpoint = context.$client;
16
14
  const chatId = await endpoint.createChat(name, members.split(','), owner);
17
15
  return { success: !!chatId, chat_id: chatId, message: chatId ? `群聊创建成功: ${chatId}` : '创建失败' };
18
16
  },
@@ -1,16 +1,14 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
- export default defineAgentTool<{ endpoint_id: string; chat_id: string }>({
3
+ export default defineAgentTool<{ chat_id: string }>({
5
4
  description: '解散飞书群聊(需要群主权限)',
6
5
  inputSchema: z.object({
7
- endpoint_id: z.string().describe('Endpoint 名称'),
8
6
  chat_id: z.string().describe('群聊 ID'),
9
7
  }),
10
- platforms: ['lark'],
8
+ adapter: 'lark',
11
9
  tags: ['lark'],
12
- async execute({ endpoint_id, chat_id }: { endpoint_id: string; chat_id: string }) {
13
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
10
+ async execute({ chat_id }: { chat_id: string }, context) {
11
+ const endpoint = context.$client;
14
12
  const success = await endpoint.dissolveChat(chat_id);
15
13
  return { success, message: success ? '群聊已解散' : '解散失败' };
16
14
  },
@@ -1,17 +1,15 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
3
 
5
- export default defineAgentTool<{ endpoint_id: string; user_id: string }>({
4
+ export default defineAgentTool<{ user_id: string }>({
6
5
  description: '获取飞书用户信息',
7
6
  inputSchema: z.object({
8
- endpoint_id: z.string().describe('Endpoint 名称'),
9
7
  user_id: z.string().describe('用户 ID (open_id)'),
10
8
  }),
11
- platforms: ['lark'],
9
+ adapter: 'lark',
12
10
  tags: ['lark'],
13
- async execute({ endpoint_id, user_id }: { endpoint_id: string; user_id: string }) {
14
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
11
+ async execute({ user_id }: { user_id: string }, context) {
12
+ const endpoint = context.$client;
15
13
  return await endpoint.getUserInfo(user_id);
16
14
  },
17
15
  });
@@ -1,20 +1,18 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
3
  import { platformPermit } from '../../src/platform-permit.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; chat_id: string; user_ids: string }>({
5
+ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
7
6
  description: '移除飞书群管理员',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  chat_id: z.string().describe('群聊 ID'),
11
9
  user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
12
10
  }),
13
- platforms: ['lark'],
11
+ adapter: 'lark',
14
12
  tags: ['lark'],
15
13
  permissions: [platformPermit('manage_managers')],
16
- async execute({ endpoint_id, chat_id, user_ids }: { endpoint_id: string; chat_id: string; user_ids: string }) {
17
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
14
+ async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
15
+ const endpoint = context.$client;
18
16
  const success = await endpoint.removeChatManagers(chat_id, user_ids.split(','));
19
17
  return { success, message: success ? '管理员移除成功' : '移除失败' };
20
18
  },
@@ -1,20 +1,18 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
3
  import { platformPermit } from '../../src/platform-permit.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; chat_id: string; user_ids: string }>({
5
+ export default defineAgentTool<{ chat_id: string; user_ids: string }>({
7
6
  description: '设置飞书群管理员',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  chat_id: z.string().describe('群聊 ID'),
11
9
  user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
12
10
  }),
13
- platforms: ['lark'],
11
+ adapter: 'lark',
14
12
  tags: ['lark'],
15
13
  permissions: [platformPermit('manage_managers')],
16
- async execute({ endpoint_id, chat_id, user_ids }: { endpoint_id: string; chat_id: string; user_ids: string }) {
17
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
14
+ async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
15
+ const endpoint = context.$client;
18
16
  const success = await endpoint.setChatManagers(chat_id, user_ids.split(','));
19
17
  return { success, message: success ? '管理员设置成功' : '设置失败' };
20
18
  },
@@ -1,21 +1,19 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
3
  import { platformPermit } from '../../src/platform-permit.js';
5
4
 
6
- export default defineAgentTool<{ endpoint_id: string; chat_id: string; name?: string; description?: string }>({
5
+ export default defineAgentTool<{ chat_id: string; name?: string; description?: string }>({
7
6
  description: '更新飞书群聊信息(群名、描述)',
8
7
  inputSchema: z.object({
9
- endpoint_id: z.string().describe('Endpoint 名称'),
10
8
  chat_id: z.string().describe('群聊 ID'),
11
9
  name: z.string().optional().describe('新群名(可选)'),
12
10
  description: z.string().optional().describe('新描述(可选)'),
13
11
  }),
14
- platforms: ['lark'],
12
+ adapter: 'lark',
15
13
  tags: ['lark'],
16
14
  permissions: [platformPermit('chat_admin')],
17
- async execute({ endpoint_id, chat_id, name, description }: { endpoint_id: string; chat_id: string; name?: string; description?: string }) {
18
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
15
+ async execute({ chat_id, name, description }: { chat_id: string; name?: string; description?: string }, context) {
16
+ const endpoint = context.$client;
19
17
  const success = await endpoint.updateChatInfo(chat_id, { name, description });
20
18
  return { success, message: success ? '群信息更新成功' : '更新失败' };
21
19
  },
@@ -1,26 +1,22 @@
1
1
  import { defineAgentTool } from '@zhin.js/agent/tools';
2
2
  import { z } from 'zod';
3
- import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
4
3
 
5
4
  export default defineAgentTool<{
6
- endpoint_id: string;
7
5
  file_path: string;
8
6
  file_type: 'image' | 'file' | 'video' | 'audio';
9
7
  }>({
10
8
  description: '上传文件到飞书(image/file/video/audio)',
11
9
  inputSchema: z.object({
12
- endpoint_id: z.string().describe('Endpoint 名称'),
13
10
  file_path: z.string().describe('本地文件路径'),
14
11
  file_type: z.enum(['image', 'file', 'video', 'audio']).default('file').describe('飞书文件类型'),
15
12
  }),
16
- platforms: ['lark'],
13
+ adapter: 'lark',
17
14
  tags: ['lark'],
18
- async execute({ endpoint_id, file_path, file_type }: {
19
- endpoint_id: string;
15
+ async execute({ file_path, file_type }: {
20
16
  file_path: string;
21
17
  file_type: 'image' | 'file' | 'video' | 'audio';
22
- }) {
23
- const endpoint = getLarkAgentDeps().getEndpoint(endpoint_id);
18
+ }, context) {
19
+ const endpoint = context.$client;
24
20
  const result = await endpoint.uploadFile(file_path, file_type);
25
21
  return { success: true, file_key: result, message: `文件已上传,file_key: ${result}` };
26
22
  },
@@ -0,0 +1,12 @@
1
+ import type { LarkClient } from './endpoint.js';
2
+ import type { LarkEventBody } from './protocol.js';
3
+ export type LarkClientEventMap = Record<string, LarkEventBody>;
4
+ declare module '@zhin.js/feature-kit' {
5
+ interface AdapterClientRegistry {
6
+ readonly lark: {
7
+ readonly client: LarkClient;
8
+ readonly events: LarkClientEventMap;
9
+ };
10
+ }
11
+ }
12
+ export declare const larkClient: import("@zhin.js/adapter").EndpointClientToken<LarkClient, LarkClientEventMap>;
package/lib/client.js ADDED
@@ -0,0 +1,2 @@
1
+ import { defineEndpointClient } from 'zhin.js/adapter';
2
+ export const larkClient = defineEndpointClient('lark');
package/lib/endpoint.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { type EndpointControl, type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
2
- import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
1
+ import { Endpoint } from 'zhin.js/adapter';
2
+ import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
3
3
  import type { HttpHost } from '@zhin.js/host-http';
4
4
  import type { CapabilityId } from 'zhin.js';
5
5
  import { resolveMediaBinary } from './media-upload.js';
@@ -17,14 +17,48 @@ export type LarkFetch = (url: string, init?: {
17
17
  }>;
18
18
  export interface LarkEndpointOptions {
19
19
  readonly id: CapabilityId;
20
- readonly gateway: MessageGateway;
21
- readonly sideEvents?: SideEventGateway;
22
20
  readonly http: HttpHost;
23
21
  readonly config: ResolvedLarkConfig;
24
22
  readonly fetch?: LarkFetch;
25
23
  }
26
- export declare class LarkEndpoint implements EndpointInstance {
24
+ export interface LarkClientApi {
25
+ getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
26
+ getChatInfo(chatId: string): Promise<unknown>;
27
+ uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
28
+ createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
29
+ updateChatInfo(chatId: string, options: {
30
+ name?: string;
31
+ description?: string;
32
+ }): Promise<boolean>;
33
+ addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
34
+ removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
35
+ getChatMembers(chatId: string): Promise<unknown[]>;
36
+ dissolveChat(chatId: string): Promise<boolean>;
37
+ setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
38
+ removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
39
+ }
40
+ /** Feishu/Lark OpenAPI client surface carried by every Endpoint event. */
41
+ export declare class LarkClient implements LarkClientApi {
42
+ readonly api: LarkClientApi;
43
+ constructor(api: LarkClientApi);
44
+ getUserInfo: (id: string, type?: "open_id" | "user_id" | "union_id") => Promise<unknown>;
45
+ getChatInfo: (id: string) => Promise<unknown>;
46
+ uploadFile: (path: string, type?: "image" | "file" | "video" | "audio") => Promise<string | null>;
47
+ createChat: (name: string, users: string[], owner?: string) => Promise<string | null>;
48
+ updateChatInfo: (id: string, options: {
49
+ name?: string;
50
+ description?: string;
51
+ }) => Promise<boolean>;
52
+ addChatMembers: (id: string, users: string[]) => Promise<boolean>;
53
+ removeChatMembers: (id: string, users: string[]) => Promise<boolean>;
54
+ getChatMembers: (id: string) => Promise<unknown[]>;
55
+ dissolveChat: (id: string) => Promise<boolean>;
56
+ setChatManagers: (id: string, users: string[]) => Promise<boolean>;
57
+ removeChatManagers: (id: string, users: string[]) => Promise<boolean>;
58
+ }
59
+ export declare class LarkEndpoint extends Endpoint<LarkClient> {
27
60
  #private;
61
+ readonly client: LarkClient;
28
62
  /**
29
63
  * Console 社交面语义端口。Lark OpenAPI 仅接读取类列表能力:
30
64
  * - listGroups:GET /im/v1/chats(bot 所在群列表,分页归一为 {group_id: chat_id, name})
@@ -48,6 +82,7 @@ export declare class LarkEndpoint implements EndpointInstance {
48
82
  uploadImage(media: Parameters<typeof resolveMediaBinary>[0]): Promise<string | null>;
49
83
  /** Test / internal: admit a parsed message when open (non-webhook path). */
50
84
  admit(msg: LarkMessage): void;
85
+ admitPlatform(name: string, event: unknown): void;
51
86
  getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
52
87
  getChatInfo(chatId: string): Promise<unknown>;
53
88
  uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
package/lib/endpoint.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
1
2
  /**
2
3
  * LarkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
3
4
  */
@@ -5,13 +6,43 @@ import { readFile } from 'node:fs/promises';
5
6
  import { basename } from 'node:path';
6
7
  import { createRecallEndpointControl, } from 'zhin.js/adapter';
7
8
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
8
- import { registerLarkAgentEndpoint } from './lark-agent-deps.js';
9
9
  import { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
10
10
  import { formatInboundContent, formatOutboundBody, generateMessageId, larkInboundConversation, resolveChatType, resolveSender, } from './protocol.js';
11
11
  import { registerLarkWebhookRoutes } from './webhook.js';
12
12
  /** 出站 HTTP 调用统一 30s 超时。 */
13
13
  const OUTBOUND_TIMEOUT_MS = 30_000;
14
- export class LarkEndpoint {
14
+ /** Feishu/Lark OpenAPI client surface carried by every Endpoint event. */
15
+ export class LarkClient {
16
+ api;
17
+ constructor(api) {
18
+ this.api = api;
19
+ }
20
+ getUserInfo = (id, type) => this.api.getUserInfo(id, type);
21
+ getChatInfo = (id) => this.api.getChatInfo(id);
22
+ uploadFile = (path, type) => this.api.uploadFile(path, type);
23
+ createChat = (name, users, owner) => this.api.createChat(name, users, owner);
24
+ updateChatInfo = (id, options) => this.api.updateChatInfo(id, options);
25
+ addChatMembers = (id, users) => this.api.addChatMembers(id, users);
26
+ removeChatMembers = (id, users) => this.api.removeChatMembers(id, users);
27
+ getChatMembers = (id) => this.api.getChatMembers(id);
28
+ dissolveChat = (id) => this.api.dissolveChat(id);
29
+ setChatManagers = (id, users) => this.api.setChatManagers(id, users);
30
+ removeChatManagers = (id, users) => this.api.removeChatManagers(id, users);
31
+ }
32
+ export class LarkEndpoint extends Endpoint {
33
+ client = new LarkClient({
34
+ getUserInfo: (id, type) => this.getUserInfo(id, type),
35
+ getChatInfo: (id) => this.getChatInfo(id),
36
+ uploadFile: (path, type) => this.uploadFile(path, type),
37
+ createChat: (name, users, owner) => this.createChat(name, users, owner),
38
+ updateChatInfo: (id, options) => this.updateChatInfo(id, options),
39
+ addChatMembers: (id, users) => this.addChatMembers(id, users),
40
+ removeChatMembers: (id, users) => this.removeChatMembers(id, users),
41
+ getChatMembers: (id) => this.getChatMembers(id),
42
+ dissolveChat: (id) => this.dissolveChat(id),
43
+ setChatManagers: (id, users) => this.setChatManagers(id, users),
44
+ removeChatManagers: (id, users) => this.removeChatManagers(id, users),
45
+ });
15
46
  #logger;
16
47
  #options;
17
48
  #fetch;
@@ -45,8 +76,8 @@ export class LarkEndpoint {
45
76
  #refreshPromise = null;
46
77
  #open = false;
47
78
  #started = false;
48
- #unregisterAgent;
49
79
  constructor(options) {
80
+ super();
50
81
  this.#logger = getAdapterLogger('lark', options.config.id);
51
82
  this.#options = options;
52
83
  this.#fetch = options.fetch ?? globalThis.fetch;
@@ -73,7 +104,6 @@ export class LarkEndpoint {
73
104
  }));
74
105
  }
75
106
  await this.#refreshAccessToken();
76
- this.#unregisterAgent = registerLarkAgentEndpoint(this.#options.config.id, this);
77
107
  this.#routeReleases.push(...registerLarkWebhookRoutes(this.#options.http, this));
78
108
  this.#logger.debug(formatCompact({
79
109
  endpoint: this.#options.config.id,
@@ -97,8 +127,6 @@ export class LarkEndpoint {
97
127
  this.#open = false;
98
128
  for (const release of this.#routeReleases.splice(0))
99
129
  release();
100
- this.#unregisterAgent?.();
101
- this.#unregisterAgent = undefined;
102
130
  this.#started = false;
103
131
  this.#logger.debug(formatCompact({ op: 'disconnect' }));
104
132
  }
@@ -186,7 +214,7 @@ export class LarkEndpoint {
186
214
  if (!this.#open)
187
215
  return;
188
216
  const conversation = larkInboundConversation(String(this.#options.id), msg);
189
- void this.#options.gateway.receive({
217
+ void this.emit('message.receive', {
190
218
  conversation,
191
219
  message: { conversation, id: generateMessageId(msg) },
192
220
  content: formatInboundContent(msg),
@@ -204,6 +232,17 @@ export class LarkEndpoint {
204
232
  }));
205
233
  });
206
234
  }
235
+ admitPlatform(name, event) {
236
+ if (!this.#open)
237
+ return;
238
+ void this.emitPlatform(name, event).catch((error) => {
239
+ this.#logger.warn(formatCompact({
240
+ op: 'lark_platform_event_failed',
241
+ event: name,
242
+ error: error instanceof Error ? error.message : String(error),
243
+ }));
244
+ });
245
+ }
207
246
  async getUserInfo(userId, userIdType = 'open_id') {
208
247
  try {
209
248
  const data = await this.#request(`/contact/v3/users/${userId}`, {
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, type AccessToken, type LarkAdapterConfig, type LarkApiResponse, type LarkEventBody, type LarkMessage, type LarkSendBody, type LarkWireSegment, type ResolvedLarkConfig, } from './protocol.js';
2
- export { getLarkAgentDeps, registerLarkAgentEndpoint, setLarkAgentDeps, type LarkAgentDeps, type LarkAgentEndpoint, } from './lark-agent-deps.js';
2
+ export { larkClient, type LarkClientEventMap } from './client.js';
3
3
  export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
4
- export { LarkEndpoint, type LarkEndpointOptions, type LarkFetch, } from './endpoint.js';
4
+ export { LarkClient, LarkEndpoint, type LarkClientApi, type LarkEndpointOptions, type LarkFetch, } from './endpoint.js';
5
5
  export { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, type MediaBinary, } from './media-upload.js';
6
6
  export { registerLarkWebhookRoutes, handleLarkWebhookRequest, type LarkWebhookHandler, } from './webhook.js';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, } from './protocol.js';
2
- export { getLarkAgentDeps, registerLarkAgentEndpoint, setLarkAgentDeps, } from './lark-agent-deps.js';
2
+ export { larkClient } from './client.js';
3
3
  export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
4
- export { LarkEndpoint, } from './endpoint.js';
4
+ export { LarkClient, LarkEndpoint, } from './endpoint.js';
5
5
  export { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
6
6
  export { registerLarkWebhookRoutes, handleLarkWebhookRequest, } from './webhook.js';
@@ -1 +1 @@
1
- export declare const larkEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
1
+ export declare const larkEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
package/lib/protocol.d.ts CHANGED
@@ -105,7 +105,7 @@ export declare function resolveChatType(chatId?: string, chatType?: string): 'gr
105
105
  export declare function larkInboundConversation(endpointKey: string, msg: LarkMessage): ConversationRef;
106
106
  export declare function resolveSender(msg: LarkMessage): string;
107
107
  export declare function generateMessageId(msg: LarkMessage): string;
108
- /** Build inbound text for MessageGateway.receive. */
108
+ /** Build inbound text for OutboundMessageService.receive. */
109
109
  export declare function formatInboundContent(msg: LarkMessage): string;
110
110
  /** 验签时间戳时效窗口(防重放)。 */
111
111
  export declare const LARK_SIGNATURE_MAX_AGE_MS: number;
package/lib/protocol.js CHANGED
@@ -69,7 +69,7 @@ export function resolveSender(msg) {
69
69
  export function generateMessageId(msg) {
70
70
  return msg.message_id || `${msg.create_time ?? Date.now()}`;
71
71
  }
72
- /** Build inbound text for MessageGateway.receive. */
72
+ /** Build inbound text for OutboundMessageService.receive. */
73
73
  export function formatInboundContent(msg) {
74
74
  if (!msg.content || !msg.message_type)
75
75
  return '';
package/lib/webhook.d.ts CHANGED
@@ -7,6 +7,7 @@ import { type LarkMessage, type ResolvedLarkConfig } from './protocol.js';
7
7
  export interface LarkWebhookHandler {
8
8
  readonly config: ResolvedLarkConfig;
9
9
  readonly isOpen: boolean;
10
+ admitPlatform(name: string, event: unknown): void;
10
11
  admit(msg: LarkMessage): void;
11
12
  }
12
13
  export declare function registerLarkWebhookRoutes(http: HttpHost, handler: LarkWebhookHandler): HttpRouteRegistration[];
package/lib/webhook.js CHANGED
@@ -44,6 +44,12 @@ export async function handleLarkWebhookRequest(request, response, handler) {
44
44
  response.end(JSON.stringify({ code: 0, msg: 'success' }));
45
45
  return;
46
46
  }
47
+ if (handler.isOpen) {
48
+ const eventName = event.type === 'event_callback'
49
+ ? String(event.event?.type ?? event.type)
50
+ : String(event.type ?? 'event');
51
+ handler.admitPlatform(eventName, event);
52
+ }
47
53
  if (event.type === 'url_verification') {
48
54
  response.writeHead(200, { 'Content-Type': 'application/json' });
49
55
  response.end(JSON.stringify({ challenge: event.challenge }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-lark",
3
- "version": "7.0.0",
3
+ "version": "7.0.2",
4
4
  "description": "Zhin.js Lark/Feishu (飞书) adapter for Plugin Runtime (HTTP webhook)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -34,21 +34,22 @@
34
34
  "directory": "plugins/adapters/lark"
35
35
  },
36
36
  "dependencies": {
37
- "@zhin.js/adapter": "1.2.0",
38
- "@zhin.js/core": "1.5.13",
39
- "@zhin.js/host-http": "1.0.12",
37
+ "@zhin.js/adapter": "1.2.1",
38
+ "@zhin.js/core": "1.5.14",
39
+ "@zhin.js/feature-kit": "1.0.13",
40
+ "@zhin.js/host-http": "1.0.13",
40
41
  "@zhin.js/im-contract": "1.0.4",
41
- "@zhin.js/logger": "1.0.76"
42
+ "@zhin.js/logger": "1.0.77"
42
43
  },
43
44
  "peerDependencies": {
44
45
  "zod": "^4.0.0",
45
- "@zhin.js/adapter": "1.2.0",
46
- "@zhin.js/agent": "1.1.15",
47
- "@zhin.js/command": "1.0.15",
48
- "@zhin.js/core": "1.5.13",
49
- "@zhin.js/host-http": "1.0.12",
50
- "@zhin.js/permission": "1.0.3",
51
- "zhin.js": "6.0.13"
46
+ "@zhin.js/adapter": "1.2.1",
47
+ "@zhin.js/agent": "1.1.17",
48
+ "@zhin.js/command": "1.0.16",
49
+ "@zhin.js/core": "1.5.14",
50
+ "@zhin.js/host-http": "1.0.13",
51
+ "@zhin.js/permission": "1.0.4",
52
+ "zhin.js": "6.0.14"
52
53
  },
53
54
  "peerDependenciesMeta": {
54
55
  "@zhin.js/agent": {
@@ -69,8 +70,8 @@
69
70
  "typescript": "^6.0.3",
70
71
  "vitest": "^4.1.10",
71
72
  "zod": "^4.4.3",
72
- "@zhin.js/agent": "1.1.15",
73
- "zhin.js": "6.0.13"
73
+ "@zhin.js/agent": "1.1.17",
74
+ "zhin.js": "6.0.14"
74
75
  },
75
76
  "files": [
76
77
  "adapters",
package/src/client.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { defineEndpointClient } from 'zhin.js/adapter';
2
+ import type { LarkClient } from './endpoint.js';
3
+ import type { LarkEventBody } from './protocol.js';
4
+
5
+ export type LarkClientEventMap = Record<string, LarkEventBody>;
6
+
7
+ declare module '@zhin.js/feature-kit' {
8
+ interface AdapterClientRegistry {
9
+ readonly lark: {
10
+ readonly client: LarkClient;
11
+ readonly events: LarkClientEventMap;
12
+ };
13
+ }
14
+ }
15
+
16
+ export const larkClient = defineEndpointClient<LarkClient, LarkClientEventMap>('lark');
package/src/endpoint.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Endpoint } from 'zhin.js/adapter';
1
2
  /**
2
3
  * LarkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
3
4
  */
@@ -7,15 +8,12 @@ import {
7
8
  createRecallEndpointControl,
8
9
  type EndpointControl,
9
10
  type EndpointGroup,
10
- type EndpointInstance,
11
11
  type EndpointManagement,
12
12
  type EndpointSendRequest,
13
13
  } from 'zhin.js/adapter';
14
- import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
15
14
  import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
16
15
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
17
16
  import type { CapabilityId } from 'zhin.js';
18
- import { registerLarkAgentEndpoint } from './lark-agent-deps.js';
19
17
  import {
20
18
  buildImageUploadForm,
21
19
  readOutboundImageMedia,
@@ -55,14 +53,59 @@ export type LarkFetch = (
55
53
 
56
54
  export interface LarkEndpointOptions {
57
55
  readonly id: CapabilityId;
58
- readonly gateway: MessageGateway;
59
- readonly sideEvents?: SideEventGateway;
60
56
  readonly http: HttpHost;
61
57
  readonly config: ResolvedLarkConfig;
62
58
  readonly fetch?: LarkFetch;
63
59
  }
64
60
 
65
- export class LarkEndpoint implements EndpointInstance {
61
+ export interface LarkClientApi {
62
+ getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
63
+ getChatInfo(chatId: string): Promise<unknown>;
64
+ uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
65
+ createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
66
+ updateChatInfo(chatId: string, options: { name?: string; description?: string }): Promise<boolean>;
67
+ addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
68
+ removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
69
+ getChatMembers(chatId: string): Promise<unknown[]>;
70
+ dissolveChat(chatId: string): Promise<boolean>;
71
+ setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
72
+ removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
73
+ }
74
+
75
+ /** Feishu/Lark OpenAPI client surface carried by every Endpoint event. */
76
+ export class LarkClient implements LarkClientApi {
77
+ constructor(readonly api: LarkClientApi) {}
78
+ getUserInfo = (id: string, type?: 'open_id' | 'user_id' | 'union_id') =>
79
+ this.api.getUserInfo(id, type);
80
+ getChatInfo = (id: string) => this.api.getChatInfo(id);
81
+ uploadFile = (path: string, type?: 'image' | 'file' | 'video' | 'audio') =>
82
+ this.api.uploadFile(path, type);
83
+ createChat = (name: string, users: string[], owner?: string) =>
84
+ this.api.createChat(name, users, owner);
85
+ updateChatInfo = (id: string, options: { name?: string; description?: string }) =>
86
+ this.api.updateChatInfo(id, options);
87
+ addChatMembers = (id: string, users: string[]) => this.api.addChatMembers(id, users);
88
+ removeChatMembers = (id: string, users: string[]) => this.api.removeChatMembers(id, users);
89
+ getChatMembers = (id: string) => this.api.getChatMembers(id);
90
+ dissolveChat = (id: string) => this.api.dissolveChat(id);
91
+ setChatManagers = (id: string, users: string[]) => this.api.setChatManagers(id, users);
92
+ removeChatManagers = (id: string, users: string[]) => this.api.removeChatManagers(id, users);
93
+ }
94
+
95
+ export class LarkEndpoint extends Endpoint<LarkClient> {
96
+ readonly client = new LarkClient({
97
+ getUserInfo: (id, type) => this.getUserInfo(id, type),
98
+ getChatInfo: (id) => this.getChatInfo(id),
99
+ uploadFile: (path, type) => this.uploadFile(path, type),
100
+ createChat: (name, users, owner) => this.createChat(name, users, owner),
101
+ updateChatInfo: (id, options) => this.updateChatInfo(id, options),
102
+ addChatMembers: (id, users) => this.addChatMembers(id, users),
103
+ removeChatMembers: (id, users) => this.removeChatMembers(id, users),
104
+ getChatMembers: (id) => this.getChatMembers(id),
105
+ dissolveChat: (id) => this.dissolveChat(id),
106
+ setChatManagers: (id, users) => this.setChatManagers(id, users),
107
+ removeChatManagers: (id, users) => this.removeChatManagers(id, users),
108
+ });
66
109
  readonly #logger!: ReturnType<typeof getAdapterLogger>;
67
110
 
68
111
  readonly #options: LarkEndpointOptions;
@@ -99,9 +142,9 @@ export class LarkEndpoint implements EndpointInstance {
99
142
  #refreshPromise: Promise<string> | null = null;
100
143
  #open = false;
101
144
  #started = false;
102
- #unregisterAgent?: () => void;
103
145
 
104
146
  constructor(options: LarkEndpointOptions) {
147
+ super();
105
148
  this.#logger = getAdapterLogger('lark', options.config.id);
106
149
  this.#options = options;
107
150
  this.#fetch = options.fetch ?? globalThis.fetch;
@@ -130,7 +173,6 @@ export class LarkEndpoint implements EndpointInstance {
130
173
  }));
131
174
  }
132
175
  await this.#refreshAccessToken();
133
- this.#unregisterAgent = registerLarkAgentEndpoint(this.#options.config.id, this);
134
176
  this.#routeReleases.push(...registerLarkWebhookRoutes(this.#options.http, this));
135
177
  this.#logger.debug(formatCompact({
136
178
  endpoint: this.#options.config.id,
@@ -155,8 +197,6 @@ export class LarkEndpoint implements EndpointInstance {
155
197
  async stop(): Promise<void> {
156
198
  this.#open = false;
157
199
  for (const release of this.#routeReleases.splice(0)) release();
158
- this.#unregisterAgent?.();
159
- this.#unregisterAgent = undefined;
160
200
  this.#started = false;
161
201
  this.#logger.debug(formatCompact({ op: 'disconnect' }));
162
202
  }
@@ -242,7 +282,7 @@ export class LarkEndpoint implements EndpointInstance {
242
282
  admit(msg: LarkMessage): void {
243
283
  if (!this.#open) return;
244
284
  const conversation = larkInboundConversation(String(this.#options.id), msg);
245
- void this.#options.gateway.receive({
285
+ void this.emit('message.receive', {
246
286
  conversation,
247
287
  message: { conversation, id: generateMessageId(msg) },
248
288
  content: formatInboundContent(msg),
@@ -261,6 +301,17 @@ export class LarkEndpoint implements EndpointInstance {
261
301
  });
262
302
  }
263
303
 
304
+ admitPlatform(name: string, event: unknown): void {
305
+ if (!this.#open) return;
306
+ void this.emitPlatform(name, event).catch((error) => {
307
+ this.#logger.warn(formatCompact({
308
+ op: 'lark_platform_event_failed',
309
+ event: name,
310
+ error: error instanceof Error ? error.message : String(error),
311
+ }));
312
+ });
313
+ }
314
+
264
315
  async getUserInfo(
265
316
  userId: string,
266
317
  userIdType: 'open_id' | 'user_id' | 'union_id' = 'open_id',
package/src/index.ts CHANGED
@@ -20,13 +20,7 @@ export {
20
20
  type ResolvedLarkConfig,
21
21
  } from './protocol.js';
22
22
 
23
- export {
24
- getLarkAgentDeps,
25
- registerLarkAgentEndpoint,
26
- setLarkAgentDeps,
27
- type LarkAgentDeps,
28
- type LarkAgentEndpoint,
29
- } from './lark-agent-deps.js';
23
+ export { larkClient, type LarkClientEventMap } from './client.js';
30
24
 
31
25
  export {
32
26
  checkLarkPlatformPermit,
@@ -36,7 +30,9 @@ export {
36
30
  } from './platform-permit.js';
37
31
 
38
32
  export {
33
+ LarkClient,
39
34
  LarkEndpoint,
35
+ type LarkClientApi,
40
36
  type LarkEndpointOptions,
41
37
  type LarkFetch,
42
38
  } from './endpoint.js';
package/src/protocol.ts CHANGED
@@ -182,7 +182,7 @@ export function generateMessageId(msg: LarkMessage): string {
182
182
  return msg.message_id || `${msg.create_time ?? Date.now()}`;
183
183
  }
184
184
 
185
- /** Build inbound text for MessageGateway.receive. */
185
+ /** Build inbound text for OutboundMessageService.receive. */
186
186
  export function formatInboundContent(msg: LarkMessage): string {
187
187
  if (!msg.content || !msg.message_type) return '';
188
188
  try {
package/src/webhook.ts CHANGED
@@ -19,6 +19,7 @@ const logger = getLogger('lark');
19
19
  export interface LarkWebhookHandler {
20
20
  readonly config: ResolvedLarkConfig;
21
21
  readonly isOpen: boolean;
22
+ admitPlatform(name: string, event: unknown): void;
22
23
  admit(msg: LarkMessage): void;
23
24
  }
24
25
 
@@ -78,6 +79,13 @@ export async function handleLarkWebhookRequest(
78
79
  return;
79
80
  }
80
81
 
82
+ if (handler.isOpen) {
83
+ const eventName = event.type === 'event_callback'
84
+ ? String(event.event?.type ?? event.type)
85
+ : String(event.type ?? 'event');
86
+ handler.admitPlatform(eventName, event);
87
+ }
88
+
81
89
  if (event.type === 'url_verification') {
82
90
  response.writeHead(200, { 'Content-Type': 'application/json' });
83
91
  response.end(JSON.stringify({ challenge: event.challenge }));
@@ -1,27 +0,0 @@
1
- /**
2
- * Agent tool deps for lark (user / chat / managers / upload).
3
- * Endpoints register themselves on start; tools look up by endpoint id.
4
- */
5
- export interface LarkAgentEndpoint {
6
- getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
7
- getChatInfo(chatId: string): Promise<unknown>;
8
- uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
9
- createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
10
- updateChatInfo(chatId: string, options: {
11
- name?: string;
12
- description?: string;
13
- }): Promise<boolean>;
14
- addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
15
- removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
16
- getChatMembers(chatId: string): Promise<unknown[]>;
17
- dissolveChat(chatId: string): Promise<boolean>;
18
- setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
19
- removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
20
- }
21
- export interface LarkAgentDeps {
22
- getEndpoint: (endpointKey: string) => LarkAgentEndpoint;
23
- }
24
- export declare function registerLarkAgentEndpoint(endpointKey: string, endpoint: LarkAgentEndpoint): () => void;
25
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
26
- export declare function setLarkAgentDeps(deps: LarkAgentDeps | null): void;
27
- export declare function getLarkAgentDeps(): LarkAgentDeps;
@@ -1,30 +0,0 @@
1
- /**
2
- * Agent tool deps for lark (user / chat / managers / upload).
3
- * Endpoints register themselves on start; tools look up by endpoint id.
4
- */
5
- const endpoints = new Map();
6
- let override = null;
7
- export function registerLarkAgentEndpoint(endpointKey, endpoint) {
8
- endpoints.set(endpointKey, endpoint);
9
- return () => {
10
- if (endpoints.get(endpointKey) === endpoint) {
11
- endpoints.delete(endpointKey);
12
- }
13
- };
14
- }
15
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
16
- export function setLarkAgentDeps(deps) {
17
- override = deps;
18
- }
19
- export function getLarkAgentDeps() {
20
- if (override)
21
- return override;
22
- return {
23
- getEndpoint(endpointKey) {
24
- const endpoint = endpoints.get(endpointKey);
25
- if (!endpoint)
26
- throw new Error(`Endpoint ${endpointKey} 不存在`);
27
- return endpoint;
28
- },
29
- };
30
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * Agent tool deps for lark (user / chat / managers / upload).
3
- * Endpoints register themselves on start; tools look up by endpoint id.
4
- */
5
-
6
- export interface LarkAgentEndpoint {
7
- getUserInfo(
8
- userId: string,
9
- userIdType?: 'open_id' | 'user_id' | 'union_id',
10
- ): Promise<unknown>;
11
- getChatInfo(chatId: string): Promise<unknown>;
12
- uploadFile(
13
- filePath: string,
14
- fileType?: 'image' | 'file' | 'video' | 'audio',
15
- ): Promise<string | null>;
16
- createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
17
- updateChatInfo(
18
- chatId: string,
19
- options: { name?: string; description?: string },
20
- ): Promise<boolean>;
21
- addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
22
- removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
23
- getChatMembers(chatId: string): Promise<unknown[]>;
24
- dissolveChat(chatId: string): Promise<boolean>;
25
- setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
26
- removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
27
- }
28
-
29
- export interface LarkAgentDeps {
30
- getEndpoint: (endpointKey: string) => LarkAgentEndpoint;
31
- }
32
-
33
- const endpoints = new Map<string, LarkAgentEndpoint>();
34
- let override: LarkAgentDeps | null = null;
35
-
36
- export function registerLarkAgentEndpoint(
37
- endpointKey: string,
38
- endpoint: LarkAgentEndpoint,
39
- ): () => void {
40
- endpoints.set(endpointKey, endpoint);
41
- return () => {
42
- if (endpoints.get(endpointKey) === endpoint) {
43
- endpoints.delete(endpointKey);
44
- }
45
- };
46
- }
47
-
48
- /** Optional override used by tests / transitional callers. Pass `null` to clear. */
49
- export function setLarkAgentDeps(deps: LarkAgentDeps | null): void {
50
- override = deps;
51
- }
52
-
53
- export function getLarkAgentDeps(): LarkAgentDeps {
54
- if (override) return override;
55
- return {
56
- getEndpoint(endpointKey) {
57
- const endpoint = endpoints.get(endpointKey);
58
- if (!endpoint) throw new Error(`Endpoint ${endpointKey} 不存在`);
59
- return endpoint;
60
- },
61
- };
62
- }