@simfinity/constellation-ui 1.0.0 → 1.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/README.md CHANGED
@@ -1,9 +1,209 @@
1
- # @simfinity/constellation-client
1
+ # @simfinity/constellation-ui
2
2
 
3
- ## Installation
3
+ React bindings for Simfinity Constellation — persistent real-time LLM chat rooms (text + audio).
4
+
5
+ ## Overview
6
+
7
+ Constellation provides:
8
+ * Persistent server-side sessions
9
+ * WebSocket real-time streaming
10
+ * Text + audio conversations
11
+ * Configurable system instructions
12
+ * Reconnectable chat rooms
13
+
14
+ This package is a React wrapper around:
4
15
 
16
+ @simfinity/constellation-client
17
+
18
+ It provides context + hooks for lifecycle management.
19
+
20
+ ## Installation
5
21
  ```bash
22
+ npm install @simfinity/constellation-ui
23
+ # or
24
+ yarn add @simfinity/constellation-ui
25
+
26
+ # Dependency:
6
27
  npm install @simfinity/constellation-client
7
28
  # or
8
29
  yarn add @simfinity/constellation-client
9
30
  ```
31
+
32
+ ## Architecture
33
+
34
+ Session lifecycle:
35
+ ```
36
+ startSession() → REST call
37
+ joinSession() → WebSocket connection
38
+
39
+ configureSession() (optional) → WebSocket messages
40
+ sendText() / sendAudioChunk() → WebSocket messages
41
+
42
+ endSession() → REST call
43
+ ```
44
+
45
+ ⚠️ A session MUST be started before it can be joined.
46
+
47
+ ⚠️ A session SHOULD be ended when finished.
48
+
49
+ ## Minimal Working Example (Text-Only)
50
+
51
+ ```Typescript
52
+ import React, { useEffect } from "react";
53
+ import WebClient from "@simfinity/constellation-client";
54
+ import {
55
+ ConstellationProvider,
56
+ useConstellationClient
57
+ } from "@simfinity/constellation-ui";
58
+
59
+ const client = new WebClient({
60
+ sessionEndpoint: "https://your-api",
61
+ streamingEndpoint: "wss://your-stream",
62
+ key: "YOUR_SECRET_KEY",
63
+ llm: "openai",
64
+ model: "gpt-4o-realtime-preview-2024-12-17"
65
+ });
66
+
67
+ function Chat() {
68
+ const {
69
+ startSession,
70
+ joinSession,
71
+ sendText,
72
+ endSession
73
+ } = useConstellationClient();
74
+
75
+ useEffect(() => {
76
+ async function init() {
77
+ await startSession(false);
78
+
79
+ await joinSession(false, {
80
+ onStreamClosed: console.log,
81
+ onTranscriptResponse: (msg) => {
82
+ console.log("Model:", msg);
83
+ }
84
+ });
85
+
86
+ sendText("Hello!");
87
+ }
88
+
89
+ init();
90
+
91
+ return () => {
92
+ endSession();
93
+ };
94
+ }, []);
95
+
96
+ return <div>Chat running...</div>;
97
+ }
98
+
99
+ export default function App() {
100
+ return (
101
+ <ConstellationProvider client={client}>
102
+ /* Chat display components */
103
+ </ConstellationProvider>
104
+ );
105
+ }
106
+ ```
107
+
108
+ ## Audio Mode
109
+
110
+ To enable audio:
111
+
112
+ ```Typescript
113
+ // Create a audio-enabled session
114
+ await startSession(true, "alloy");
115
+
116
+ // Join a stream subscribing to audio events
117
+ await joinSession(true, {
118
+ onStreamClosed: console.log,
119
+ onAudioResponseStart: () => console.log("Speaking..."),
120
+ onAudioResponseChunk: (chunk) => audioPlayer.enqueue(chunk),
121
+ onAudioResponseEnd: () => console.log("Done")
122
+ });
123
+ ```
124
+
125
+ Audio requirements:
126
+
127
+ * Format: PCM16
128
+ * Encoding: Base64
129
+ * Transcription: handled server-side
130
+
131
+ Send audio:
132
+
133
+ ```Typescript
134
+ sendAudioChunk(base64PcmChunk);
135
+ commitAudio();
136
+ ```
137
+
138
+ commitAudio() is optional (silence auto-flushes).
139
+
140
+ ⚠️ There is server-side silence detection to trigger a model response, however for optimal use,
141
+ the client should implement audio-input noise detection to avoid continuously streaming audio data.
142
+
143
+ ## Text and Transcript
144
+
145
+ Text is always enabled in a session. However, the client must provide the appropriate handlers to receive events:
146
+ ```Typescript
147
+ interface EventHandlers {
148
+ // ...
149
+ onTranscriptInput?: (transcript: string) => void;
150
+ onTranscriptResponse?: (transcript: string) => void;
151
+ }
152
+ ```
153
+ ⚠️ These events serve both the text exchanges AND transcript of audio exchanges:
154
+
155
+ ```Typescript
156
+ // Pseudo-code:
157
+
158
+ // Text:
159
+ constellationClient.sendText("Hello");
160
+
161
+ // Triggers:
162
+ // 1) onTranscriptInput(transcript) -> transcript is "Hello"
163
+ // 2) onTranscriptResponse(transcript) -> transcript is the response from the LLM
164
+
165
+ // Audio:
166
+ constellationClient.sendAudioChunk("... audio data for 'Hello'...");
167
+ constellationClient.commitAudio();
168
+
169
+ // Triggers:
170
+ // 1) onTranscriptInput(transcript) -> transcript is "Hello"
171
+ // 2) onTranscriptResponse(transcript) -> transcript is the response from the LLM
172
+ ```
173
+
174
+ ## Session Configuration
175
+
176
+ You can update system behavior dynamically:
177
+
178
+ ```Typescript
179
+ configureSession({
180
+ temperature: 0.2,
181
+ instructions: "You are a helpful coding assistant.",
182
+ maxResponseToken: 500
183
+ });
184
+ ```
185
+
186
+
187
+ This does NOT trigger a response.
188
+
189
+ ## Event Handlers
190
+
191
+ joinSession() requires at least:
192
+
193
+ ```Typescript
194
+ {
195
+ onStreamClosed: (reason: string) => void
196
+ }
197
+ ```
198
+
199
+ Optional handlers:
200
+
201
+ * onSessionConfigured
202
+ * onAudioResponseStart
203
+ * onAudioResponseChunk
204
+ * onAudioResponseEnd
205
+ * onTranscriptInput
206
+ * onTranscriptResponse
207
+ * onTechnicalError
208
+
209
+ If omitted, events are ignored safely.
package/dist/index.d.cts CHANGED
@@ -1,24 +1,163 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { WebClient, EventHandlers, SessionConfig } from '@simfinity/constellation-client';
3
+ import { WebClient } from '@simfinity/constellation-client';
4
4
 
