@tpitre/story-ui 4.3.0 → 4.4.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/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Story UI revolutionizes component documentation by automatically generating Stor
|
|
|
10
10
|
## Why Story UI?
|
|
11
11
|
|
|
12
12
|
- **Framework Agnostic**: Works with React, Vue, Angular, Svelte, and Web Components
|
|
13
|
-
- **Multi-Provider AI**: Choose between Claude
|
|
13
|
+
- **Multi-Provider AI**: Choose between Claude, OpenAI, or Google Gemini - always using the latest models
|
|
14
14
|
- **Design System Aware**: Learns your component library and generates appropriate code
|
|
15
15
|
- **Production Ready**: Deploy as a standalone web app with full MCP integration
|
|
16
16
|
- **Zero Lock-in**: Use any component library - Mantine, Vuetify, Angular Material, Shoelace, or your own
|
|
@@ -68,8 +68,8 @@ Story UI will guide you through:
|
|
|
68
68
|
| Provider | Models | Best For |
|
|
69
69
|
|----------|--------|----------|
|
|
70
70
|
| **Claude** (Anthropic) | claude-opus-4-5, claude-sonnet-4-5, claude-haiku-4-5 | Complex reasoning, code quality |
|
|
71
|
-
| **GPT** (OpenAI) | gpt-4o, gpt-4o-mini
|
|
72
|
-
| **Gemini** (Google) | gemini-2.
|
|
71
|
+
| **GPT** (OpenAI) | gpt-5.2, gpt-5.1, gpt-4o, gpt-4o-mini | Versatility, latest capabilities |
|
|
72
|
+
| **Gemini** (Google) | gemini-2.5-pro, gemini-2.5-flash, gemini-2.0-flash | Fast generation, cost efficiency |
|
|
73
73
|
|
|
74
74
|
### Production Deployment
|
|
75
75
|
- **Railway**: Node.js backend with file-based story persistence
|
|
@@ -121,7 +121,7 @@ The interactive installer will ask:
|
|
|
121
121
|
```
|
|
122
122
|
? Which AI provider do you prefer?
|
|
123
123
|
> Claude (Anthropic) - Recommended
|
|
124
|
-
OpenAI
|
|
124
|
+
OpenAI
|
|
125
125
|
Google Gemini
|
|
126
126
|
|
|
127
127
|
? Enter your API key:
|
|
@@ -262,11 +262,18 @@ The easiest way to connect is via Claude Desktop's built-in connector UI:
|
|
|
262
262
|
2. Go to **Settings** → **Connectors**
|
|
263
263
|
3. Click **"Add custom connector"**
|
|
264
264
|
4. Enter:
|
|
265
|
-
- **Name**: `Story UI` (or any name
|
|
266
|
-
- **URL**:
|
|
265
|
+
- **Name**: `Story UI React` (or any descriptive name)
|
|
266
|
+
- **URL**: Your deployed Railway URL + `/mcp-remote/mcp`
|
|
267
|
+
- Example: `https://your-app-name.up.railway.app/mcp-remote/mcp`
|
|
267
268
|
5. Click **Add**
|
|
268
269
|
6. **Restart Claude Desktop**
|
|
269
270
|
|
|
271
|
+
> **Note**: The URL will be your own Railway deployment URL. See [Production Deployment](#production-deployment) to set up your instance.
|
|
272
|
+
|
|
273
|
+
**Multiple Projects**: If you have multiple Storybook projects, add a separate connector for each:
|
|
274
|
+
- `Story UI React` → `https://my-react-app.up.railway.app/mcp-remote/mcp`
|
|
275
|
+
- `Story UI Vue` → `https://my-vue-app.up.railway.app/mcp-remote/mcp`
|
|
276
|
+
|
|
270
277
|
Once connected, you'll have access to all Story UI tools directly in your Claude conversations:
|
|
271
278
|
- `generate-story` - Generate Storybook stories from natural language
|
|
272
279
|
- `list-components` - Discover available components
|
|
@@ -280,38 +287,52 @@ Once connected, you'll have access to all Story UI tools directly in your Claude
|
|
|
280
287
|
Connect via Claude Code's built-in MCP support:
|
|
281
288
|
|
|
282
289
|
```bash
|
|
283
|
-
# Add
|
|
284
|
-
claude mcp add --transport http story-ui https://
|
|
290
|
+
# Add your production Railway deployment
|
|
291
|
+
claude mcp add --transport http story-ui-react https://your-react-app.up.railway.app/mcp-remote/mcp
|
|
292
|
+
|
|
293
|
+
# Add another project (if needed)
|
|
294
|
+
claude mcp add --transport http story-ui-vue https://your-vue-app.up.railway.app/mcp-remote/mcp
|
|
285
295
|
|
|
286
|
-
#
|
|
287
|
-
claude mcp add --transport http story-ui-local http://localhost:
|
|
296
|
+
# For local development (default port is 4001)
|
|
297
|
+
claude mcp add --transport http story-ui-local http://localhost:4001/mcp-remote/mcp
|
|
288
298
|
```
|
|
289
299
|
|
|
290
300
|
### Manual Configuration (Advanced)
|
|
291
301
|
|
|
292
|
-
For
|
|
302
|
+
For running multiple local Story UI instances with different ports, configure your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
293
303
|
|
|
294
304
|
```json
|
|
295
305
|
{
|
|
296
306
|
"mcpServers": {
|
|
297
|
-
"story-ui": {
|
|
307
|
+
"story-ui-react": {
|
|
308
|
+
"command": "npx",
|
|
309
|
+
"args": ["@tpitre/story-ui", "start", "--port", "4001"]
|
|
310
|
+
},
|
|
311
|
+
"story-ui-vue": {
|
|
312
|
+
"command": "npx",
|
|
313
|
+
"args": ["@tpitre/story-ui", "start", "--port", "4002"]
|
|
314
|
+
},
|
|
315
|
+
"story-ui-angular": {
|
|
298
316
|
"command": "npx",
|
|
299
|
-
"args": ["@tpitre/story-ui", "
|
|
300
|
-
"env": {
|
|
301
|
-
"ANTHROPIC_API_KEY": "your-api-key"
|
|
302
|
-
}
|
|
317
|
+
"args": ["@tpitre/story-ui", "start", "--port", "4003"]
|
|
303
318
|
}
|
|
304
319
|
}
|
|
305
320
|
}
|
|
306
321
|
```
|
|
307
322
|
|
|
323
|
+
> **Note**: When using Claude Desktop, API keys are managed through your Anthropic account - no need to configure them in the MCP server.
|
|
324
|
+
|
|
308
325
|
### Starting the Local MCP Server
|
|
309
326
|
|
|
310
327
|
```bash
|
|
328
|
+
# Start with default port (4001)
|
|
311
329
|
npx story-ui start
|
|
330
|
+
|
|
331
|
+
# Or specify a custom port
|
|
332
|
+
npx story-ui start --port 4002
|
|
312
333
|
```
|
|
313
334
|
|
|
314
|
-
This starts the Story UI HTTP server with MCP endpoint at `http://localhost
|
|
335
|
+
This starts the Story UI HTTP server with MCP endpoint at `http://localhost:<port>/mcp-remote/mcp`.
|
|
315
336
|
|
|
316
337
|
### Available MCP Commands
|
|
317
338
|
|
|
@@ -325,13 +346,13 @@ Once connected, you can use these commands in Claude Desktop:
|
|
|
325
346
|
|
|
326
347
|
## Production Deployment
|
|
327
348
|
|
|
328
|
-
Story UI can be deployed as a standalone web application accessible from anywhere.
|
|
349
|
+
Story UI can be deployed as a standalone web application accessible from anywhere. We recommend Railway for its ease of use, but any Node.js hosting platform will work.
|
|
329
350
|
|
|
330
351
|
### Architecture
|
|
331
352
|
|
|
332
353
|
```
|
|
333
354
|
┌─────────────────────────────────────────────────────────────┐
|
|
334
|
-
│
|
|
355
|
+
│ Your Deployment (e.g., Railway) │
|
|
335
356
|
│ ┌─────────────────────────────────────────────────────────┐│
|
|
336
357
|
│ │ Express MCP Server (Node.js) ││
|
|
337
358
|
│ │ - Serves Storybook with Story UI addon ││
|
|
@@ -342,9 +363,9 @@ Story UI can be deployed as a standalone web application accessible from anywher
|
|
|
342
363
|
└──────────────────────────────────────────────────────────────┘
|
|
343
364
|
```
|
|
344
365
|
|
|
345
|
-
### Deploy to Railway
|
|
366
|
+
### Deploy to Railway (Recommended)
|
|
346
367
|
|
|
347
|
-
Railway provides a straightforward deployment experience with file-based story persistence.
|
|
368
|
+
Railway provides a straightforward deployment experience with automatic HTTPS and file-based story persistence.
|
|
348
369
|
|
|
349
370
|
**Quick Start:**
|
|
350
371
|
|
|
@@ -353,23 +374,27 @@ Railway provides a straightforward deployment experience with file-based story p
|
|
|
353
374
|
npm install -g @railway/cli
|
|
354
375
|
railway login
|
|
355
376
|
|
|
356
|
-
# Initialize and deploy
|
|
377
|
+
# Initialize and deploy from your Storybook project
|
|
357
378
|
railway init
|
|
358
379
|
railway up
|
|
359
380
|
```
|
|
360
381
|
|
|
361
382
|
**Environment Variables (set in Railway Dashboard):**
|
|
362
383
|
- `ANTHROPIC_API_KEY` - Required for Claude models
|
|
363
|
-
- `OPENAI_API_KEY` - Optional for OpenAI models
|
|
364
|
-
- `GEMINI_API_KEY` - Optional for Gemini models
|
|
384
|
+
- `OPENAI_API_KEY` - Optional, for OpenAI models
|
|
385
|
+
- `GEMINI_API_KEY` - Optional, for Gemini models
|
|
386
|
+
|
|
387
|
+
**After Deployment:**
|
|
365
388
|
|
|
366
|
-
|
|
389
|
+
Your Railway app will have a URL like `https://your-app-name.up.railway.app`. Use this URL to connect MCP clients:
|
|
367
390
|
|
|
368
391
|
```bash
|
|
369
|
-
#
|
|
370
|
-
claude mcp add --transport http story-ui https://your-app.up.railway.app/mcp-remote/mcp
|
|
392
|
+
# In Claude Code
|
|
393
|
+
claude mcp add --transport http story-ui https://your-app-name.up.railway.app/mcp-remote/mcp
|
|
371
394
|
```
|
|
372
395
|
|
|
396
|
+
Or add it to Claude Desktop via **Settings** → **Connectors** → **Add custom connector**.
|
|
397
|
+
|
|
373
398
|
See [DEPLOYMENT.md](DEPLOYMENT.md) for detailed deployment instructions and troubleshooting.
|
|
374
399
|
|
|
375
400
|
---
|
|
@@ -423,17 +448,14 @@ For simpler setups, use `story-ui-considerations.md`:
|
|
|
423
448
|
## CLI Reference
|
|
424
449
|
|
|
425
450
|
```bash
|
|
426
|
-
# Initialize Story UI
|
|
451
|
+
# Initialize Story UI in your project
|
|
427
452
|
npx story-ui init
|
|
428
453
|
|
|
429
|
-
# Start the
|
|
454
|
+
# Start the MCP server (default port: 4001)
|
|
430
455
|
npx story-ui start
|
|
431
|
-
npx story-ui start --port
|
|
432
|
-
|
|
433
|
-
# Deploy to production
|
|
434
|
-
npx story-ui deploy
|
|
456
|
+
npx story-ui start --port 4002 # Custom port
|
|
435
457
|
|
|
436
|
-
# Run MCP server
|
|
458
|
+
# Run MCP STDIO server (for Claude Desktop local integration)
|
|
437
459
|
npx story-ui mcp
|
|
438
460
|
```
|
|
439
461
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StoryUIPanel.d.ts","sourceRoot":"","sources":["../../../templates/StoryUI/StoryUIPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,oBAAoB,CAAC;AAwwB5B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,iBAAS,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"StoryUIPanel.d.ts","sourceRoot":"","sources":["../../../templates/StoryUI/StoryUIPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,oBAAoB,CAAC;AAwwB5B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,iBAAS,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,iBAAiB,2CA0sCnD;AAED,eAAe,YAAY,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -452,12 +452,79 @@ function StoryUIPanel({ mcpPort }) {
|
|
|
452
452
|
const fileInputRef = useRef(null);
|
|
453
453
|
const abortControllerRef = useRef(null);
|
|
454
454
|
const hasShownRefreshHint = useRef(false);
|
|
455
|
+
// Track stories for MCP external generation detection
|
|
456
|
+
// Used to detect when stories are created via MCP remote (Claude Desktop)
|
|
457
|
+
// and trigger automatic refresh since MCP has no browser context
|
|
458
|
+
const panelGeneratedStoryIds = useRef(new Set());
|
|
459
|
+
const knownStoryIds = useRef(new Set());
|
|
460
|
+
const isPollingInitialized = useRef(false);
|
|
455
461
|
// Set port override if provided
|
|
456
462
|
useEffect(() => {
|
|
457
463
|
if (mcpPort && typeof window !== 'undefined') {
|
|
458
464
|
window.STORY_UI_MCP_PORT = String(mcpPort);
|
|
459
465
|
}
|
|
460
466
|
}, [mcpPort]);
|
|
467
|
+
// Poll for MCP-generated stories (stories created externally via Claude Desktop/Code)
|
|
468
|
+
// This solves the Vite HMR issue where stories generated via MCP remote don't trigger
|
|
469
|
+
// a browser refresh because MCP has no browser context to call window.location.reload()
|
|
470
|
+
useEffect(() => {
|
|
471
|
+
const POLL_INTERVAL_MS = 5000; // Check every 5 seconds
|
|
472
|
+
const pollForExternalStories = async () => {
|
|
473
|
+
try {
|
|
474
|
+
const baseUrl = getApiBaseUrl();
|
|
475
|
+
const response = await fetch(`${baseUrl}/story-ui/stories`);
|
|
476
|
+
if (!response.ok)
|
|
477
|
+
return;
|
|
478
|
+
const data = await response.json();
|
|
479
|
+
const currentStoryIds = new Set(data.stories?.map((s) => s.id) || []);
|
|
480
|
+
// On first poll, just record what's already there
|
|
481
|
+
if (!isPollingInitialized.current) {
|
|
482
|
+
knownStoryIds.current = currentStoryIds;
|
|
483
|
+
isPollingInitialized.current = true;
|
|
484
|
+
console.log('[Story UI] MCP story polling initialized with', currentStoryIds.size, 'stories');
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
// Check for new stories not created by this panel session
|
|
488
|
+
for (const storyId of currentStoryIds) {
|
|
489
|
+
if (!knownStoryIds.current.has(storyId) && !panelGeneratedStoryIds.current.has(storyId)) {
|
|
490
|
+
// New story detected that wasn't created by this panel - must be from MCP remote
|
|
491
|
+
console.log('[Story UI] Detected externally generated story:', storyId);
|
|
492
|
+
console.log('[Story UI] Triggering refresh to register new story in Vite import map...');
|
|
493
|
+
// Update known stories before refresh
|
|
494
|
+
knownStoryIds.current = currentStoryIds;
|
|
495
|
+
// Trigger refresh with a short delay
|
|
496
|
+
setTimeout(() => {
|
|
497
|
+
try {
|
|
498
|
+
if (window.top && window.top !== window) {
|
|
499
|
+
window.top.location.reload();
|
|
500
|
+
}
|
|
501
|
+
else if (window.parent && window.parent !== window) {
|
|
502
|
+
window.parent.location.reload();
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
window.location.reload();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
console.warn('[Story UI] Could not auto-refresh for MCP-generated story');
|
|
510
|
+
}
|
|
511
|
+
}, 1000);
|
|
512
|
+
return; // Only trigger one refresh
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// Update known stories
|
|
516
|
+
knownStoryIds.current = currentStoryIds;
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
// Silently ignore polling errors - server may be unavailable temporarily
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
// Start polling
|
|
523
|
+
const intervalId = setInterval(pollForExternalStories, POLL_INTERVAL_MS);
|
|
524
|
+
// Initial poll
|
|
525
|
+
pollForExternalStories();
|
|
526
|
+
return () => clearInterval(intervalId);
|
|
527
|
+
}, []);
|
|
461
528
|
// Detect Storybook theme
|
|
462
529
|
useEffect(() => {
|
|
463
530
|
const detectTheme = () => {
|
|
@@ -863,6 +930,13 @@ function StoryUIPanel({ mcpPort }) {
|
|
|
863
930
|
title: completion.title,
|
|
864
931
|
action: completion.summary?.action,
|
|
865
932
|
});
|
|
933
|
+
// Track this story as panel-generated to prevent false MCP detection
|
|
934
|
+
// The story ID is the fileName without .stories.tsx extension
|
|
935
|
+
if (completion.success && completion.fileName) {
|
|
936
|
+
const storyId = completion.fileName.replace('.stories.tsx', '');
|
|
937
|
+
panelGeneratedStoryIds.current.add(storyId);
|
|
938
|
+
console.log('[Story UI] Tracking panel-generated story:', storyId);
|
|
939
|
+
}
|
|
866
940
|
const isUpdate = completion.summary.action === 'updated';
|
|
867
941
|
const responseMessage = buildConversationalResponse(completion, isUpdate);
|
|
868
942
|
const aiMsg = { role: 'ai', content: responseMessage };
|
package/package.json
CHANGED
|
@@ -800,6 +800,13 @@ function StoryUIPanel({ mcpPort }: StoryUIPanelProps) {
|
|
|
800
800
|
const abortControllerRef = useRef<AbortController | null>(null);
|
|
801
801
|
const hasShownRefreshHint = useRef(false);
|
|
802
802
|
|
|
803
|
+
// Track stories for MCP external generation detection
|
|
804
|
+
// Used to detect when stories are created via MCP remote (Claude Desktop)
|
|
805
|
+
// and trigger automatic refresh since MCP has no browser context
|
|
806
|
+
const panelGeneratedStoryIds = useRef<Set<string>>(new Set());
|
|
807
|
+
const knownStoryIds = useRef<Set<string>>(new Set());
|
|
808
|
+
const isPollingInitialized = useRef(false);
|
|
809
|
+
|
|
803
810
|
// Set port override if provided
|
|
804
811
|
useEffect(() => {
|
|
805
812
|
if (mcpPort && typeof window !== 'undefined') {
|
|
@@ -807,6 +814,73 @@ function StoryUIPanel({ mcpPort }: StoryUIPanelProps) {
|
|
|
807
814
|
}
|
|
808
815
|
}, [mcpPort]);
|
|
809
816
|
|
|
817
|
+
// Poll for MCP-generated stories (stories created externally via Claude Desktop/Code)
|
|
818
|
+
// This solves the Vite HMR issue where stories generated via MCP remote don't trigger
|
|
819
|
+
// a browser refresh because MCP has no browser context to call window.location.reload()
|
|
820
|
+
useEffect(() => {
|
|
821
|
+
const POLL_INTERVAL_MS = 5000; // Check every 5 seconds
|
|
822
|
+
|
|
823
|
+
const pollForExternalStories = async () => {
|
|
824
|
+
try {
|
|
825
|
+
const baseUrl = getApiBaseUrl();
|
|
826
|
+
const response = await fetch(`${baseUrl}/story-ui/stories`);
|
|
827
|
+
if (!response.ok) return;
|
|
828
|
+
|
|
829
|
+
const data = await response.json();
|
|
830
|
+
const currentStoryIds = new Set<string>(data.stories?.map((s: { id: string }) => s.id) || []);
|
|
831
|
+
|
|
832
|
+
// On first poll, just record what's already there
|
|
833
|
+
if (!isPollingInitialized.current) {
|
|
834
|
+
knownStoryIds.current = currentStoryIds;
|
|
835
|
+
isPollingInitialized.current = true;
|
|
836
|
+
console.log('[Story UI] MCP story polling initialized with', currentStoryIds.size, 'stories');
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Check for new stories not created by this panel session
|
|
841
|
+
for (const storyId of currentStoryIds) {
|
|
842
|
+
if (!knownStoryIds.current.has(storyId) && !panelGeneratedStoryIds.current.has(storyId)) {
|
|
843
|
+
// New story detected that wasn't created by this panel - must be from MCP remote
|
|
844
|
+
console.log('[Story UI] Detected externally generated story:', storyId);
|
|
845
|
+
console.log('[Story UI] Triggering refresh to register new story in Vite import map...');
|
|
846
|
+
|
|
847
|
+
// Update known stories before refresh
|
|
848
|
+
knownStoryIds.current = currentStoryIds;
|
|
849
|
+
|
|
850
|
+
// Trigger refresh with a short delay
|
|
851
|
+
setTimeout(() => {
|
|
852
|
+
try {
|
|
853
|
+
if (window.top && window.top !== window) {
|
|
854
|
+
window.top.location.reload();
|
|
855
|
+
} else if (window.parent && window.parent !== window) {
|
|
856
|
+
window.parent.location.reload();
|
|
857
|
+
} else {
|
|
858
|
+
window.location.reload();
|
|
859
|
+
}
|
|
860
|
+
} catch (error) {
|
|
861
|
+
console.warn('[Story UI] Could not auto-refresh for MCP-generated story');
|
|
862
|
+
}
|
|
863
|
+
}, 1000);
|
|
864
|
+
return; // Only trigger one refresh
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Update known stories
|
|
869
|
+
knownStoryIds.current = currentStoryIds;
|
|
870
|
+
} catch (error) {
|
|
871
|
+
// Silently ignore polling errors - server may be unavailable temporarily
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
// Start polling
|
|
876
|
+
const intervalId = setInterval(pollForExternalStories, POLL_INTERVAL_MS);
|
|
877
|
+
|
|
878
|
+
// Initial poll
|
|
879
|
+
pollForExternalStories();
|
|
880
|
+
|
|
881
|
+
return () => clearInterval(intervalId);
|
|
882
|
+
}, []);
|
|
883
|
+
|
|
810
884
|
// Detect Storybook theme
|
|
811
885
|
useEffect(() => {
|
|
812
886
|
const detectTheme = () => {
|
|
@@ -1219,6 +1293,14 @@ function StoryUIPanel({ mcpPort }: StoryUIPanelProps) {
|
|
|
1219
1293
|
action: completion.summary?.action,
|
|
1220
1294
|
});
|
|
1221
1295
|
|
|
1296
|
+
// Track this story as panel-generated to prevent false MCP detection
|
|
1297
|
+
// The story ID is the fileName without .stories.tsx extension
|
|
1298
|
+
if (completion.success && completion.fileName) {
|
|
1299
|
+
const storyId = completion.fileName.replace('.stories.tsx', '');
|
|
1300
|
+
panelGeneratedStoryIds.current.add(storyId);
|
|
1301
|
+
console.log('[Story UI] Tracking panel-generated story:', storyId);
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1222
1304
|
const isUpdate = completion.summary.action === 'updated';
|
|
1223
1305
|
const responseMessage = buildConversationalResponse(completion, isUpdate);
|
|
1224
1306
|
const aiMsg: Message = { role: 'ai', content: responseMessage };
|