@optima-chat/agentic-sdk 0.1.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.
Files changed (73) hide show
  1. package/dist/client/conversation-api.d.ts +23 -0
  2. package/dist/client/conversation-api.d.ts.map +1 -0
  3. package/dist/client/conversation-api.js +207 -0
  4. package/dist/client/conversation-api.js.map +1 -0
  5. package/dist/client/error-mapper.d.ts +5 -0
  6. package/dist/client/error-mapper.d.ts.map +1 -0
  7. package/dist/client/error-mapper.js +19 -0
  8. package/dist/client/error-mapper.js.map +1 -0
  9. package/dist/client/event-parser.d.ts +79 -0
  10. package/dist/client/event-parser.d.ts.map +1 -0
  11. package/dist/client/event-parser.js +219 -0
  12. package/dist/client/event-parser.js.map +1 -0
  13. package/dist/client/gateway-client.d.ts +45 -0
  14. package/dist/client/gateway-client.d.ts.map +1 -0
  15. package/dist/client/gateway-client.js +172 -0
  16. package/dist/client/gateway-client.js.map +1 -0
  17. package/dist/hooks/use-approval.d.ts +8 -0
  18. package/dist/hooks/use-approval.d.ts.map +1 -0
  19. package/dist/hooks/use-approval.js +39 -0
  20. package/dist/hooks/use-approval.js.map +1 -0
  21. package/dist/hooks/use-connection-state.d.ts +7 -0
  22. package/dist/hooks/use-connection-state.d.ts.map +1 -0
  23. package/dist/hooks/use-connection-state.js +12 -0
  24. package/dist/hooks/use-connection-state.js.map +1 -0
  25. package/dist/hooks/use-conversations.d.ts +12 -0
  26. package/dist/hooks/use-conversations.d.ts.map +1 -0
  27. package/dist/hooks/use-conversations.js +42 -0
  28. package/dist/hooks/use-conversations.js.map +1 -0
  29. package/dist/hooks/use-current-chat.d.ts +14 -0
  30. package/dist/hooks/use-current-chat.d.ts.map +1 -0
  31. package/dist/hooks/use-current-chat.js +142 -0
  32. package/dist/hooks/use-current-chat.js.map +1 -0
  33. package/dist/hooks/use-question.d.ts +7 -0
  34. package/dist/hooks/use-question.d.ts.map +1 -0
  35. package/dist/hooks/use-question.js +17 -0
  36. package/dist/hooks/use-question.js.map +1 -0
  37. package/dist/hooks/use-session.d.ts +7 -0
  38. package/dist/hooks/use-session.d.ts.map +1 -0
  39. package/dist/hooks/use-session.js +13 -0
  40. package/dist/hooks/use-session.js.map +1 -0
  41. package/dist/hooks/use-switch-config.d.ts +7 -0
  42. package/dist/hooks/use-switch-config.d.ts.map +1 -0
  43. package/dist/hooks/use-switch-config.js +30 -0
  44. package/dist/hooks/use-switch-config.js.map +1 -0
  45. package/dist/index.d.ts +13 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +12 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/provider/chat-context.d.ts +14 -0
  50. package/dist/provider/chat-context.d.ts.map +1 -0
  51. package/dist/provider/chat-context.js +10 -0
  52. package/dist/provider/chat-context.js.map +1 -0
  53. package/dist/provider/chat-provider.d.ts +16 -0
  54. package/dist/provider/chat-provider.d.ts.map +1 -0
  55. package/dist/provider/chat-provider.js +200 -0
  56. package/dist/provider/chat-provider.js.map +1 -0
  57. package/dist/store/chat-store.d.ts +65 -0
  58. package/dist/store/chat-store.d.ts.map +1 -0
  59. package/dist/store/chat-store.js +220 -0
  60. package/dist/store/chat-store.js.map +1 -0
  61. package/dist/types.d.ts +152 -0
  62. package/dist/types.d.ts.map +1 -0
  63. package/dist/types.js +10 -0
  64. package/dist/types.js.map +1 -0
  65. package/dist/workspace/default-provider.d.ts +14 -0
  66. package/dist/workspace/default-provider.d.ts.map +1 -0
  67. package/dist/workspace/default-provider.js +46 -0
  68. package/dist/workspace/default-provider.js.map +1 -0
  69. package/dist/workspace/types.d.ts +11 -0
  70. package/dist/workspace/types.d.ts.map +1 -0
  71. package/dist/workspace/types.js +2 -0
  72. package/dist/workspace/types.js.map +1 -0
  73. package/package.json +49 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * WebSocket client for the Optima gateway. Handles connect/reconnect,
