moelove commited on
Commit
ce51672
Β·
1 Parent(s): 6226e73

refactor: completely remove PWA functionality

Browse files

- Delete all PWA-related files:
- public/sw.js (service worker)
- public/manifest.json (PWA manifest)
- public/icons/ directory (PWA icons)
- src/serviceWorkerRegistration.js
- src/utils/clearCache.js
- scripts/generate-icons.js
- XSAI_INTEGRATION_SUMMARY.md
- test-xsai.js

- Clean up HTML references:
- Remove manifest.json link
- Remove apple-touch-icon link
- Remove theme-color meta tag

- Remove from main.jsx:
- Remove service worker import and registration

- Remove from Settings.jsx:
- Remove clearCache utility imports
- Remove developer tools section entirely

- Clean up CSS:
- Remove all developer tools related styles

This completely removes PWA functionality from the project as requested.

XSAI_INTEGRATION_SUMMARY.md DELETED
@@ -1,120 +0,0 @@
1
- # xsai Integration Summary
2
-
3
- ## 🎯 Objective
4
- Migrated the thinking-model-client from using `node-fetch` directly to using the [xsai](https://github.com/moeru-ai/xsai) library for LLM provider connections.
5
-
6
- ## πŸ”„ Changes Made
7
-
8
- ### 1. Dependencies Updated
9
- - **Added**:
10
- - `@xsai/stream-text@^0.3.3` - For streaming text responses
11
- - `@xsai/generate-text@^0.3.3` - For text generation (summarization)
12
- - `@xsai/utils-reasoning@^0.3.3` - For extracting reasoning from responses
13
- - **Removed**:
14
- - `node-fetch` - No longer needed
15
-
16
- ### 2. Server Implementation (`server/index.js`)
17
-
18
- #### Chat Endpoint (`/api/chat`)
19
- - **Before**: Used `node-fetch` with manual streaming setup
20
- - **After**: Uses `xsai.streamText()` with automatic reasoning extraction
21
- - **Benefits**:
22
- - Cleaner error handling
23
- - Automatic reasoning/content separation
24
- - Better streaming reliability
25
- - Built-in support for different model formats
26
-
27
- #### Summarization Endpoint (`/api/summarize`)
28
- - **Before**: Used `node-fetch` with manual JSON parsing
29
- - **After**: Uses `xsai.generateText()` for direct text generation
30
- - **Benefits**:
31
- - Simplified API calls
32
- - Better error handling
33
- - Consistent interface across providers
34
-
35
- ### 3. Key Features Enhanced
36
-
37
- #### Reasoning Extraction
38
- - Automatically extracts `<think>...</think>` tags from AI responses
39
- - Separates reasoning process from final answer
40
- - Streams reasoning first, then content for better UX
41
-
42
- #### Streaming Improvements
43
- - More reliable streaming with better error handling
44
- - Consistent format across different model providers
45
- - Automatic handling of different response formats
46
-
47
- ### 4. Testing & Documentation
48
-
49
- #### Test Script (`test-xsai.js`)
50
- - Created comprehensive test script to verify xsai integration
51
- - Tests both `generateText` and `streamText` with reasoning extraction
52
- - Provides easy way to validate setup with different API providers
53
-
54
- #### Documentation Updates
55
- - Updated README.md with xsai integration details
56
- - Added technical implementation details
57
- - Enhanced feature descriptions
58
- - Updated CHANGELOG.md with breaking changes
59
- - Version bumped to 0.2.0 (breaking change)
60
-
61
- ## πŸš€ Benefits of xsai Integration
62
-
63
- ### Performance
64
- - **Lightweight**: Smaller bundle size compared to multiple HTTP client dependencies
65
- - **Efficient**: Optimized for AI model interactions
66
- - **Runtime Agnostic**: Works in Node.js, Deno, Bun, and browsers
67
-
68
- ### Developer Experience
69
- - **Simplified API**: Consistent interface across different model providers
70
- - **Better Error Handling**: Built-in error handling and retry logic
71
- - **Type Safety**: Better TypeScript support for AI interactions
72
-
73
- ### Features
74
- - **Automatic Reasoning Extraction**: Built-in support for thinking processes
75
- - **Streaming Utilities**: Advanced streaming capabilities
76
- - **Multiple Providers**: Easily switch between different AI providers
77
-
78
- ## πŸ§ͺ Testing the Integration
79
-
80
- 1. **Start the server**:
81
- ```bash
82
- npm run server
83
- ```
84
-
85
- 2. **Test with the frontend**:
86
- ```bash
87
- npm start
88
- ```
89
-
90
- 3. **Run standalone tests**:
91
- ```bash
92
- node test-xsai.js
93
- ```
94
- (After updating API credentials in the test file)
95
-
96
- ## πŸ”§ Configuration
97
-
98
- The application maintains the same configuration interface:
99
- - API endpoints are automatically converted to xsai's baseURL format
100
- - All existing profiles and settings continue to work
101
- - No changes required to existing user configurations
102
-
103
- ## πŸ“‹ Migration Notes
104
-
105
- This is a **breaking change** internally but maintains API compatibility:
106
- - Server endpoints (`/api/chat`, `/api/summarize`) maintain same interface
107
- - Frontend code requires no changes
108
- - User configurations remain compatible
109
- - Docker deployments work without changes
110
-
111
- ## πŸŽ‰ Result
112
-
113
- The thinking-model-client now uses xsai for all LLM interactions, providing:
114
- - More reliable streaming
115
- - Better reasoning extraction
116
- - Cleaner codebase
117
- - Enhanced error handling
118
- - Future-proof architecture for AI model connections
119
-
120
- The migration is complete and fully functional!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
index.html CHANGED
@@ -5,9 +5,6 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
  <title>Thinking Model Client</title>
7
  <meta name="description" content="A client for interacting with thinking models" />
8
- <meta name="theme-color" content="#3e6ae1" />
9
- <link rel="manifest" href="/manifest.json" />
10
- <link rel="apple-touch-icon" href="/icons/icon-192x192.png" />
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
  <title>Thinking Model Client</title>
7
  <meta name="description" content="A client for interacting with thinking models" />
 
 
 
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
public/icons/icon-192x192.png DELETED
public/icons/icon-512x512.png DELETED
public/icons/icon-512x512.svg DELETED
public/manifest.json DELETED
@@ -1,59 +0,0 @@
1
- {
2
- "name": "Thinking Model Client",
3
- "short_name": "Thinking Model",
4
- "description": "A client for interacting with thinking models",
5
- "start_url": "/",
6
- "display": "standalone",
7
- "background_color": "#ffffff",
8
- "theme_color": "#3e6ae1",
9
- "icons": [
10
- {
11
- "src": "icons/icon-72x72.png",
12
- "sizes": "72x72",
13
- "type": "image/png",
14
- "purpose": "any maskable"
15
- },
16
- {
17
- "src": "icons/icon-96x96.png",
18
- "sizes": "96x96",
19
- "type": "image/png",
20
- "purpose": "any maskable"
21
- },
22
- {
23
- "src": "icons/icon-128x128.png",
24
- "sizes": "128x128",
25
- "type": "image/png",
26
- "purpose": "any maskable"
27
- },
28
- {
29
- "src": "icons/icon-144x144.png",
30
- "sizes": "144x144",
31
- "type": "image/png",
32
- "purpose": "any maskable"
33
- },
34
- {
35
- "src": "icons/icon-152x152.png",
36
- "sizes": "152x152",
37
- "type": "image/png",
38
- "purpose": "any maskable"
39
- },
40
- {
41
- "src": "icons/icon-192x192.png",
42
- "sizes": "192x192",
43
- "type": "image/png",
44
- "purpose": "any maskable"
45
- },
46
- {
47
- "src": "icons/icon-384x384.png",
48
- "sizes": "384x384",
49
- "type": "image/png",
50
- "purpose": "any maskable"
51
- },
52
- {
53
- "src": "icons/icon-512x512.png",
54
- "sizes": "512x512",
55
- "type": "image/png",
56
- "purpose": "any maskable"
57
- }
58
- ]
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/sw.js DELETED
@@ -1,80 +0,0 @@
1
- // Service Worker for Thinking Model Client PWA
2
-
3
- const CACHE_NAME = 'thinking-model-cache-v1';
4
- const urlsToCache = [
5
- '/',
6
- '/index.html',
7
- '/manifest.json',
8
- '/icons/icon-192x192.png',
9
- '/icons/icon-512x512.png'
10
- ];
11
-
12
- // Install event - cache basic assets
13
- self.addEventListener('install', event => {
14
- event.waitUntil(
15
- caches.open(CACHE_NAME)
16
- .then(cache => {
17
- console.log('Opened cache');
18
- return cache.addAll(urlsToCache);
19
- })
20
- );
21
- });
22
-
23
- // Activate event - clean up old caches
24
- self.addEventListener('activate', event => {
25
- const cacheWhitelist = [CACHE_NAME];
26
- event.waitUntil(
27
- caches.keys().then(cacheNames => {
28
- return Promise.all(
29
- cacheNames.map(cacheName => {
30
- if (cacheWhitelist.indexOf(cacheName) === -1) {
31
- return caches.delete(cacheName);
32
- }
33
- })
34
- );
35
- })
36
- );
37
- });
38
-
39
- // Fetch event - serve from cache if available, otherwise fetch from network
40
- self.addEventListener('fetch', event => {
41
- // Skip caching for localhost/development
42
- const isLocalhost = event.request.url.includes('localhost') || event.request.url.includes('127.0.0.1');
43
-
44
- if (isLocalhost) {
45
- // In development, always fetch from network (no caching)
46
- event.respondWith(fetch(event.request));
47
- return;
48
- }
49
-
50
- event.respondWith(
51
- caches.match(event.request)
52
- .then(response => {
53
- // Cache hit - return response
54
- if (response) {
55
- return response;
56
- }
57
- return fetch(event.request).then(
58
- response => {
59
- // Check if we received a valid response
60
- if (!response || response.status !== 200 || response.type !== 'basic') {
61
- return response;
62
- }
63
-
64
- // Clone the response
65
- const responseToCache = response.clone();
66
-
67
- caches.open(CACHE_NAME)
68
- .then(cache => {
69
- // Don't cache API requests
70
- if (!event.request.url.includes('/api/')) {
71
- cache.put(event.request, responseToCache);
72
- }
73
- });
74
-
75
- return response;
76
- }
77
- );
78
- })
79
- );
80
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/generate-icons.js DELETED
@@ -1,41 +0,0 @@
1
- // This script can be used to generate different sized icons from the SVG source
2
- // You would need to install sharp: npm install sharp
3
- // Then run: node scripts/generate-icons.js
4
-
5
- const fs = require('fs');
6
- const path = require('path');
7
- const sharp = require('sharp');
8
-
9
- const sizes = [72, 96, 128, 144, 152, 192, 384, 512];
10
- const svgPath = path.join(__dirname, '../public/icons/icon-512x512.svg');
11
- const outputDir = path.join(__dirname, '../public/icons');
12
-
13
- async function generateIcons() {
14
- try {
15
- // Make sure the output directory exists
16
- if (!fs.existsSync(outputDir)) {
17
- fs.mkdirSync(outputDir, { recursive: true });
18
- }
19
-
20
- // Read the SVG file
21
- const svgBuffer = fs.readFileSync(svgPath);
22
-
23
- // Generate each size
24
- for (const size of sizes) {
25
- const outputPath = path.join(outputDir, `icon-${size}x${size}.png`);
26
-
27
- await sharp(svgBuffer)
28
- .resize(size, size)
29
- .png()
30
- .toFile(outputPath);
31
-
32
- console.log(`Generated: ${outputPath}`);
33
- }
34
-
35
- console.log('All icons generated successfully!');
36
- } catch (error) {
37
- console.error('Error generating icons:', error);
38
- }
39
- }
40
-
41
- generateIcons();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/components/Settings.jsx CHANGED
@@ -1,5 +1,4 @@
1
  import { useState, useEffect } from 'react';
2
- import { clearAllCache, hardRefresh, checkCacheStatus } from '../utils/clearCache';
3
 
4
  function Settings({
5
  profiles,
@@ -707,96 +706,6 @@ function Settings({
707
  )}
708
  </div>
709
 
710
- {/* Developer Tools Section */}
711
- <div className="profiles-section">
712
- <h3>Developer Tools</h3>
713
- <div className="developer-tools-section">
714
- <div className="tool-group">
715
- <h4>Cache Management</h4>
716
- <p className="tool-description">Clear PWA cache and service workers that might interfere with page refreshing.</p>
717
-
718
- <div className="tool-buttons">
719
- <button
720
- type="button"
721
- className="dev-tool-button"
722
- onClick={async () => {
723
- try {
724
- await clearAllCache();
725
- alert('Cache cleared successfully! Page will refresh.');
726
- window.location.reload();
727
- } catch (error) {
728
- alert('Error clearing cache: ' + error.message);
729
- }
730
- }}
731
- >
732
- Clear All Cache
733
- </button>
734
-
735
- <button
736
- type="button"
737
- className="dev-tool-button secondary"
738
- onClick={async () => {
739
- try {
740
- await hardRefresh();
741
- } catch (error) {
742
- alert('Error performing hard refresh: ' + error.message);
743
- }
744
- }}
745
- >
746
- Hard Refresh
747
- </button>
748
-
749
- <button
750
- type="button"
751
- className="dev-tool-button secondary"
752
- onClick={async () => {
753
- try {
754
- await checkCacheStatus();
755
- alert('Check console for cache status details');
756
- } catch (error) {
757
- alert('Error checking cache status: ' + error.message);
758
- }
759
- }}
760
- >
761
- Check Cache Status
762
- </button>
763
- </div>
764
- </div>
765
-
766
- <div className="tool-group">
767
- <h4>Storage Management</h4>
768
- <p className="tool-description">Clear local storage data including chat history and settings.</p>
769
-
770
- <div className="tool-buttons">
771
- <button
772
- type="button"
773
- className="dev-tool-button warning"
774
- onClick={() => {
775
- if (confirm('This will clear all local data including chat history. Are you sure?')) {
776
- localStorage.clear();
777
- sessionStorage.clear();
778
- alert('Local storage cleared! Page will refresh.');
779
- window.location.reload();
780
- }
781
- }}
782
- >
783
- Clear Local Storage
784
- </button>
785
- </div>
786
- </div>
787
-
788
- <div className="tool-group">
789
- <h4>PWA Status</h4>
790
- <p className="tool-description">PWA (Progressive Web App) functionality is currently disabled to improve page refresh behavior.</p>
791
-
792
- <div className="pwa-info">
793
- <span className="status-indicator disabled">PWA Disabled</span>
794
- <small>Service worker registration is commented out in main.jsx</small>
795
- </div>
796
- </div>
797
- </div>
798
- </div>
799
-
800
  <div className="settings-actions">
801
  <button type="submit" className="save-button">Save Settings</button>
802
  <button type="button" className="cancel-button" onClick={onCloseSettings}>Cancel</button>
 
1
  import { useState, useEffect } from 'react';
 
2
 
3
  function Settings({
4
  profiles,
 
706
  )}
707
  </div>
708
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
  <div className="settings-actions">
710
  <button type="submit" className="save-button">Save Settings</button>
711
  <button type="button" className="cancel-button" onClick={onCloseSettings}>Cancel</button>
src/index.css CHANGED
@@ -2,113 +2,6 @@
2
  @import './styles/mcp.css';
3
  @import './styles/mcp-settings.css';
4
 
5
- /* Developer Tools Styles */
6
- .developer-tools-section {
7
- background: var(--background-secondary);
8
- border-radius: var(--border-radius);
9
- padding: 1rem;
10
- margin-top: 1rem;
11
- }
12
-
13
- .tool-group {
14
- margin-bottom: 1.5rem;
15
- border-bottom: 1px solid var(--border-color);
16
- padding-bottom: 1rem;
17
- }
18
-
19
- .tool-group:last-child {
20
- border-bottom: none;
21
- margin-bottom: 0;
22
- }
23
-
24
- .tool-group h4 {
25
- color: var(--text-color);
26
- font-size: 1rem;
27
- font-weight: 600;
28
- margin-bottom: 0.5rem;
29
- }
30
-
31
- .tool-description {
32
- color: var(--text-secondary);
33
- font-size: 0.875rem;
34
- margin-bottom: 1rem;
35
- line-height: 1.5;
36
- }
37
-
38
- .tool-buttons {
39
- display: flex;
40
- gap: 0.75rem;
41
- flex-wrap: wrap;
42
- }
43
-
44
- .dev-tool-button {
45
- padding: 0.5rem 1rem;
46
- border: 1px solid var(--border-color);
47
- border-radius: var(--border-radius);
48
- background: var(--background-primary);
49
- color: var(--text-color);
50
- font-size: 0.875rem;
51
- cursor: pointer;
52
- transition: all var(--transition-fast);
53
- font-weight: 500;
54
- }
55
-
56
- .dev-tool-button:hover {
57
- background: var(--background-secondary);
58
- border-color: var(--primary-color);
59
- color: var(--primary-color);
60
- }
61
-
62
- .dev-tool-button.secondary {
63
- background: var(--background-secondary);
64
- color: var(--text-secondary);
65
- }
66
-
67
- .dev-tool-button.secondary:hover {
68
- background: var(--background-tertiary);
69
- color: var(--text-color);
70
- }
71
-
72
- .dev-tool-button.warning {
73
- background: var(--warning-light);
74
- color: var(--warning-color);
75
- border-color: var(--warning-color);
76
- }
77
-
78
- .dev-tool-button.warning:hover {
79
- background: var(--warning-color);
80
- color: white;
81
- }
82
-
83
- .pwa-info {
84
- display: flex;
85
- align-items: center;
86
- gap: 0.75rem;
87
- padding: 0.75rem;
88
- background: var(--background-tertiary);
89
- border-radius: var(--border-radius);
90
- border: 1px solid var(--border-color);
91
- }
92
-
93
- .status-indicator {
94
- padding: 0.25rem 0.75rem;
95
- border-radius: 9999px;
96
- font-size: 0.75rem;
97
- font-weight: 600;
98
- text-transform: uppercase;
99
- letter-spacing: 0.05em;
100
- }
101
-
102
- .status-indicator.disabled {
103
- background: var(--error-light);
104
- color: var(--error-color);
105
- }
106
-
107
- .pwa-info small {
108
- color: var(--text-muted);
109
- font-size: 0.75rem;
110
- }
111
-
112
  @tailwind base;
113
  @tailwind components;
114
  @tailwind utilities;
 
2
  @import './styles/mcp.css';
3
  @import './styles/mcp-settings.css';
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  @tailwind base;
6
  @tailwind components;
7
  @tailwind utilities;
src/main.jsx CHANGED
@@ -3,13 +3,9 @@ import ReactDOM from 'react-dom/client'
3
  import App from './App'
4
  import './tailwind.css'
5
  import './index.css'
6
- // import { register as registerServiceWorker } from './serviceWorkerRegistration'
7
 
8
  ReactDOM.createRoot(document.getElementById('root')).render(
9
  <React.StrictMode>
10
  <App />
11
  </React.StrictMode>,
12
  )
13
-
14
- // PWA functionality disabled to allow proper refreshing
15
- // registerServiceWorker()
 
3
  import App from './App'
4
  import './tailwind.css'
5
  import './index.css'
 
6
 
7
  ReactDOM.createRoot(document.getElementById('root')).render(
8
  <React.StrictMode>
9
  <App />
10
  </React.StrictMode>,
11
  )
 
 
 
src/serviceWorkerRegistration.js DELETED
@@ -1,134 +0,0 @@
1
- // This optional code is used to register a service worker.
2
- // register() is not called by default.
3
-
4
- // This lets the app load faster on subsequent visits in production, and gives
5
- // it offline capabilities. However, it also means that developers (and users)
6
- // will only see deployed updates on subsequent visits to a page, after all the
7
- // existing tabs open on the page have been closed, since previously cached
8
- // resources are updated in the background.
9
-
10
- const isLocalhost = Boolean(
11
- window.location.hostname === 'localhost' ||
12
- // [::1] is the IPv6 localhost address.
13
- window.location.hostname === '[::1]' ||
14
- // 127.0.0.0/8 are considered localhost for IPv4.
15
- window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
16
- );
17
-
18
- export function register(config) {
19
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
20
- // The URL constructor is available in all browsers that support SW.
21
- const publicUrl = new URL(import.meta.env.BASE_URL, window.location.href);
22
- if (publicUrl.origin !== window.location.origin) {
23
- // Our service worker won't work if BASE_URL is on a different origin
24
- // from what our page is served on. This might happen if a CDN is used to
25
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
26
- return;
27
- }
28
-
29
- window.addEventListener('load', () => {
30
- const swUrl = `${import.meta.env.BASE_URL}sw.js`;
31
-
32
- if (isLocalhost) {
33
- // This is running on localhost. Let's check if a service worker still exists or not.
34
- checkValidServiceWorker(swUrl, config);
35
-
36
- // Add some additional logging to localhost, pointing developers to the
37
- // service worker/PWA documentation.
38
- navigator.serviceWorker.ready.then(() => {
39
- console.log(
40
- 'This web app is being served cache-first by a service ' +
41
- 'worker. To learn more, visit https://cra.link/PWA'
42
- );
43
- });
44
- } else {
45
- // Is not localhost. Just register service worker
46
- registerValidSW(swUrl, config);
47
- }
48
- });
49
- }
50
- }
51
-
52
- function registerValidSW(swUrl, config) {
53
- navigator.serviceWorker
54
- .register(swUrl)
55
- .then((registration) => {
56
- registration.onupdatefound = () => {
57
- const installingWorker = registration.installing;
58
- if (installingWorker == null) {
59
- return;
60
- }
61
- installingWorker.onstatechange = () => {
62
- if (installingWorker.state === 'installed') {
63
- if (navigator.serviceWorker.controller) {
64
- // At this point, the updated precached content has been fetched,
65
- // but the previous service worker will still serve the older
66
- // content until all client tabs are closed.
67
- console.log(
68
- 'New content is available and will be used when all ' +
69
- 'tabs for this page are closed. See https://cra.link/PWA.'
70
- );
71
-
72
- // Execute callback
73
- if (config && config.onUpdate) {
74
- config.onUpdate(registration);
75
- }
76
- } else {
77
- // At this point, everything has been precached.
78
- // It's the perfect time to display a
79
- // "Content is cached for offline use." message.
80
- console.log('Content is cached for offline use.');
81
-
82
- // Execute callback
83
- if (config && config.onSuccess) {
84
- config.onSuccess(registration);
85
- }
86
- }
87
- }
88
- };
89
- };
90
- })
91
- .catch((error) => {
92
- console.error('Error during service worker registration:', error);
93
- });
94
- }
95
-
96
- function checkValidServiceWorker(swUrl, config) {
97
- // Check if the service worker can be found. If it can't reload the page.
98
- fetch(swUrl, {
99
- headers: { 'Service-Worker': 'script' },
100
- })
101
- .then((response) => {
102
- // Ensure service worker exists, and that we really are getting a JS file.
103
- const contentType = response.headers.get('content-type');
104
- if (
105
- response.status === 404 ||
106
- (contentType != null && contentType.indexOf('javascript') === -1)
107
- ) {
108
- // No service worker found. Probably a different app. Reload the page.
109
- navigator.serviceWorker.ready.then((registration) => {
110
- registration.unregister().then(() => {
111
- window.location.reload();
112
- });
113
- });
114
- } else {
115
- // Service worker found. Proceed as normal.
116
- registerValidSW(swUrl, config);
117
- }
118
- })
119
- .catch(() => {
120
- console.log('No internet connection found. App is running in offline mode.');
121
- });
122
- }
123
-
124
- export function unregister() {
125
- if ('serviceWorker' in navigator) {
126
- navigator.serviceWorker.ready
127
- .then((registration) => {
128
- registration.unregister();
129
- })
130
- .catch((error) => {
131
- console.error(error.message);
132
- });
133
- }
134
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/utils/clearCache.js DELETED
@@ -1,68 +0,0 @@
1
- // Utility to clear PWA cache and service worker
2
-
3
- export async function clearAllCache() {
4
- try {
5
- // Unregister all service workers
6
- if ('serviceWorker' in navigator) {
7
- const registrations = await navigator.serviceWorker.getRegistrations();
8
- for (let registration of registrations) {
9
- await registration.unregister();
10
- console.log('Service worker unregistered:', registration);
11
- }
12
- }
13
-
14
- // Clear all caches
15
- if ('caches' in window) {
16
- const cacheNames = await caches.keys();
17
- await Promise.all(
18
- cacheNames.map(cacheName => {
19
- console.log('Deleting cache:', cacheName);
20
- return caches.delete(cacheName);
21
- })
22
- );
23
- }
24
-
25
- // Clear localStorage and sessionStorage
26
- localStorage.clear();
27
- sessionStorage.clear();
28
-
29
- console.log('All cache and storage cleared!');
30
- return true;
31
- } catch (error) {
32
- console.error('Error clearing cache:', error);
33
- return false;
34
- }
35
- }
36
-
37
- export async function hardRefresh() {
38
- await clearAllCache();
39
-
40
- // Force hard refresh
41
- if (typeof window !== 'undefined') {
42
- // Try different hard refresh methods
43
- if (window.location.reload) {
44
- window.location.reload(true); // Force reload
45
- } else {
46
- window.location.href = window.location.href;
47
- }
48
- }
49
- }
50
-
51
- // Debug function to check cache status
52
- export async function checkCacheStatus() {
53
- if ('caches' in window) {
54
- const cacheNames = await caches.keys();
55
- console.log('Active caches:', cacheNames);
56
-
57
- for (const cacheName of cacheNames) {
58
- const cache = await caches.open(cacheName);
59
- const requests = await cache.keys();
60
- console.log(`Cache ${cacheName} contains:`, requests.map(req => req.url));
61
- }
62
- }
63
-
64
- if ('serviceWorker' in navigator) {
65
- const registrations = await navigator.serviceWorker.getRegistrations();
66
- console.log('Active service workers:', registrations);
67
- }
68
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test-xsai.js DELETED
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { streamText } from '@xsai/stream-text';
4
- import { generateText } from '@xsai/generate-text';
5
- import { extractReasoningStream } from '@xsai/utils-reasoning';
6
-
7
- // Test configuration - replace with your actual API details
8
- const testConfig = {
9
- baseURL: 'https://api.deepseek.com/v1', // Example - replace with your API endpoint
10
- apiKey: 'your-api-key-here', // Replace with your actual API key
11
- model: 'deepseek-r1' // Replace with your model
12
- };
13
-
14
- async function testGenerateText() {
15
- console.log('πŸ§ͺ Testing xsai generateText integration...\n');
16
-
17
- try {
18
- const { text } = await generateText({
19
- apiKey: testConfig.apiKey,
20
- baseURL: testConfig.baseURL,
21
- model: testConfig.model,
22
- messages: [{
23
- role: 'user',
24
- content: 'Summarize this in 3-5 words: Hello, how are you today? I am doing well, thanks for asking!'
25
- }],
26
- temperature: 0.2,
27
- max_tokens: 20
28
- });
29
-
30
- console.log('βœ… GenerateText test successful!');
31
- console.log('πŸ“ Summary result:', text.trim());
32
-
33
- } catch (error) {
34
- console.error('❌ GenerateText test failed:', error.message);
35
- }
36
- }
37
-
38
- async function testStreamText() {
39
- console.log('\nπŸ§ͺ Testing xsai streamText with reasoning extraction...\n');
40
-
41
- try {
42
- const { textStream } = await streamText({
43
- apiKey: testConfig.apiKey,
44
- baseURL: testConfig.baseURL,
45
- model: testConfig.model,
46
- messages: [
47
- { role: 'system', content: 'You are a helpful assistant. Use <think></think> tags to show your reasoning process.' },
48
- { role: 'user', content: 'Why is the sky blue? Please think through this step by step.' }
49
- ]
50
- });
51
-
52
- // Extract reasoning and content streams
53
- const { reasoningStream, textStream: contentStream } = extractReasoningStream(textStream);
54
-
55
- console.log('🧠 Reasoning process:');
56
- console.log('='.repeat(50));
57
- let reasoningText = '';
58
- for await (const chunk of reasoningStream) {
59
- process.stdout.write(chunk);
60
- reasoningText += chunk;
61
- }
62
-
63
- console.log('\n' + '='.repeat(50));
64
- console.log('\nπŸ’¬ Final answer:');
65
- console.log('='.repeat(50));
66
- for await (const chunk of contentStream) {
67
- process.stdout.write(chunk);
68
- }
69
-
70
- console.log('\n' + '='.repeat(50));
71
- console.log('\nβœ… StreamText test successful!');
72
-
73
- } catch (error) {
74
- console.error('❌ StreamText test failed:', error.message);
75
- }
76
- }
77
-
78
- async function runTests() {
79
- console.log('πŸš€ Testing xsai integration for thinking-model-client\n');
80
-
81
- // Check if configuration is set
82
- if (testConfig.apiKey === 'your-api-key-here') {
83
- console.log('⚠️ Please update the testConfig in this file with your actual API details before running tests.');
84
- console.log('πŸ“ Edit the testConfig object at the top of this file.');
85
- return;
86
- }
87
-
88
- await testGenerateText();
89
- await testStreamText();
90
-
91
- console.log('\nπŸŽ‰ All tests completed!');
92
- }
93
-
94
- runTests().catch(console.error);