5
+ /**
6
+ * React context provider wrapping a Constellation WebClient instance.
7
+ *
8
+ * This component exposes session lifecycle state and client control
9
+ * functions to its descendant components.
10
+ *
11
+ * A ConstellationProvider MUST wrap any component that calls:
12
+ * - useConstellationClient()
13
+ * - useConstellationSession()
14
+ *
15
+ * @param client A pre-configured WebClient instance from
16
+ * "@simfinity/constellation-client".
17
+ * @param children The DOM descendant components
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * import WebClient from "@simfinity/constellation-client";
22
+ * import { ConstellationProvider } from "@simfinity/constellation-ui";
23
+ *
24
+ * const client = new WebClient({
25
+ * sessionEndpoint: "https://your-api",
26
+ * streamingEndpoint: "wss://your-stream",
27
+ * key: "YOUR_SECRET_KEY",
28
+ * llm: "openai",
29
+ * model: "gpt-4o-realtime-preview-2024-12-17"
30
+ * });
31
+ *
32
+ * function App() {
33
+ * return (
34
+ * <ConstellationProvider client={client}>
35
+ * <Chat />
36
+ * </ConstellationProvider>
37
+ * );
38
+ * }
39
+ * ```
40
+ *
41
+ * @remarks
42
+ * This provider does NOT automatically start or join sessions.
43
+ * The lifecycle must be controlled explicitly via useConstellationClient().
44
+ */
5
45
  declare function ConstellationProvider({ client, children, }: {
6
46
  client: WebClient;
7
47
  children: React.ReactNode;
8
48
  }): react_jsx_runtime.JSX.Element;
