@beanx/cathygo-web-core 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,10 +21,16 @@ Host applications still own account routing, agent selection, transport setup,
21
21
  selected session id, lightweight session lists, and product-specific shell UI.
22
22
  They should not own a second session execution runtime.
23
23
 
24
+ ## Session Host Helpers (`@0.1.4`)
25
+
26
+ - `buildSessionLoadedAction` / `conversationMessagesToChatMessages`
27
+ - `createSessionEventRouter`
28
+ - `selectCanSend`, `selectCanStop`, `selectActiveTurnId`, `selectSessionStatus`, `selectIsMutating`
29
+
24
30
  ## First vNext Deliverables
25
31
 
26
32
  - Keep the current single-session `ChatState` reducer exported.
27
- - Add `SessionViewState`, session event reducer, and current-session selectors.
33
+ - Session host helpers and selectors (above).
28
34
  - Add reducer tests for interrupt, replay, stop, and optimistic reconciliation.
29
35
  - Prove the implementation in `cathygo-agent/web` before publishing
30
- `@beanx/cathygo-web-core@0.2.0`.
36
+ npm bumps on the `0.1.x` line (`0.2.0` reserved for breaking renames).
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { Dispatch, RefObject } from 'react';
3
- import { AgentActivity, SessionRuntimeSnapshot, LearningTurnEvent, ConversationSummary, GatewayModelStatus } from '@beanx/cathygo-protocol';
3
+ import { AgentActivity, SessionRuntimeSnapshot, LearningTurnEvent, ConversationSummary, GatewayModelStatus, ConversationDetail, ConversationMessage } from '@beanx/cathygo-protocol';
4
4
 