3
+ * heartbeat, token-refresh signalling, and event dispatch. Does not own any
4
+ * state — everything flows out via the callbacks.
5
+ */
6
+ export class GatewayClient {
7
+ options;
8
+ ws = null;
9
+ heartbeatTimer = null;
10
+ reconnectTimer = null;
11
+ reconnectAttempt = 0;
12
+ intentionalDisconnect = false;
13
+ reconnectConfig;
14
+ heartbeatInterval;
15
+ constructor(options) {
16
+ this.options = options;
17
+ this.reconnectConfig = {
18
+ maxRetries: options.reconnectOptions?.maxRetries ?? 5,
19
+ baseDelay: options.reconnectOptions?.baseDelay ?? 2000,
20
+ maxDelay: options.reconnectOptions?.maxDelay ?? 30000,
21
+ };
22
+ this.heartbeatInterval = options.heartbeatInterval ?? 30000;
23
+ }
24
+ async connect() {
25
+ this.intentionalDisconnect = false;
26
+ this.options.onConnectionStateChange('connecting');
27
+ await this.openSocket();
28
+ }
29
+ disconnect() {
30
+ this.intentionalDisconnect = true;
31
+ this.stopHeartbeat();
32
+ if (this.reconnectTimer !== null) {
33
+ clearTimeout(this.reconnectTimer);
34
+ this.reconnectTimer = null;
35
+ }
36
+ if (this.ws) {
37
+ try {
38
+ this.ws.close();
39
+ }
40
+ catch {
41
+ /* noop */
42
+ }
43
+ this.ws = null;
44
+ }
45
+ this.options.onConnectionStateChange('disconnected');
46
+ }
47
+ /** Returns true if the event was dispatched, false otherwise. */
48
+ send(event) {
49
+ const transformed = this.options.onBeforeSend
50
+ ? this.options.onBeforeSend(event)
51
+ : event;
52
+ if (transformed === null)
53
+ return false;
54
+ const ws = this.ws;
55
+ if (!ws || ws.readyState !== 1 /* OPEN */)
56
+ return false;
57
+ ws.send(JSON.stringify(transformed));
58
+ return true;
59
+ }
60
+ /** Exposed so ChatProvider can trigger token refresh manually if needed. */
61
+ async handleTokenRefresh() {
62
+ try {
63
+ const token = await this.options.tokenProvider();
64
+ this.send({
65
+ type: 'update_token',
66
+ token,
67
+ user: { userId: '' },
68
+ });
69
+ }
70
+ catch (err) {
71
+ this.options.onAuthError({
72
+ code: 'auth_expired',
73
+ message: err instanceof Error ? err.message : 'Token provider failed',
74
+ });
75
+ this.disconnect();
76
+ this.options.onConnectionStateChange('auth_failed');
77
+ }
78
+ }
79
+ // ---- internals ----
80
+ async openSocket() {
81
+ let token;
82
+ try {
83
+ token = await this.options.tokenProvider();
84
+ }
85
+ catch (err) {
86
+ this.options.onAuthError({
87
+ code: 'auth_expired',
88
+ message: err instanceof Error ? err.message : 'Token fetch failed',
89
+ });
90
+ this.options.onConnectionStateChange('auth_failed');
91
+ return;
92
+ }
93
+ const separator = this.options.gatewayUrl.includes('?') ? '&' : '?';
94
+ const url = `${this.options.gatewayUrl}${separator}token=${encodeURIComponent(token)}`;
95
+ const ws = new WebSocket(url);
96
+ this.ws = ws;
97
+ await new Promise((resolve) => {
98
+ ws.onopen = () => {
99
+ this.reconnectAttempt = 0;
100
+ this.options.onConnectionStateChange('connected');
101
+ this.startHeartbeat();
102
+ resolve();
103
+ };
104
+ ws.onclose = () => {
105
+ this.stopHeartbeat();
106
+ if (this.intentionalDisconnect) {
107
+ this.options.onConnectionStateChange('disconnected');
108
+ return;
109
+ }
110
+ if (this.reconnectAttempt >= this.reconnectConfig.maxRetries) {
111
+ this.options.onConnectionStateChange('disconnected');
112
+ this.options.onError({
113
+ code: 'reconnect_exhausted',
114
+ message: 'WebSocket reconnect retries exhausted',
115
+ retryable: false,
116
+ });
117
+ return;
118
+ }
119
+ this.options.onConnectionStateChange('reconnecting');
120
+ this.scheduleReconnect();
121
+ // Resolve so the caller's connect() promise doesn't hang forever; the
122
+ // consumer observes the state change via the callback.
123
+ resolve();
124
+ };
125
+ ws.onerror = () => {
126
+ // `onclose` will follow; handle reconnect there.
127
+ };
128
+ ws.onmessage = (ev) => this.handleMessage(ev);
129
+ });
130
+ }
131
+ handleMessage(ev) {
132
+ let event;
133
+ try {
134
+ event = JSON.parse(String(ev.data));
135
+ }
136
+ catch {
137
+ return;
138
+ }
139
+ // Always forward to consumer — they may route it to rawEvent.
140
+ this.options.onEvent(event);
141
+ // Internal handling: token_refresh_needed triggers a refresh+send cycle.
142
+ if (event.type === 'token_refresh_needed') {
143
+ void this.handleTokenRefresh();
144
+ }
145
+ }
146
+ scheduleReconnect() {
147
+ const attempt = this.reconnectAttempt;
148
+ this.reconnectAttempt = attempt + 1;
149
+ const base = Math.min(this.reconnectConfig.baseDelay * Math.pow(2, attempt), this.reconnectConfig.maxDelay);
150
+ // Jitter: scale by random factor in [0.5, 1.0].
151
+ const delay = base * (0.5 + Math.random() * 0.5);
152
+ this.reconnectTimer = setTimeout(() => {
153
+ this.reconnectTimer = null;
154
+ void this.openSocket();
155
+ }, delay);
156
+ }
157
+ startHeartbeat() {
158
+ this.stopHeartbeat();
159
+ this.heartbeatTimer = setInterval(() => {
160
+ if (this.ws && this.ws.readyState === 1 /* OPEN */) {
161
+ this.send({ type: 'ping' });
162
+ }
163
+ }, this.heartbeatInterval);
164
+ }
165
+ stopHeartbeat() {
166
+ if (this.heartbeatTimer !== null) {
167
+ clearInterval(this.heartbeatTimer);
168
+ this.heartbeatTimer = null;
169
+ }
170
+ }
171
+ }
172
+ //# sourceMappingURL=gateway-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-client.js","sourceRoot":"","sources":["../../src/client/gateway-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ApprovalRequestWithId } from '../types.js';
2
+ export declare function useApproval(): {
3
+ pendingApprovals: ApprovalRequestWithId[];
4
+ approve: (requestId: string) => void;
5
+ reject: (requestId: string, reason?: string) => void;
6
+ modify: (requestId: string, modifiedArgs: Record<string, unknown>, message?: string) => void;
7
+ };
8
+ //# sourceMappingURL=use-approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-approval.d.ts","sourceRoot":"","sources":["../../src/hooks/use-approval.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,wBAAgB,WAAW,IAAI;IAC7B,gBAAgB,EAAE,qBAAqB,EAAE,CAAC;IAC1C,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,MAAM,EAAE,CACN,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,OAAO,CAAC,EAAE,MAAM,KACb,IAAI,CAAC;CACX,CAmDA"}
@@ -0,0 +1,39 @@
1
+ import { useCallback } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import { useChatContext } from '../provider/chat-context.js';
4
+ export function useApproval() {
5
+ const { store, client } = useChatContext();
6
+ const pendingApprovals = useStore(store, (s) => s.pendingApprovals);
7
+ const approve = useCallback((requestId) => {
8
+ client.send({
9
+ type: 'approval_response',
10
+ approval: { requestId, decision: 'approved' },
11
+ });
12
+ store.getState().removePendingApproval(requestId);
13
+ }, [client, store]);
14
+ const reject = useCallback((requestId, reason) => {
15
+ client.send({
16
+ type: 'approval_response',
17
+ approval: {
18
+ requestId,
19
+ decision: 'denied',
20
+ ...(reason !== undefined ? { message: reason } : {}),
21
+ },
22
+ });
23
+ store.getState().removePendingApproval(requestId);
24
+ }, [client, store]);
25
+ const modify = useCallback((requestId, modifiedArgs, message) => {
26
+ client.send({
27
+ type: 'approval_response',
28
+ approval: {
29
+ requestId,
30
+ decision: 'modified',
31
+ modifiedArgs,
32
+ ...(message !== undefined ? { message } : {}),
33
+ },
34
+ });
35
+ store.getState().removePendingApproval(requestId);
36
+ }, [client, store]);
37
+ return { pendingApprovals, approve, reject, modify };
38
+ }
39
+ //# sourceMappingURL=use-approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-approval.js","sourceRoot":"","sources":["../../src/hooks/use-approval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,UAAU,WAAW;IAUzB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC3C,MAAM,gBAAgB,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAEpE,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,SAAiB,EAAE,EAAE;QACpB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;SAC9C,CAAC,CAAC;QACH,KAAK,CAAC,QAAQ,EAAE,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,SAAiB,EAAE,MAAe,EAAE,EAAE;QACrC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE;gBACR,SAAS;gBACT,QAAQ,EAAE,QAAQ;gBAClB,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD;SACF,CAAC,CAAC;QACH,KAAK,CAAC,QAAQ,EAAE,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,MAAM,MAAM,GAAG,WAAW,CACxB,CACE,SAAiB,EACjB,YAAqC,EACrC,OAAgB,EAChB,EAAE;QACF,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE;gBACR,SAAS;gBACT,QAAQ,EAAE,UAAU;gBACpB,YAAY;gBACZ,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9C;SACF,CAAC,CAAC;QACH,KAAK,CAAC,QAAQ,EAAE,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACvD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ChatError, ConnectionState } from '../types.js';
2
+ export declare function useConnectionState(): {
3
+ connectionState: ConnectionState;
4
+ error: ChatError | null;
5
+ reconnectAttempt: number;
6
+ };
7
+ //# sourceMappingURL=use-connection-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-connection-state.d.ts","sourceRoot":"","sources":["../../src/hooks/use-connection-state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9D,wBAAgB,kBAAkB,IAAI;IACpC,eAAe,EAAE,eAAe,CAAC;IACjC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAUA"}
@@ -0,0 +1,12 @@
1
+ import { useStore } from 'zustand';
2
+ import { useShallow } from 'zustand/react/shallow';
3
+ import { useChatContext } from '../provider/chat-context.js';
4
+ export function useConnectionState() {
5
+ const { store } = useChatContext();
6
+ return useStore(store, useShallow((s) => ({
7
+ connectionState: s.connectionState,
8
+ error: s.connectionError,
9
+ reconnectAttempt: s.reconnectAttempt,
10
+ })));
11
+ }
12
+ //# sourceMappingURL=use-connection-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-connection-state.js","sourceRoot":"","sources":["../../src/hooks/use-connection-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,UAAU,kBAAkB;IAKhC,MAAM,EAAE,KAAK,EAAE,GAAG,cAAc,EAAE,CAAC;IACnC,OAAO,QAAQ,CACb,KAAK,EACL,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjB,eAAe,EAAE,CAAC,CAAC,eAAe;QAClC,KAAK,EAAE,CAAC,CAAC,eAAe;QACxB,gBAAgB,EAAE,CAAC,CAAC,gBAAgB;KACrC,CAAC,CAAC,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ChatError, Conversation } from '../types.js';
2
+ export declare function useConversations(): {
3
+ conversations: Conversation[];
4
+ currentConversationId: string | null;
5
+ isLoading: boolean;
6
+ error: ChatError | null;
7
+ createConversation: (title?: string) => Promise<Conversation>;
8
+ deleteConversation: (conversationId: string) => Promise<void>;
9
+ renameConversation: (conversationId: string, title: string) => Promise<void>;
10
+ switchConversation: (conversationId: string) => void;
11
+ };
12
+ //# sourceMappingURL=use-conversations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversations.d.ts","sourceRoot":"","sources":["../../src/hooks/use-conversations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3D,wBAAgB,gBAAgB,IAAI;IAClC,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,kBAAkB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9D,kBAAkB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,kBAAkB,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,kBAAkB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD,CAwDA"}
@@ -0,0 +1,42 @@
1
+ import { useCallback } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import { useShallow } from 'zustand/react/shallow';
4
+ import { useChatContext } from '../provider/chat-context.js';
5
+ export function useConversations() {
6
+ const { store, client, api } = useChatContext();
7
+ const state = useStore(store, useShallow((s) => ({
8
+ conversations: s.conversations,
9
+ currentConversationId: s.currentConversationId,
10
+ isLoading: s.conversationsLoading,
11
+ error: s.conversationsError,
12
+ })));
13
+ const createConversation = useCallback(async (title) => {
14
+ const conversation = await api.createConversation(title);
15
+ store.getState().addConversation(conversation);
16
+ return conversation;
17
+ }, [api, store]);
18
+ // Delete/rename go through the WebSocket — gateway persists and re-broadcasts.
19
+ const deleteConversation = useCallback(async (conversationId) => {
20
+ client.send({ type: 'delete_conversation', conversation_id: conversationId });
21
+ store.getState().removeConversation(conversationId);
22
+ }, [client, store]);
23
+ const renameConversation = useCallback(async (conversationId, title) => {
24
+ client.send({
25
+ type: 'rename_conversation',
26
+ conversation_id: conversationId,
27
+ title,
28
+ });
29
+ store.getState().updateConversationTitle(conversationId, title);
30
+ }, [client, store]);
31
+ const switchConversation = useCallback((conversationId) => {
32
+ store.getState().setCurrentConversationId(conversationId);
33
+ }, [store]);
34
+ return {
35
+ ...state,
36
+ createConversation,
37
+ deleteConversation,
38
+ renameConversation,
39
+ switchConversation,
40
+ };
41
+ }
42
+ //# sourceMappingURL=use-conversations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversations.js","sourceRoot":"","sources":["../../src/hooks/use-conversations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,UAAU,gBAAgB;IAU9B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,QAAQ,CACpB,KAAK,EACL,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjB,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,qBAAqB,EAAE,CAAC,CAAC,qBAAqB;QAC9C,SAAS,EAAE,CAAC,CAAC,oBAAoB;QACjC,KAAK,EAAE,CAAC,CAAC,kBAAkB;KAC5B,CAAC,CAAC,CACJ,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CACpC,KAAK,EAAE,KAAc,EAAE,EAAE;QACvB,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACzD,KAAK,CAAC,QAAQ,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;QAC/C,OAAO,YAAY,CAAC;IACtB,CAAC,EACD,CAAC,GAAG,EAAE,KAAK,CAAC,CACb,CAAC;IAEF,+EAA+E;IAC/E,MAAM,kBAAkB,GAAG,WAAW,CACpC,KAAK,EAAE,cAAsB,EAAE,EAAE;QAC/B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAC;QAC9E,KAAK,CAAC,QAAQ,EAAE,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACtD,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CACpC,KAAK,EAAE,cAAsB,EAAE,KAAa,EAAE,EAAE;QAC9C,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,qBAAqB;YAC3B,eAAe,EAAE,cAAc;YAC/B,KAAK;SACN,CAAC,CAAC;QACH,KAAK,CAAC,QAAQ,EAAE,CAAC,uBAAuB,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,cAAsB,EAAE,EAAE;QACzB,KAAK,CAAC,QAAQ,EAAE,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;IAC5D,CAAC,EACD,CAAC,KAAK,CAAC,CACR,CAAC;IAEF,OAAO;QACL,GAAG,KAAK;QACR,kBAAkB;QAClB,kBAAkB;QAClB,kBAAkB;QAClB,kBAAkB;KACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ChatError, Message, SendMessageOptions } from '../types.js';
2
+ export declare function useCurrentChat(): {
3
+ messages: Message[];
4
+ isStreaming: boolean;
5
+ isThinking: boolean;
6
+ error: ChatError | null;
7
+ sendMessage: (content: string, options?: SendMessageOptions) => Promise<void>;
8
+ abort: () => void;
9
+ resetConversation: () => Promise<void>;
10
+ loadHistory: () => Promise<void>;
11
+ hasMoreHistory: boolean;
12
+ isLoadingHistory: boolean;
13
+ };
14
+ //# sourceMappingURL=use-current-chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-current-chat.d.ts","sourceRoot":"","sources":["../../src/hooks/use-current-chat.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAQrB,wBAAgB,cAAc,IAAI;IAChC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAgJA"}
@@ -0,0 +1,142 @@
1
+ import { useCallback } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import { useShallow } from 'zustand/react/shallow';
4
+ import { useChatContext } from '../provider/chat-context.js';
5
+ // Stable empty-array reference for missing message lists — avoids creating
6
+ // new array references in the selector (which would break shallow equality
7
+ // and, under React 19, trigger "getSnapshot should be cached" warnings).
8
+ const EMPTY_MESSAGES = [];
9
+ Object.freeze(EMPTY_MESSAGES);
10
+ export function useCurrentChat() {
11
+ const { store, client, api, workspaceProvider } = useChatContext();
12
+ const conversationId = useStore(store, (s) => s.currentConversationId);
13
+ const state = useStore(store, useShallow((s) => {
14
+ const id = s.currentConversationId;
15
+ return {
16
+ messages: id ? (s.messages[id] ?? EMPTY_MESSAGES) : EMPTY_MESSAGES,
17
+ isStreaming: s.isStreaming,
18
+ isThinking: s.isThinking,
19
+ error: s.currentChatError,
20
+ hasMoreHistory: id ? (s.hasMoreHistory[id] ?? true) : false,
21
+ isLoadingHistory: s.historyLoading,
22
+ };
23
+ }));
24
+ const sendMessage = useCallback(async (content, options) => {
25
+ if (!conversationId)
26
+ throw new Error('No active conversation');
27
+ const contentParts = { text: content };
28
+ const attachments = [];
29
+ if (options?.images?.length) {
30
+ if (!workspaceProvider) {
31
+ throw new Error('workspaceProvider is required to send images');
32
+ }
33
+ const results = await workspaceProvider.uploadFiles(options.images);
34
+ contentParts.images = results.map((r) => ({
35
+ url: r.url,
36
+ mediaType: r.mediaType,
37
+ }));
38
+ for (const r of results) {
39
+ attachments.push({
40
+ type: 'image',
41
+ url: r.url,
42
+ name: r.originalName,
43
+ mediaType: r.mediaType,
44
+ });
45
+ }
46
+ }
47
+ if (options?.files?.length) {
48
+ if (!workspaceProvider) {
49
+ throw new Error('workspaceProvider is required to send files');
50
+ }
51
+ const results = await workspaceProvider.uploadFiles(options.files);
52
+ contentParts.files = results.map((r) => ({
53
+ url: r.url,
54
+ filename: r.originalName,
55
+ mediaType: r.mediaType,
56
+ }));
57
+ for (const r of results) {
58
+ attachments.push({
59
+ type: 'file',
60
+ url: r.url,
61
+ name: r.originalName,
62
+ mediaType: r.mediaType,
63
+ });
64
+ }
65
+ }
66
+ if (options?.audio?.length) {
67
+ if (!workspaceProvider) {
68
+ throw new Error('workspaceProvider is required to send audio');
69
+ }
70
+ const results = await workspaceProvider.uploadFiles(options.audio);
71
+ for (const r of results) {
72
+ attachments.push({
73
+ type: 'audio',
74
+ url: r.url,
75
+ name: r.originalName,
76
+ mediaType: r.mediaType,
77
+ });
78
+ }
79
+ }
80
+ const userMessageId = crypto.randomUUID();
81
+ store.getState().addMessage(conversationId, {
82
+ id: userMessageId,
83
+ conversationId,
84
+ role: 'user',
85
+ content,
86
+ toolCalls: [],
87
+ ...(attachments.length > 0 ? { attachments } : {}),
88
+ status: 'complete',
89
+ createdAt: Date.now(),
90
+ });
91
+ const sent = client.send({
92
+ type: 'message',
93
+ conversation_id: conversationId,
94
+ content,
95
+ contentParts,
96
+ ...(options?.metadata !== undefined ? { metadata: options.metadata } : {}),
97
+ });
98
+ if (!sent)
99
+ throw new Error('Failed to send message');
100
+ store.getState().setThinking(true);
101
+ }, [conversationId, client, store, workspaceProvider]);
102
+ const abort = useCallback(() => {
103
+ if (!conversationId)
104
+ return;
105
+ client.send({ type: 'abort', conversation_id: conversationId });
106
+ }, [conversationId, client]);
107
+ const resetConversation = useCallback(async () => {
108
+ if (!conversationId)
109
+ return;
110
+ client.send({ type: 'reset_conversation', conversation_id: conversationId });
111
+ }, [conversationId, client]);
112
+ const loadHistory = useCallback(async () => {
113
+ if (!conversationId)
114
+ return;
115
+ if (state.isLoadingHistory || !state.hasMoreHistory)
116
+ return;
117
+ store.getState().setHistoryLoading(true);
118
+ try {
119
+ const offset = store.getState().historyOffset[conversationId] ?? 0;
120
+ const messages = await api.getMessages(conversationId, {
121
+ skip: offset,
122
+ take: 50,
123
+ });
124
+ store.getState().prependMessages(conversationId, messages);
125
+ store
126
+ .getState()
127
+ .setHistoryOffset(conversationId, offset + messages.length);
128
+ store.getState().setHasMoreHistory(conversationId, messages.length === 50);
129
+ }
130
+ finally {
131
+ store.getState().setHistoryLoading(false);
132
+ }
133
+ }, [conversationId, api, store, state.isLoadingHistory, state.hasMoreHistory]);
134
+ return {
135
+ ...state,
136
+ sendMessage,
137
+ abort,
138
+ resetConversation,
139
+ loadHistory,
140
+ };
141
+ }
142
+ //# sourceMappingURL=use-current-chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-current-chat.js","sourceRoot":"","sources":["../../src/hooks/use-current-chat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { QuestionRequest } from '../types.js';
2
+ export declare function useQuestion(): {
3
+ pendingQuestion: QuestionRequest | null;
4
+ answerQuestion: (requestId: string, answers: Record<string, string>) => void;
5
+ dismissQuestion: (requestId: string) => void;
6
+ };
7
+ //# sourceMappingURL=use-question.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-question.d.ts","sourceRoot":"","sources":["../../src/hooks/use-question.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,wBAAgB,WAAW,IAAI;IAC7B,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7E,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,CAqBA"}
@@ -0,0 +1,17 @@
1
+ import { useCallback } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import { useChatContext } from '../provider/chat-context.js';
4
+ export function useQuestion() {
5
+ const { store, client } = useChatContext();
6
+ const pendingQuestion = useStore(store, (s) => s.pendingQuestion);
7
+ const answerQuestion = useCallback((requestId, answers) => {
8
+ client.send({ type: 'answer_question', request_id: requestId, answers });
9
+ store.getState().setPendingQuestion(null);
10
+ }, [client, store]);
11
+ const dismissQuestion = useCallback((requestId) => {
12
+ client.send({ type: 'answer_question', request_id: requestId, answers: {} });
13
+ store.getState().setPendingQuestion(null);
14
+ }, [client, store]);
15
+ return { pendingQuestion, answerQuestion, dismissQuestion };
16
+ }
17
+ //# sourceMappingURL=use-question.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-question.js","sourceRoot":"","sources":["../../src/hooks/use-question.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,UAAU,WAAW;IAKzB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC3C,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;IAElE,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,SAAiB,EAAE,OAA+B,EAAE,EAAE;QACrD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QACzE,KAAK,CAAC,QAAQ,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,MAAM,eAAe,GAAG,WAAW,CACjC,CAAC,SAAiB,EAAE,EAAE;QACpB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7E,KAAK,CAAC,QAAQ,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,CAAC,CAChB,CAAC;IAEF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function useSession(): {
2
+ sessionId: string | null;
3
+ userId: string | null;
4
+ provider: string | null;
5
+ model: string | null;
6
+ };
7
+ //# sourceMappingURL=use-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-session.d.ts","sourceRoot":"","sources":["../../src/hooks/use-session.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAWA"}
@@ -0,0 +1,13 @@
1
+ import { useStore } from 'zustand';
2
+ import { useShallow } from 'zustand/react/shallow';
3
+ import { useChatContext } from '../provider/chat-context.js';
4
+ export function useSession() {
5
+ const { store } = useChatContext();
6
+ return useStore(store, useShallow((s) => ({
7
+ sessionId: s.sessionId,
8
+ userId: s.userId,
9
+ provider: s.provider,
10
+ model: s.model,
11
+ })));
12
+ }
13
+ //# sourceMappingURL=use-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-session.js","sourceRoot":"","sources":["../../src/hooks/use-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,UAAU,UAAU;IAMxB,MAAM,EAAE,KAAK,EAAE,GAAG,cAAc,EAAE,CAAC;IACnC,OAAO,QAAQ,CACb,KAAK,EACL,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC,CAAC,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function useSwitchConfig(): {
2
+ switchConfig: (config: {
3
+ provider?: string;
4
+ model?: string;
5
+ }) => void;
6
+ };
7
+ //# sourceMappingURL=use-switch-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-switch-config.d.ts","sourceRoot":"","sources":["../../src/hooks/use-switch-config.ts"],"names":[],"mappings":"AAIA,wBAAgB,eAAe,IAAI;IACjC,YAAY,EAAE,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACvE,CA+BA"}
@@ -0,0 +1,30 @@
1
+ import { useCallback } from 'react';
2
+ import { useStore } from 'zustand';
3
+ import { useChatContext } from '../provider/chat-context.js';
4
+ export function useSwitchConfig() {
5
+ const { store, client } = useChatContext();
6
+ const currentConversationId = useStore(store, (s) => s.currentConversationId);
7
+ const switchConfig = useCallback((config) => {
8
+ // 1. Send switch_config over the existing WebSocket.
9
+ client.send({
10
+ type: 'switch_config',
11
+ ...(config.provider !== undefined ? { provider: config.provider } : {}),
12
+ ...(config.model !== undefined ? { model: config.model } : {}),
13
+ ...(currentConversationId
14
+ ? { conversation_id: currentConversationId }
15
+ : {}),
16
+ });
17
+ // 2. Optimistic store update so useSession() reflects the new choice
18
+ // immediately; gateway confirmation via a later session_ready (if any)
19
+ // can overwrite this.
20
+ const state = store.getState();
21
+ state.setSessionInfo({
22
+ sessionId: state.sessionId ?? '',
23
+ userId: state.userId ?? '',
24
+ provider: config.provider ?? state.provider ?? undefined,
25
+ model: config.model ?? state.model ?? undefined,
26
+ });
27
+ }, [client, store, currentConversationId]);
28
+ return { switchConfig };
29
+ }
30
+ //# sourceMappingURL=use-switch-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-switch-config.js","sourceRoot":"","sources":["../../src/hooks/use-switch-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,UAAU,eAAe;IAG7B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC3C,MAAM,qBAAqB,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;IAE9E,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,MAA6C,EAAE,EAAE;QAChD,qDAAqD;QACrD,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,eAAe;YACrB,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,qBAAqB;gBACvB,CAAC,CAAC,EAAE,eAAe,EAAE,qBAAqB,EAAE;gBAC5C,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;QAEH,qEAAqE;QACrE,uEAAuE;QACvE,sBAAsB;QACtB,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC/B,KAAK,CAAC,cAAc,CAAC;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;YAChC,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;YAC1B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,IAAI,SAAS;YACxD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,SAAS;SAChD,CAAC,CAAC;IACL,CAAC,EACD,CAAC,MAAM,EAAE,KAAK,EAAE,qBAAqB,CAAC,CACvC,CAAC;IAEF,OAAO,EAAE,YAAY,EAAE,CAAC;AAC1B,CAAC"}