@zhin.js/host-http 1.0.13 → 1.0.14

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.
@@ -26,6 +26,8 @@ export interface ConsoleRestCtx {
26
26
  get(name: string): unknown;
27
27
  };
28
28
  };
29
+ /** Distinguishes a real IM conversation with no Agent turn from a typo key. */
30
+ readonly isKnownConversationSession?: (sessionKey: string) => boolean | undefined | Promise<boolean | undefined>;
29
31
  }
30
32
  /** 内省数据门面 — 由 basic/cli 用 agent 包 collectIntrospection* 装配。 */
31
33
  export interface ConsoleAgentIntrospection {
@@ -663,9 +663,33 @@ function registerAgentSessionRoutes(route, base, ctx) {
663
663
  try {
664
664
  const sessionId = await runtime.resolveActiveSessionId(parsed.sessionKey);
665
665
  if (!sessionId) {
666
- writeJson(response, 404, {
667
- success: false,
668
- error: `未找到活跃会话:${parsed.sessionKey}`,
666
+ if (!isRuntimeImSessionKey(parsed.sessionKey)) {
667
+ writeJson(response, 404, {
668
+ success: false,
669
+ error: `未找到会话:${parsed.sessionKey}`,
670
+ });
671
+ return;
672
+ }
673
+ const knownConversation = await ctx.isKnownConversationSession?.(parsed.sessionKey);
674
+ if (knownConversation === false) {
675
+ writeJson(response, 404, {
676
+ success: false,
677
+ error: `未找到会话:${parsed.sessionKey}`,
678
+ });
679
+ return;
680
+ }
681
+ // 渠道会话与 Agent 会话的生命周期不同:用户可以先在 Console
682
+ // 选中一个真实渠道会话,而该会话尚未触发过 Agent。树查询是只读操作,
683
+ // 因而将这种正常状态返回为可渲染空态,而不是误报资源不存在。
684
+ writeJson(response, 200, {
685
+ success: true,
686
+ data: {
687
+ state: 'not_started',
688
+ sessionKey: parsed.sessionKey,
689
+ sessionId: null,
690
+ activeLeafMessageId: null,
691
+ points: [],
692
+ },
669
693
  });
670
694
  return;
671
695
  }
@@ -674,6 +698,7 @@ function registerAgentSessionRoutes(route, base, ctx) {
674
698
  writeJson(response, 200, {
675
699
  success: true,
676
700
  data: {
701
+ state: 'active',
677
702
  sessionKey: parsed.sessionKey,
678
703
  sessionId,
679
704
  activeLeafMessageId,
@@ -774,6 +799,16 @@ function registerAgentSessionRoutes(route, base, ctx) {
774
799
  }
775
800
  }, { summary: 'Switch agent session active leaf', tags: ['console', 'agent'] });
776
801
  }
802
+ /** Runtime IM session keys are `<platform>:<endpoint>:<scope>:<sceneId>`. */
803
+ function isRuntimeImSessionKey(value) {
804
+ const first = value.indexOf(':');
805
+ const second = value.indexOf(':', first + 1);
806
+ const third = value.indexOf(':', second + 1);
807
+ return first > 0
808
+ && second > first + 1
809
+ && third > second + 1
810
+ && third < value.length - 1;
811
+ }
777
812
  function parseSessionAction(pathname, prefix, action) {
778
813
  if (!pathname.startsWith(prefix))
779
814
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/host-http",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Minimal HTTP and WebSocket host for Plugin Runtime (no Koa)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -42,6 +42,10 @@ export interface ConsoleRestCtx {
42
42
  readonly started: boolean;
43
43
  readonly models: { get(name: string): unknown };
44
44
  };
45
+ /** Distinguishes a real IM conversation with no Agent turn from a typo key. */
46
+ readonly isKnownConversationSession?: (
47
+ sessionKey: string,
48
+ ) => boolean | undefined | Promise<boolean | undefined>;
45
49
  }
46
50
 
47
51
  /** 内省数据门面 — 由 basic/cli 用 agent 包 collectIntrospection* 装配。 */
@@ -864,9 +868,33 @@ function registerAgentSessionRoutes(
864
868
  try {
865
869
  const sessionId = await runtime.resolveActiveSessionId(parsed.sessionKey);
866
870
  if (!sessionId) {
867
- writeJson(response, 404, {
868
- success: false,
869
- error: `未找到活跃会话:${parsed.sessionKey}`,
871
+ if (!isRuntimeImSessionKey(parsed.sessionKey)) {
872
+ writeJson(response, 404, {
873
+ success: false,
874
+ error: `未找到会话:${parsed.sessionKey}`,
875
+ });
876
+ return;
877
+ }
878
+ const knownConversation = await ctx.isKnownConversationSession?.(parsed.sessionKey);
879
+ if (knownConversation === false) {
880
+ writeJson(response, 404, {
881
+ success: false,
882
+ error: `未找到会话:${parsed.sessionKey}`,
883
+ });
884
+ return;
885
+ }
886
+ // 渠道会话与 Agent 会话的生命周期不同:用户可以先在 Console
887
+ // 选中一个真实渠道会话,而该会话尚未触发过 Agent。树查询是只读操作,
888
+ // 因而将这种正常状态返回为可渲染空态,而不是误报资源不存在。
889
+ writeJson(response, 200, {
890
+ success: true,
891
+ data: {
892
+ state: 'not_started',
893
+ sessionKey: parsed.sessionKey,
894
+ sessionId: null,
895
+ activeLeafMessageId: null,
896
+ points: [],
897
+ },
870
898
  });
871
899
  return;
872
900
  }
@@ -876,6 +904,7 @@ function registerAgentSessionRoutes(
876
904
  writeJson(response, 200, {
877
905
  success: true,
878
906
  data: {
907
+ state: 'active',
879
908
  sessionKey: parsed.sessionKey,
880
909
  sessionId,
881
910
  activeLeafMessageId,
@@ -975,6 +1004,17 @@ function registerAgentSessionRoutes(
975
1004
  }, { summary: 'Switch agent session active leaf', tags: ['console', 'agent'] });
976
1005
  }
977
1006
 
1007
+ /** Runtime IM session keys are `<platform>:<endpoint>:<scope>:<sceneId>`. */
1008
+ function isRuntimeImSessionKey(value: string): boolean {
1009
+ const first = value.indexOf(':');
1010
+ const second = value.indexOf(':', first + 1);
1011
+ const third = value.indexOf(':', second + 1);
1012
+ return first > 0
1013
+ && second > first + 1
1014
+ && third > second + 1
1015
+ && third < value.length - 1;
1016
+ }
1017
+
978
1018
  function parseSessionAction(
979
1019
  pathname: string,
980
1020
  prefix: string,