5
5
  type AgentIdentityStatus = {
6
6
  agent_id?: string | null;
@@ -394,4 +394,34 @@ declare function ChatView({ chat, draft, attachments, attachmentPolicy, composer
394
394
 
395
395
  declare function modelStatusText(model: GatewayModelStatus): string;
396
396
 
397
- export { AgentActivityTimeline, type AgentIdentityStatus, type AgentRunProgress, type AgentRunProgressPhase, type AgentRunThinking, CHAT_HOME_MODES, CathyGOChatApp, type CathyGOChatAppProps, type CathyGOChatScreen, type ChatAction, ChatAgentIdentity, type ChatAttachment, type ChatHomeMode, type ChatHomeModeId, ChatHomeView, ChatListView, type ChatMessage$1 as ChatMessage, type ChatMessagePart, ChatMessage as ChatMessageView, type ChatRole, type ChatRuntimeId, ChatRuntimeSelector, type ChatRuntimeSelectorProps, type ChatState, ChatTopBar, ChatTranscript, ChatView, type ComposerAttachmentPolicy, type ComposerFileLike, type ComposerFileRejection, type ComposerFileRejectionReason, type ComposerFileValidationResult, DEFAULT_CHAT_HOME_MODE_ID, DEFAULT_COMPOSER_ATTACHMENT_POLICY, IconBack, IconBrain, IconCalendar, IconChevronDown, IconChevronRight, IconClose, IconCloud, IconCode, IconDevice, IconDevices, IconDocument, IconExternalLink, IconGatewayConnecting, IconGatewayOffline, IconGatewayOnline, IconGithub, IconHome, IconImageUpload, IconInfo, IconLocalComputer, IconMessage, IconMore, IconNewChat, IconPencil, IconPlug, IconSearch, IconSend, IconSettings, IconShield, IconSmartphone, MathMarkdown, MessageComposer, type MessageComposerHandle, type PendingComposerAttachment, RunStatus, type RuntimeOption, ScrollToBottomButton, type UseCathyGOChatResult, agentDisplayName, agentShortId, buildRuntimeOptions, composerAcceptAttribute, findChatHomeMode, fixCommonLatexMistakes, formatBytes, initialChatState, modelStatusText, normalizeComposerAttachmentPolicy, normalizeMathDelimiters, prepareMathMarkdown, reduceChat, stripMathForPreview, useCathyGOChat, validateComposerFiles };
397
+ type RunningTurnsBySession = Record<string, string>;
398
+ declare function eventSessionId(event: LearningTurnEvent): string | undefined;
399
+ declare function eventTurnId(event: LearningTurnEvent): string | undefined;
400
+ declare function shouldApplyEventToRuntime(chat: ChatState | undefined, event: LearningTurnEvent): boolean;
401
+ declare function shouldApplyEventToActiveSession(event: LearningTurnEvent, activeSessionId: string | undefined): boolean;
402
+ declare function isChatStateMutating(chat: ChatState | undefined): boolean;
403
+ declare function selectCanSend(chat: ChatState): boolean;
404
+ declare function selectCanStop(chat: ChatState): boolean;
405
+ declare function selectActiveTurnId(chat: ChatState): string | undefined;
406
+ declare function selectSessionStatus(chat: ChatState): string;
407
+ declare function selectIsMutating(chat: ChatState): boolean;
408
+ declare function updateRunningTurnFromEvent(running: RunningTurnsBySession, event: LearningTurnEvent): RunningTurnsBySession;
409
+ declare function createSessionEventRouter(options: {
410
+ getActiveSessionId: () => string | undefined;
411
+ getChat: () => ChatState;
412
+ dispatchChat: (action: {
413
+ type: 'event.received';
414
+ event: LearningTurnEvent;
415
+ }) => void;
416
+ onTerminalTurn?: (sessionId: string) => void;
417
+ }): (event: LearningTurnEvent) => void;
418
+
419
+ type SessionHydrationOptions = {
420
+ resolveAttachmentUrl?: (uri: string) => string;
421
+ };
422
+ declare function buildSessionLoadedAction(sessionId: string, detail: ConversationDetail, options?: SessionHydrationOptions): Extract<ChatAction, {
423
+ type: 'session.loaded';
424
+ }>;
425
+ declare function conversationMessagesToChatMessages(messages: ConversationMessage[], options?: SessionHydrationOptions): ChatMessage$1[];
426
+
427
+ export { AgentActivityTimeline, type AgentIdentityStatus, type AgentRunProgress, type AgentRunProgressPhase, type AgentRunThinking, CHAT_HOME_MODES, CathyGOChatApp, type CathyGOChatAppProps, type CathyGOChatScreen, type ChatAction, ChatAgentIdentity, type ChatAttachment, type ChatHomeMode, type ChatHomeModeId, ChatHomeView, ChatListView, type ChatMessage$1 as ChatMessage, type ChatMessagePart, ChatMessage as ChatMessageView, type ChatRole, type ChatRuntimeId, ChatRuntimeSelector, type ChatRuntimeSelectorProps, type ChatState, ChatTopBar, ChatTranscript, ChatView, type ComposerAttachmentPolicy, type ComposerFileLike, type ComposerFileRejection, type ComposerFileRejectionReason, type ComposerFileValidationResult, DEFAULT_CHAT_HOME_MODE_ID, DEFAULT_COMPOSER_ATTACHMENT_POLICY, IconBack, IconBrain, IconCalendar, IconChevronDown, IconChevronRight, IconClose, IconCloud, IconCode, IconDevice, IconDevices, IconDocument, IconExternalLink, IconGatewayConnecting, IconGatewayOffline, IconGatewayOnline, IconGithub, IconHome, IconImageUpload, IconInfo, IconLocalComputer, IconMessage, IconMore, IconNewChat, IconPencil, IconPlug, IconSearch, IconSend, IconSettings, IconShield, IconSmartphone, MathMarkdown, MessageComposer, type MessageComposerHandle, type PendingComposerAttachment, RunStatus, type RunningTurnsBySession, type RuntimeOption, ScrollToBottomButton, type SessionHydrationOptions, type UseCathyGOChatResult, agentDisplayName, agentShortId, buildRuntimeOptions, buildSessionLoadedAction, composerAcceptAttribute, conversationMessagesToChatMessages, createSessionEventRouter, eventSessionId, eventTurnId, findChatHomeMode, fixCommonLatexMistakes, formatBytes, initialChatState, isChatStateMutating, modelStatusText, normalizeComposerAttachmentPolicy, normalizeMathDelimiters, prepareMathMarkdown, reduceChat, selectActiveTurnId, selectCanSend, selectCanStop, selectIsMutating, selectSessionStatus, shouldApplyEventToActiveSession, shouldApplyEventToRuntime, stripMathForPreview, updateRunningTurnFromEvent, useCathyGOChat, validateComposerFiles };
package/dist/index.js CHANGED
@@ -2800,6 +2800,131 @@ function RuntimeIcon({ kind }) {
2800
2800
  const className = "chat-runtime-icon";
2801
2801
  return kind === "cloud" ? /* @__PURE__ */ jsx15(IconCloud, { className }) : /* @__PURE__ */ jsx15(IconLocalComputer, { className });
2802
2802
  }
2803
+
2804
+ // src/session-host/session-runtime.ts
2805
+ var TERMINAL_TURN_EVENTS = /* @__PURE__ */ new Set(["turn.completed", "turn.failed", "turn.cancelled"]);
2806
+ function eventSessionId(event) {
2807
+ return optionalString2(event.payload.session_id);
2808
+ }
2809
+ function eventTurnId(event) {
2810
+ return optionalString2(event.payload.turn_id);
2811
+ }
2812
+ function shouldApplyEventToRuntime(chat, event) {
2813
+ const turnId = eventTurnId(event);
2814
+ if (!turnId || event.event === "session.input.accepted") return true;
2815
+ if (!isTurnScopedRuntimeEvent(event.event)) return true;
2816
+ const activeTurnId = chat?.activeTurnId;
2817
+ return !activeTurnId || activeTurnId === turnId;
2818
+ }
2819
+ function shouldApplyEventToActiveSession(event, activeSessionId) {
2820
+ const sessionId = eventSessionId(event);
2821
+ if (!sessionId) return false;
2822
+ if (!activeSessionId) return false;
2823
+ return sessionId === activeSessionId;
2824
+ }
2825
+ function isChatStateMutating(chat) {
2826
+ if (!chat) return false;
2827
+ return Boolean(chat.activeTurnId) || chat.status === "Sending" || chat.status === "Thinking" || chat.status === "Streaming" || chat.status === "Stopping";
2828
+ }
2829
+ function selectCanSend(chat) {
2830
+ return chat.status !== "Loading" && chat.status !== "Disconnected" && chat.status !== "Error";
2831
+ }
2832
+ function selectCanStop(chat) {
2833
+ return Boolean(chat.activeTurnId) || chat.status === "Thinking" || chat.status === "Streaming" || chat.status === "Stopping";
2834
+ }
2835
+ function selectActiveTurnId(chat) {
2836
+ return chat.activeTurnId;
2837
+ }
2838
+ function selectSessionStatus(chat) {
2839
+ return chat.status;
2840
+ }
2841
+ function selectIsMutating(chat) {
2842
+ return isChatStateMutating(chat);
2843
+ }
2844
+ function updateRunningTurnFromEvent(running, event) {
2845
+ const sessionId = eventSessionId(event);
2846
+ const turnId = eventTurnId(event);
2847
+ if (!sessionId || !turnId) return running;
2848
+ if (TERMINAL_TURN_EVENTS.has(event.event)) {
2849
+ if (!running[sessionId] || running[sessionId] === turnId) {
2850
+ const next = { ...running };
2851
+ delete next[sessionId];
2852
+ return next;
2853
+ }
2854
+ return running;
2855
+ }
2856
+ if (event.event === "turn.started" || event.event === "assistant.delta") {
2857
+ if (running[sessionId] === turnId) return running;
2858
+ return { ...running, [sessionId]: turnId };
2859
+ }
2860
+ return running;
2861
+ }
2862
+ function createSessionEventRouter(options) {
2863
+ return (event) => {
2864
+ const sessionId = eventSessionId(event);
2865
+ if (shouldApplyEventToActiveSession(event, options.getActiveSessionId()) && shouldApplyEventToRuntime(options.getChat(), event)) {
2866
+ options.dispatchChat({ type: "event.received", event });
2867
+ }
2868
+ if (sessionId && TERMINAL_TURN_EVENTS.has(event.event)) {
2869
+ options.onTerminalTurn?.(sessionId);
2870
+ }
2871
+ };
2872
+ }
2873
+ function isTurnScopedRuntimeEvent(event) {
2874
+ return event === "turn.started" || event === "assistant.delta" || event === "assistant.completed" || event === "turn.completed" || event === "turn.cancelled" || event === "turn.failed" || event === "agent.activity.started" || event === "agent.activity.updated" || event === "agent.activity.completed" || event === "agent.progress.delta";
2875
+ }
2876
+ function optionalString2(value) {
2877
+ if (value === void 0 || value === null) return void 0;
2878
+ const text = String(value).trim();
2879
+ return text || void 0;
2880
+ }
2881
+
2882
+ // src/session-host/hydration.ts
2883
+ function buildSessionLoadedAction(sessionId, detail, options = {}) {
2884
+ return {
2885
+ type: "session.loaded",
2886
+ sessionId,
2887
+ messages: conversationMessagesToChatMessages(detail.messages, options),
2888
+ activities: detail.activities ?? [],
2889
+ runtime: detail.runtime ?? detail.session.runtime
2890
+ };
2891
+ }
2892
+ function conversationMessagesToChatMessages(messages, options = {}) {
2893
+ return messages.map((message) => ({
2894
+ id: message.id,
2895
+ role: message.role,
2896
+ content: message.content,
2897
+ parts: normalizeMessageParts(message.parts, options.resolveAttachmentUrl),
2898
+ turnId: message.turn_id ?? void 0,
2899
+ clientInputId: messageMetadataString(message.metadata, "client_input_id"),
2900
+ clientTurnId: messageMetadataString(message.metadata, "client_turn_id"),
2901
+ status: "done"
2902
+ }));
2903
+ }
2904
+ function normalizeMessageParts(parts, resolveAttachmentUrl) {
2905
+ const normalized = parts?.map((part) => {
2906
+ if (part.type === "text" && part.text) {
2907
+ return { type: "text", text: part.text };
2908
+ }
2909
+ if (part.type === "image" && part.attachment_id && part.attachment) {
2910
+ const uri = part.attachment.uri;
2911
+ return {
2912
+ type: "image",
2913
+ attachment_id: part.attachment_id,
2914
+ attachment: {
2915
+ ...part.attachment,
2916
+ uri: uri && resolveAttachmentUrl ? resolveAttachmentUrl(uri) : uri
2917
+ }
2918
+ };
2919
+ }
2920
+ return void 0;
2921
+ }).filter((part) => Boolean(part));
2922
+ return normalized?.length ? normalized : void 0;
2923
+ }
2924
+ function messageMetadataString(metadata, key) {
2925
+ const value = metadata?.[key];
2926
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2927
+ }
2803
2928
  export {
2804
2929
  AgentActivityTimeline,
2805
2930
  CHAT_HOME_MODES,
@@ -2851,17 +2976,31 @@ export {
2851
2976
  agentDisplayName,
2852
2977
  agentShortId,
2853
2978
  buildRuntimeOptions,
2979
+ buildSessionLoadedAction,
2854
2980
  composerAcceptAttribute,
2981
+ conversationMessagesToChatMessages,
2982
+ createSessionEventRouter,
2983
+ eventSessionId,
2984
+ eventTurnId,
2855
2985
  findChatHomeMode,
2856
2986
  fixCommonLatexMistakes,
2857
2987
  formatBytes,
2858
2988
  initialChatState,
2989
+ isChatStateMutating,
2859
2990
  modelStatusText,
2860
2991
  normalizeComposerAttachmentPolicy,
2861
2992
  normalizeMathDelimiters,
2862
2993
  prepareMathMarkdown,
2863
2994
  reduceChat,
2995
+ selectActiveTurnId,
2996
+ selectCanSend,
2997
+ selectCanStop,
2998
+ selectIsMutating,
2999
+ selectSessionStatus,
3000
+ shouldApplyEventToActiveSession,
3001
+ shouldApplyEventToRuntime,
2864
3002
  stripMathForPreview,
3003
+ updateRunningTurnFromEvent,
2865
3004
  useCathyGOChat,
2866
3005
  validateComposerFiles
2867
3006
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beanx/cathygo-web-core",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -16,7 +16,7 @@
16
16
  "./styles.css": "./dist/styles.css"
17
17
  },
18
18
  "dependencies": {
19
- "@beanx/cathygo-protocol": "0.1.2",
19
+ "@beanx/cathygo-protocol": "0.1.5",
20
20
  "@streamdown/math": "^1.0.2",
21
21
  "katex": "^0.16.47",
22
22
  "streamdown": "^2.5.0"