9
- declare function useConstellationClient(): {
10
- startSession: (audio: boolean, voice?: string) => Promise<void>;
11
- endSession: () => Promise<void>;
12
- joinSession: (audio: boolean, handlers: EventHandlers) => Promise<void>;
13
- configureSession: (settings: SessionConfig) => void;
14
- sendText: (text: string) => void;
15
- sendAudioChunk: (chunk: string) => void;
16
- commitAudio: () => void;
17
- };
18
- declare function useConstellationSession(): {
19
- sessionId: string | null;
20
- connected: boolean;
21
- audioEnabled: boolean;
22
- };
49
+ /**
50
+ * Hook exposing all lifecycle control functions required to
51
+ * interact with a Constellation session.
52
+ *
53
+ * IMPORTANT SESSION ORDER:
54
+ *
55
+ * 1) startSession(audioEnabled, voice?)
56
+ * Creates a persistent server-side session (REST)
57
+ * → A session remains alive and can be re-joined within 5 minutes of inactivity
58
+ * → audioEnabled makes the session capable of receiving and producing audio stream
59
+ * voice is an LLM specific name of a voice e.g. for OpenAI 'alloy' is a valid value
60
+ * Once a session has started, audio & voice options cannot be changed
61
+ *
62
+ * 2) joinSession(audioEnabled, handlers)
63
+ * → Opens WebSocket stream and begins event flow
64
+ * → audioEnabled (along with an audioEnabled session) to subscribe to audio events
65
+ * → handlers are the callback functions to receive server events
66
+ *
67
+ * 3) configureSession(settings?) (optional)
68
+ * → Update of the settings affecting the LLM behaviour/context
69
+ * → This can be done at any time mid-stream
70
+ *
71
+ * 4) sendText(...) OR sendAudioChunk(...) + commitAudio()
72
+ * → Input-sending methods text & audio
73
+ *
74
+ * 5) endSession()
75
+ * → Closes the persistent server-side session
76
+ * → For a clean implementation the client should close the stream first
77
+ *
78
+ * This hook does NOT expose the underlying WebClient directly.
79
+ * It provides a controlled abstraction safe for React usage.
80
+ *
81
+ * @throws Error if used outside ConstellationProvider.
82
+ *
83
+ * @returns
84
+ * Lifecycle control methods:
85
+ *
86
+ * startSession(audioEnabled: boolean, voice?: string)
87
+ * - Creates a new persistent session on the server.
88
+ * - Must be called before joinSession().
89
+ *
90
+ * joinSession(audioEnabled: boolean, handlers: EventHandlers)
91
+ * - Opens the WebSocket stream.
92
+ * - Handlers are required to receive model responses.
93
+ *
94
+ * configureSession(settings: SessionConfig)
95
+ * - Updates temperature, instructions, max tokens.
96
+ * - Does NOT trigger a response.
97
+ *
98
+ * sendText(text: string)
99
+ * - Sends a user text message.
100
+ * - Triggers model response.
101
+ *
102
+ * sendAudioChunk(chunk: string)
103
+ * - Sends base64 PCM16 audio chunk.
104
+ * - Accumulates until commitAudio() or silence detection.
105
+ *
106
+ * commitAudio()
107
+ * - Forces model to process accumulated audio.
108
+ *
109
+ * endSession()
110
+ * - Closes session and frees server resources.
111
+ *
112
+ * @example
113
+ * ```tsx
114
+ * const {
115
+ * startSession,
116
+ * joinSession,
117
+ * sendText,
118
+ * endSession
119
+ * } = useConstellationClient();
120
+ *
121
+ * await startSession(false);
122
+ *
123
+ * await joinSession(false, {
124
+ * onStreamClosed: console.log,
125
+ * onTranscriptResponse: (text) => console.log(text),
126
+ * });
127
+ *
128
+ * sendText("Hello world");
129
+ * ```
130
+ */
131
+ declare function useConstellationClient(): any;
132
+ /**
133
+ * Hook exposing reactive session state.
134
+ *
135
+ * This hook does NOT control the session.
136
+ * It only reflects the current state managed by ConstellationProvider.
137
+ *
138
+ * @returns
139
+ * {
140
+ * sessionId: string | null
141
+ * connected: boolean
142
+ * audioEnabled: boolean
143
+ * }
144
+ *
145
+ * sessionId
146
+ * - Null until startSession() succeeds.
147
+ *
148
+ * connected
149
+ * - True after successful joinSession().
150
+ *
151
+ * audioEnabled
152
+ * - Reflects whether session was started in audio mode.
153
+ *
154
+ * @example
155
+ * ```tsx
156
+ * const { connected, sessionId } = useConstellationSession();
157
+ *
158
+ * if (!connected) return <p>Disconnected</p>;
159
+ * ```
160
+ */
161
+ declare function useConstellationSession(): any;
23
162
 
