@xmanrui/dsh-im 3.2.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmanrui/dsh-im",
3
- "version": "3.2.0",
3
+ "version": "4.0.0",
4
4
  "description": "把九种 IM 机器人和公网 AI Office 接入本机 DeepSeek Harness。 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installDingtalkRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-dingtalk-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installDiscordRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-discord-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -3,7 +3,7 @@ import { createProductionController } from './production.mjs';
3
3
  import { installFeishuRpc } from './rpc.mjs';
4
4
 
5
5
  export const name = 'dsh-feishu-host';
6
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
6
+ export const inject = ['connection', 'credentials', 'typertGateway'];
7
7
 
8
8
  function controllerFrom(ctx, config) {
9
9
  if (config?.controller) return config.controller;
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installQqRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-qq-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installSlackRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-slack-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) return installSlackRpc(ctx, config.controller, config.rpcAuthority);
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installTelegramRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-telegram-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installWecomRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-wecom-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installWeixinRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-weixin-host';
5
- export const inject = ['connection', 'credentials', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'credentials', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -2,7 +2,7 @@ import { createProductionController } from './production.mjs';
2
2
  import { installWhatsappRpc } from './rpc.mjs';
3
3
 
4
4
  export const name = 'dsh-im-whatsapp-host';
5
- export const inject = ['connection', 'apiProxy', 'typertGateway'];
5
+ export const inject = ['connection', 'typertGateway'];
6
6
 
7
7
  export async function apply(ctx, config = {}) {
8
8
  if (config?.controller) {
@@ -1,13 +1,18 @@
1
+ import { modernHarnessApi } from './modern-harness-api.mjs';
2
+
3
+ function optionalService(ctx, name) {
4
+ if (ctx && Object.hasOwn(ctx, name)) return ctx[name];
5
+ return typeof ctx?.get === 'function' ? ctx.get(name) : undefined;
6
+ }
7
+
1
8
  /** Connect to this Host directly unless an external Harness URL was configured. */
2
9
  export function harnessConnection(ctx, config = {}) {
3
10
  if (config.harnessBaseUrl !== undefined) {
4
11
  return { baseUrl: new URL(config.harnessBaseUrl) };
5
12
  }
6
- if (!ctx?.apiProxy) {
7
- throw new TypeError('dsh-im requires the Host apiProxy service; check that DSH has finished loading its Host services');
8
- }
13
+ const apiProxy = optionalService(ctx, 'apiProxy') ?? modernHarnessApi(ctx);
9
14
  return {
10
- apiProxy: ctx.apiProxy,
15
+ apiProxy,
11
16
  // Cordis child contexts share one root; different Hosts must not share
12
17
  // ownership of pending questions and approvals.
13
18
  interactionScope: ctx.root ?? ctx,
@@ -16,7 +16,6 @@ export const name = 'dsh-im-host';
16
16
  export const inject = [
17
17
  'connection',
18
18
  'credentials',
19
- 'apiProxy',
20
19
  'typertGateway',
21
20
  ];
22
21
 
@@ -55,38 +54,53 @@ export function createImHostPlugin(internals = {}) {
55
54
  name,
56
55
  inject,
57
56
  async apply(ctx, config = {}) {
58
- setImHostLanguage(config.language ?? process.env.DSH_IM_LANGUAGE);
57
+ const activate = async (readyCtx) => {
58
+ await activateChannels(readyCtx, config);
59
+ };
59
60
  if (typeof ctx?.inject === 'function') {
60
- ctx.inject(['tools', 'systemPrompt'], (artifactCtx) => {
61
- installOutboundArtifactTool(artifactCtx);
62
- });
63
- } else {
64
- installOutboundArtifactTool(ctx);
65
- }
66
- const logger = typeof ctx?.logger === 'function'
67
- ? ctx.logger(name)
68
- : (ctx?.logger ?? console);
69
- if (ctx?.connection?.rpc) {
70
- try {
71
- startUpdate(ctx);
72
- } catch (error) {
73
- logger.error?.('[dsh-im] failed to activate update management; continuing with channels', error);
74
- }
75
- }
76
- const failures = [];
77
- for (const [channel, start] of channels) {
78
- try {
79
- await start(ctx, channelConfig(config, channel));
80
- } catch (error) {
81
- failures.push(error);
82
- logger.error?.(`[dsh-im] failed to activate ${channel}; continuing with the remaining channels`, error);
83
- }
84
- }
85
- if (failures.length === channels.length) {
86
- throw new AggregateError(failures, 'dsh-im failed to activate every channel');
61
+ const modern = typeof ctx?.typertGateway?.stream === 'function';
62
+ await ctx.inject(
63
+ modern ? ['sessionController', 'workspaceController'] : ['apiProxy'],
64
+ activate,
65
+ );
66
+ return;
87
67
  }
68
+ await activate(ctx);
88
69
  },
89
70
  });
71
+
72
+ async function activateChannels(ctx, config) {
73
+ setImHostLanguage(config.language ?? process.env.DSH_IM_LANGUAGE);
74
+ if (typeof ctx?.inject === 'function') {
75
+ ctx.inject(['tools', 'systemPrompt'], (artifactCtx) => {
76
+ installOutboundArtifactTool(artifactCtx);
77
+ });
78
+ } else {
79
+ installOutboundArtifactTool(ctx);
80
+ }
81
+ const logger = typeof ctx?.logger === 'function'
82
+ ? ctx.logger(name)
83
+ : (ctx?.logger ?? console);
84
+ if (ctx?.connection?.rpc) {
85
+ try {
86
+ startUpdate(ctx);
87
+ } catch (error) {
88
+ logger.error?.('[dsh-im] failed to activate update management; continuing with channels', error);
89
+ }
90
+ }
91
+ const failures = [];
92
+ for (const [channel, start] of channels) {
93
+ try {
94
+ await start(ctx, channelConfig(config, channel));
95
+ } catch (error) {
96
+ failures.push(error);
97
+ logger.error?.(`[dsh-im] failed to activate ${channel}; continuing with the remaining channels`, error);
98
+ }
99
+ }
100
+ if (failures.length === channels.length) {
101
+ throw new AggregateError(failures, 'dsh-im failed to activate every channel');
102
+ }
103
+ }
90
104
  }
91
105
 
92
106
  export async function apply(ctx, config = {}) {