24
163
  export { ConstellationProvider, useConstellationClient, useConstellationSession };
package/dist/index.d.ts CHANGED
@@ -1,24 +1,163 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { WebClient, EventHandlers, SessionConfig } from '@simfinity/constellation-client';
3
+ import { WebClient } from '@simfinity/constellation-client';
4
4
 
5
+ /**
6
+ * React context provider wrapping a Constellation WebClient instance.
7
+ *
8
+ * This component exposes session lifecycle state and client control
9
+ * functions to its descendant components.
10
+ *
11
+ * A ConstellationProvider MUST wrap any component that calls:
12
+ * - useConstellationClient()
13
+ * - useConstellationSession()
14
+ *
15
+ * @param client A pre-configured WebClient instance from
16
+ * "@simfinity/constellation-client".
17
+ * @param children The DOM descendant components
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * import WebClient from "@simfinity/constellation-client";
22
+ * import { ConstellationProvider } from "@simfinity/constellation-ui";
23
+ *
24
+ * const client = new WebClient({
25
+ * sessionEndpoint: "https://your-api",
26
+ * streamingEndpoint: "wss://your-stream",
27
+ * key: "YOUR_SECRET_KEY",
28
+ * llm: "openai",
29
+ * model: "gpt-4o-realtime-preview-2024-12-17"
30
+ * });
31
+ *
32
+ * function App() {
33
+ * return (
34
+ * <ConstellationProvider client={client}>
35
+ * <Chat />
36
+ * </ConstellationProvider>
37
+ * );
38
+ * }
39
+ * ```
40
+ *
41
+ * @remarks
42
+ * This provider does NOT automatically start or join sessions.
43
+ * The lifecycle must be controlled explicitly via useConstellationClient().
44
+ */
5
45
  declare function ConstellationProvider({ client, children, }: {
6
46
  client: WebClient;
7
47
  children: React.ReactNode;
8
48
  }): react_jsx_runtime.JSX.Element;
9
- declare function useConstellationClient(): {
10
- startSession: (audio: boolean, voice?: string) => Promise<void>;
11
- endSession: () => Promise<void>;
12
- joinSession: (audio: boolean, handlers: EventHandlers) => Promise<void>;
13
- configureSession: (settings: SessionConfig) => void;
14
- sendText: (text: string) => void;
15
- sendAudioChunk: (chunk: string) => void;
16
- commitAudio: () => void;
17
- };
18
- declare function useConstellationSession(): {
19
- sessionId: string | null;
20
- connected: boolean;
21
- audioEnabled: boolean;
22
- };
49
+ /**
50
+ * Hook exposing all lifecycle control functions required to
51
+ * interact with a Constellation session.
52
+ *
53
+ * IMPORTANT SESSION ORDER:
54
+ *
55
+ * 1) startSession(audioEnabled, voice?)
56
+ * Creates a persistent server-side session (REST)
57
+ * → A session remains alive and can be re-joined within 5 minutes of inactivity
58
+ * → audioEnabled makes the session capable of receiving and producing audio stream
59
+ * voice is an LLM specific name of a voice e.g. for OpenAI 'alloy' is a valid value
60
+ * Once a session has started, audio & voice options cannot be changed
61
+ *
62
+ * 2) joinSession(audioEnabled, handlers)
63
+ * → Opens WebSocket stream and begins event flow
64
+ * → audioEnabled (along with an audioEnabled session) to subscribe to audio events
65
+ * → handlers are the callback functions to receive server events
66
+ *
67
+ * 3) configureSession(settings?) (optional)
68
+ * → Update of the settings affecting the LLM behaviour/context
69
+ * → This can be done at any time mid-stream
70
+ *
71
+ * 4) sendText(...) OR sendAudioChunk(...) + commitAudio()
72
+ * → Input-sending methods text & audio
73
+ *
74
+ * 5) endSession()
75
+ * → Closes the persistent server-side session
76
+ * → For a clean implementation the client should close the stream first
77
+ *
78
+ * This hook does NOT expose the underlying WebClient directly.
79
+ * It provides a controlled abstraction safe for React usage.
80
+ *
81
+ * @throws Error if used outside ConstellationProvider.
82
+ *
83
+ * @returns
84
+ * Lifecycle control methods:
85
+ *
86
+ * startSession(audioEnabled: boolean, voice?: string)
87
+ * - Creates a new persistent session on the server.
88
+ * - Must be called before joinSession().
89
+ *
90
+ * joinSession(audioEnabled: boolean, handlers: EventHandlers)
91
+ * - Opens the WebSocket stream.
92
+ * - Handlers are required to receive model responses.
93
+ *
94
+ * configureSession(settings: SessionConfig)
95
+ * - Updates temperature, instructions, max tokens.
96
+ * - Does NOT trigger a response.
97
+ *
98
+ * sendText(text: string)
99
+ * - Sends a user text message.
100
+ * - Triggers model response.
101
+ *
102
+ * sendAudioChunk(chunk: string)
103
+ * - Sends base64 PCM16 audio chunk.
104
+ * - Accumulates until commitAudio() or silence detection.
105
+ *
106
+ * commitAudio()
107
+ * - Forces model to process accumulated audio.
108
+ *
109
+ * endSession()
110
+ * - Closes session and frees server resources.
111
+ *
112
+ * @example
113
+ * ```tsx
114
+ * const {
115
+ * startSession,
116
+ * joinSession,
117
+ * sendText,
118
+ * endSession
119
+ * } = useConstellationClient();
120
+ *
121
+ * await startSession(false);
122
+ *
123
+ * await joinSession(false, {
124
+ * onStreamClosed: console.log,
125
+ * onTranscriptResponse: (text) => console.log(text),
126
+ * });
127
+ *
128
+ * sendText("Hello world");
129
+ * ```
130
+ */
131
+ declare function useConstellationClient(): any;
132
+ /**
133
+ * Hook exposing reactive session state.
134
+ *
135
+ * This hook does NOT control the session.
136
+ * It only reflects the current state managed by ConstellationProvider.
137
+ *
138
+ * @returns
139
+ * {
140
+ * sessionId: string | null
141
+ * connected: boolean
142
+ * audioEnabled: boolean
143
+ * }
144
+ *
145
+ * sessionId
146
+ * - Null until startSession() succeeds.
147
+ *
148
+ * connected
149
+ * - True after successful joinSession().
150
+ *
151
+ * audioEnabled
152
+ * - Reflects whether session was started in audio mode.
153
+ *
154
+ * @example
155
+ * ```tsx
156
+ * const { connected, sessionId } = useConstellationSession();
157
+ *
158
+ * if (!connected) return <p>Disconnected</p>;
159
+ * ```
160
+ */
161
+ declare function useConstellationSession(): any;
23
162
 
24
163
  export { ConstellationProvider, useConstellationClient, useConstellationSession };
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@simfinity/constellation-ui",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
7
- "import": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "import": "./dist/index.js",
8
9
  "require": "./dist/index.cjs"
9
10
  }
10
11
  },