worksona-js 0.2.0 → 0.3.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 +166 -14
- package/agents/interviewer-agent.json +1 -1
- package/agents/legal-agent.json +1 -1
- package/agents/marketing-agent.json +1 -1
- package/agents/prd-editor-agent.json +9 -18
- package/agents/research-analyst.json +1 -1
- package/package.json +27 -4
- package/worksona.js +84 -23
- package/worksona.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
# Worksona.js
|
|
2
2
|
|
|
3
|
+
**Last Updated:** January 19, 2026
|
|
4
|
+
**Version:** 0.3.0
|
|
5
|
+
|
|
3
6
|
[](https://badge.fury.io/js/worksona-js)
|
|
4
7
|
[](https://opensource.org/licenses/MIT)
|
|
5
8
|
[](https://npmjs.com/package/worksona-js)
|
|
6
9
|
|
|
7
|
-
A lightweight, single-file JavaScript library for creating and managing AI agents with distinct personalities across multiple LLM providers.
|
|
10
|
+
A lightweight, single-file JavaScript library for creating and managing AI agents with distinct personalities across multiple LLM providers. Now supporting the latest frontier models including GPT-5, Claude Opus 4.5, and Claude Sonnet 4.5.
|
|
11
|
+
|
|
12
|
+
## 🆕 What's New in v0.3.0
|
|
13
|
+
|
|
14
|
+
- 📚 **Complete Documentation Suite** - Interactive demos, code examples, visual workflow builder
|
|
15
|
+
- 🔌 **REST API Server** - Production-ready Express server with 32+ endpoints
|
|
16
|
+
- 🛠️ **Tool System** - DALL-E image generation, web scraper, text-to-speech
|
|
17
|
+
- 🎨 **Agent Personality System** - Rich configuration with traits, knowledge, tone
|
|
18
|
+
- 📄 **Document Processing** - OCR, PDF/DOCX/XLSX parsing built-in
|
|
19
|
+
- ✨ **Latest Frontier Models** - Full support for GPT-5, Claude Opus 4.5, o3
|
|
20
|
+
- 🔗 **Multi-Agent Workflows** - Build and execute complex agent delegation chains
|
|
8
21
|
|
|
9
22
|
## ✨ Features
|
|
10
23
|
|
|
@@ -20,15 +33,20 @@ A lightweight, single-file JavaScript library for creating and managing AI agent
|
|
|
20
33
|
|
|
21
34
|
### Installation
|
|
22
35
|
|
|
36
|
+
**Via NPM:**
|
|
23
37
|
```bash
|
|
24
|
-
npm
|
|
38
|
+
npm i worksona-js
|
|
25
39
|
```
|
|
26
40
|
|
|
27
|
-
|
|
41
|
+
**Via CDN:**
|
|
28
42
|
```html
|
|
29
43
|
<script src="https://unpkg.com/worksona-js@latest/worksona.min.js"></script>
|
|
30
44
|
```
|
|
31
45
|
|
|
46
|
+
**NPM Package:** https://www.npmjs.com/package/worksona-js
|
|
47
|
+
|
|
48
|
+
**Live Documentation:** The complete documentation site is available at `docs/www-api/` and can be deployed to any static hosting provider (Netlify, Vercel, GitHub Pages, etc.)
|
|
49
|
+
|
|
32
50
|
### Basic Usage
|
|
33
51
|
|
|
34
52
|
```javascript
|
|
@@ -40,7 +58,7 @@ const worksona = new Worksona({
|
|
|
40
58
|
}
|
|
41
59
|
});
|
|
42
60
|
|
|
43
|
-
// Load an agent
|
|
61
|
+
// Load an agent with latest GPT-5 model
|
|
44
62
|
await worksona.loadAgent({
|
|
45
63
|
id: 'customer-service',
|
|
46
64
|
name: 'Sarah',
|
|
@@ -52,12 +70,25 @@ await worksona.loadAgent({
|
|
|
52
70
|
},
|
|
53
71
|
config: {
|
|
54
72
|
provider: 'openai',
|
|
55
|
-
model: 'gpt-4o'
|
|
73
|
+
model: 'gpt-5', // Or 'gpt-5-mini', 'gpt-5-nano', 'o3', 'gpt-4o'
|
|
56
74
|
temperature: 0.7,
|
|
57
75
|
systemPrompt: 'You are Sarah, a helpful customer service representative...'
|
|
58
76
|
}
|
|
59
77
|
});
|
|
60
78
|
|
|
79
|
+
// Load an agent with Claude Opus 4.5
|
|
80
|
+
await worksona.loadAgent({
|
|
81
|
+
id: 'technical-writer',
|
|
82
|
+
name: 'Alex',
|
|
83
|
+
description: 'Technical documentation specialist',
|
|
84
|
+
config: {
|
|
85
|
+
provider: 'anthropic',
|
|
86
|
+
model: 'claude-opus-4-5-20251101', // Or 'claude-sonnet-4-5-20250929'
|
|
87
|
+
temperature: 0.5,
|
|
88
|
+
systemPrompt: 'You are Alex, an expert technical writer...'
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
61
92
|
// Chat with the agent
|
|
62
93
|
const response = await worksona.chat('customer-service', 'How do I return an item?');
|
|
63
94
|
console.log(response);
|
|
@@ -91,11 +122,31 @@ const editedUrl = await worksona.editImage('agent-id', imageData,
|
|
|
91
122
|
|
|
92
123
|
## 🔧 Provider Support
|
|
93
124
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
|
97
|
-
|
|
98
|
-
|
|
|
125
|
+
### Latest Frontier Models
|
|
126
|
+
|
|
127
|
+
| Provider | Latest Models | Chat | Vision | Image Generation |
|
|
128
|
+
|----------|--------------|------|---------|-----------------|
|
|
129
|
+
| **OpenAI** | GPT-5, GPT-5-mini, GPT-5-nano, o3, o1, GPT-4o | ✅ | ✅ | ✅ DALL-E 3 |
|
|
130
|
+
| **Anthropic** | Claude Opus 4.5, Claude Sonnet 4.5, Claude 3.5 Sonnet | ✅ | ❌ | ❌ |
|
|
131
|
+
| **Google** | Gemini Pro | ✅ | ❌ | ❌ |
|
|
132
|
+
|
|
133
|
+
### Supported Models by Provider
|
|
134
|
+
|
|
135
|
+
**OpenAI:**
|
|
136
|
+
- GPT-5 series: `gpt-5`, `gpt-5-mini`, `gpt-5-nano` 🆕
|
|
137
|
+
- Reasoning models: `o3`, `o3-mini`, `o1`, `o1-mini`, `o1-preview` 🆕
|
|
138
|
+
- GPT-4 series: `gpt-4o`, `gpt-4o-mini`, `gpt-4-turbo`, `gpt-4`, `gpt-4-32k`
|
|
139
|
+
- GPT-3.5 series: `gpt-3.5-turbo`, `gpt-3.5-turbo-16k`
|
|
140
|
+
- Image generation: `dall-e-3`, `dall-e-2`
|
|
141
|
+
|
|
142
|
+
**Anthropic:**
|
|
143
|
+
- Claude 4.5: `claude-opus-4-5-20251101`, `claude-sonnet-4-5-20250929` 🆕
|
|
144
|
+
- Claude 3.5: `claude-3-5-sonnet-20241022`, `claude-3-5-haiku-20241022`
|
|
145
|
+
- Claude 3: `claude-3-opus-20240229`, `claude-3-sonnet-20240229`, `claude-3-haiku-20240307`
|
|
146
|
+
- Legacy: `claude-2.1`, `claude-2.0`, `claude-instant-1.2`
|
|
147
|
+
|
|
148
|
+
**Google:**
|
|
149
|
+
- Gemini: `gemini-pro`, `gemini-pro-vision`
|
|
99
150
|
|
|
100
151
|
## 📖 API Reference
|
|
101
152
|
|
|
@@ -278,11 +329,112 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
278
329
|
|
|
279
330
|
Contributions welcome! Please read our [contributing guidelines](CONTRIBUTING.md) first.
|
|
280
331
|
|
|
281
|
-
## 📚 Documentation
|
|
332
|
+
## 📚 Documentation & Resources
|
|
333
|
+
|
|
334
|
+
The complete documentation site is available in `docs/www-api/` and includes:
|
|
335
|
+
|
|
336
|
+
### 🎯 Quick Links
|
|
337
|
+
|
|
338
|
+
**Documentation**
|
|
339
|
+
- **[📖 Documentation Hub](docs/www-api/docs/index.html)** - Central documentation portal
|
|
340
|
+
- **[🔌 API Reference (Swagger)](docs/www-api/docs/api-reference-swagger.html)** - Interactive API documentation
|
|
341
|
+
- **[💻 Code Examples](docs/www-api/docs/code-examples-hub.html)** - 60+ copy/paste examples
|
|
342
|
+
|
|
343
|
+
**Interactive Demos**
|
|
344
|
+
- **[🎮 Demos Home](docs/www-api/demos/index.html)** - All interactive demos
|
|
345
|
+
- **[🔌 Endpoint API Demo](docs/www-api/demos/endpoint-api-demo.html)** - Test all REST endpoints
|
|
346
|
+
- **[📚 Library Demo](docs/www-api/demos/library-internal-demo.html)** - Direct library usage
|
|
347
|
+
- **[🔗 Delegation Workflow](docs/www-api/demos/delegation-demo.html)** - Visual multi-agent workflows
|
|
348
|
+
|
|
349
|
+
**Vibe Coding (AI-Assisted Development)**
|
|
350
|
+
- **[🎵 Vibe Coding Home](docs/www-api/vibe-coding/index.html)** - AI coding assistant support
|
|
351
|
+
- **[📝 AI Coding Prompt](docs/www-api/vibe-coding/AI_CODING_PROMPT.md)** - Prompts for Claude, ChatGPT, Copilot
|
|
352
|
+
- **[💡 Examples](docs/www-api/vibe-coding/examples/)** - Chatbot, content pipeline, workflow builder
|
|
353
|
+
|
|
354
|
+
**Downloads**
|
|
355
|
+
- **[📦 worksona.min.js](docs/www-api/downloads/worksona.min.js)** - Minified library (51KB)
|
|
356
|
+
- **[📦 worksona.js](docs/www-api/downloads/worksona.js)** - Full source (80KB)
|
|
357
|
+
- **[📦 worksona-server.js](docs/www-api/downloads/worksona-server.js)** - REST API server
|
|
358
|
+
- **[📦 worksona.d.ts](docs/www-api/downloads/worksona.d.ts)** - TypeScript definitions
|
|
359
|
+
- **[📦 Complete Package (.zip)](docs/www-api/downloads/worksona-complete.zip)** - All files bundled
|
|
360
|
+
|
|
361
|
+
### 🌐 Deploying the Documentation Site
|
|
362
|
+
|
|
363
|
+
The documentation site in `docs/www-api/` is a standalone static site that can be deployed anywhere:
|
|
364
|
+
|
|
365
|
+
**Netlify (Recommended)**
|
|
366
|
+
```bash
|
|
367
|
+
# Deploy from repository root
|
|
368
|
+
netlify deploy --dir=docs/www-api --prod
|
|
369
|
+
|
|
370
|
+
# Or use the included netlify.toml configuration
|
|
371
|
+
cd docs/www-api
|
|
372
|
+
netlify deploy --prod
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Vercel**
|
|
376
|
+
```bash
|
|
377
|
+
cd docs/www-api
|
|
378
|
+
vercel --prod
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**GitHub Pages**
|
|
382
|
+
```bash
|
|
383
|
+
# Push to gh-pages branch
|
|
384
|
+
git subtree push --prefix docs/www-api origin gh-pages
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Any Static Host**
|
|
388
|
+
Simply upload the contents of `docs/www-api/` to your web server or CDN.
|
|
389
|
+
|
|
390
|
+
### 📖 Documentation Structure
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
docs/www-api/
|
|
394
|
+
├── index.html # Landing page
|
|
395
|
+
├── overview.html # Project overview
|
|
396
|
+
├── assets/ # Shared CSS and JS
|
|
397
|
+
│ ├── css/
|
|
398
|
+
│ │ └── navigation.css # Unified navigation styles
|
|
399
|
+
│ └── js/
|
|
400
|
+
│ └── navigation.js # Navigation functionality
|
|
401
|
+
├── docs/ # Documentation section
|
|
402
|
+
│ ├── index.html
|
|
403
|
+
│ ├── api-reference-swagger.html
|
|
404
|
+
│ └── code-examples-hub.html
|
|
405
|
+
├── demos/ # Interactive demos
|
|
406
|
+
│ ├── index.html
|
|
407
|
+
│ ├── endpoint-api-demo.html
|
|
408
|
+
│ ├── library-internal-demo.html
|
|
409
|
+
│ ├── delegation-demo.html
|
|
410
|
+
│ └── examples/
|
|
411
|
+
├── vibe-coding/ # AI coding assistant support
|
|
412
|
+
│ ├── index.html
|
|
413
|
+
│ ├── AI_CODING_PROMPT.md
|
|
414
|
+
│ ├── README.md
|
|
415
|
+
│ └── examples/
|
|
416
|
+
├── marketing/ # Marketing site
|
|
417
|
+
│ └── index.html
|
|
418
|
+
├── downloads/ # Downloadable files
|
|
419
|
+
│ ├── worksona.min.js
|
|
420
|
+
│ ├── worksona.js
|
|
421
|
+
│ ├── worksona-server.js
|
|
422
|
+
│ ├── worksona.d.ts
|
|
423
|
+
│ └── *.zip
|
|
424
|
+
└── netlify.toml # Netlify configuration
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### 🎨 Features of the Documentation Site
|
|
428
|
+
|
|
429
|
+
- **Unified Left Rail Navigation** - Persistent navigation on desktop, hamburger menu on mobile
|
|
430
|
+
- **Responsive Design** - Optimized for all screen sizes
|
|
431
|
+
- **Interactive Demos** - Test all features directly in browser
|
|
432
|
+
- **Code Examples** - Copy/paste ready examples in multiple languages
|
|
433
|
+
- **AI Coding Support** - Full Vibe Coding integration for AI assistants
|
|
434
|
+
- **Downloadable Files** - All library files available for offline use
|
|
435
|
+
- **SEO Optimized** - Proper meta tags and structure
|
|
282
436
|
|
|
283
|
-
|
|
284
|
-
- [API Reference](docs/api-reference.html)
|
|
285
|
-
- [Live Examples](docs/)
|
|
437
|
+
**→ Start here: [docs/index.html](docs/index.html)**
|
|
286
438
|
|
|
287
439
|
## 🔗 Links
|
|
288
440
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"config": {
|
|
12
12
|
"provider": "openai",
|
|
13
|
-
"model": "gpt-
|
|
13
|
+
"model": "gpt-4o",
|
|
14
14
|
"temperature": 0.6,
|
|
15
15
|
"maxTokens": 2000,
|
|
16
16
|
"systemPrompt": "You are Reporter Thompson, a political journalist specializing in Canadian elections. Your process involves: 1) Research current Canadian election news and developments, 2) Analyze key issues and party positions, 3) Develop 10 insightful questions based on recent developments, 4) Conduct the interview with follow-up questions, 5) Summarize key findings and insights. Always begin by explaining your research process and the topics you'll cover. Questions should be based on the most current news and developments in the Canadian election. Be prepared to ask follow-up questions based on the interviewee's responses. Maintain a balance between hard-hitting political questions and broader policy discussions.",
|
package/agents/legal-agent.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"config": {
|
|
12
12
|
"provider": "openai",
|
|
13
|
-
"model": "gpt-
|
|
13
|
+
"model": "gpt-4o",
|
|
14
14
|
"temperature": 0.3,
|
|
15
15
|
"maxTokens": 800,
|
|
16
16
|
"systemPrompt": "You are James, a legal consultant with expertise in business law. Your role is to provide clear, accurate legal information while emphasizing that you are not providing legal advice. Always maintain a formal and precise tone, and be sure to recommend consulting with a licensed attorney for specific legal matters.",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"config": {
|
|
12
12
|
"provider": "openai",
|
|
13
|
-
"model": "gpt-
|
|
13
|
+
"model": "gpt-4o",
|
|
14
14
|
"temperature": 0.8,
|
|
15
15
|
"maxTokens": 600,
|
|
16
16
|
"systemPrompt": "You are Emma, a creative marketing strategist. Your expertise lies in developing compelling marketing campaigns and brand strategies. You excel at understanding target audiences and creating engaging content that drives results. Always provide actionable insights and creative solutions while maintaining a professional yet enthusiastic tone.",
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
],
|
|
12
|
-
"api": {
|
|
13
|
-
"type": "worksona",
|
|
14
|
-
"endpoints": [
|
|
15
|
-
"analyze",
|
|
16
|
-
"edit",
|
|
17
|
-
"summarize",
|
|
18
|
-
"qualify"
|
|
19
|
-
]
|
|
2
|
+
"id": "prd-editor-agent",
|
|
3
|
+
"name": "PRD Editor",
|
|
4
|
+
"description": "A long-form Worksona agent specialized in reviewing, editing, and refining PRD documents. The agent can answer questions, propose changes, and ask qualifying questions before making edits.",
|
|
5
|
+
"config": {
|
|
6
|
+
"provider": "openai",
|
|
7
|
+
"model": "gpt-4o",
|
|
8
|
+
"temperature": 0.7,
|
|
9
|
+
"maxTokens": 1000,
|
|
10
|
+
"systemPrompt": "You are a helpful, detail-oriented product requirements document (PRD) editor. You can analyze, rewrite, and improve sections of a PRD based on user instructions. Always ask clarifying questions if the user's request is ambiguous, and confirm changes before applying them. Respond in markdown format."
|
|
20
11
|
}
|
|
21
12
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"config": {
|
|
12
12
|
"provider": "openai",
|
|
13
|
-
"model": "gpt-
|
|
13
|
+
"model": "gpt-4o",
|
|
14
14
|
"temperature": 0.4,
|
|
15
15
|
"maxTokens": 2000,
|
|
16
16
|
"systemPrompt": "You are Dr. Chen, a senior research analyst. Your approach involves: 1) Initial consultation to understand research goals, 2) Development of research methodology, 3) Data collection and analysis, 4) Interim findings presentation, 5) Final comprehensive report. Always begin by understanding the client's specific needs, timeline, and desired depth of analysis. Break down complex research into manageable milestones and provide regular updates. Ensure all findings are well-documented and supported by data.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "worksona-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A lightweight, single-file JavaScript library for creating and managing AI agents with distinct personalities across multiple LLM providers. Features comprehensive image processing, real-time control panel, and event-driven architecture.",
|
|
5
5
|
"main": "worksona.js",
|
|
6
6
|
"browser": "worksona.min.js",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"minify": "terser worksona.js -o worksona.min.js --compress --mangle",
|
|
22
22
|
"validate": "node -c worksona.js",
|
|
23
23
|
"prepare": "npm run build",
|
|
24
|
-
"prepack": "npm run validate && npm run build"
|
|
24
|
+
"prepack": "npm run validate && npm run build",
|
|
25
|
+
"start": "node worksona-server.js",
|
|
26
|
+
"dev": "node worksona-server.js"
|
|
25
27
|
},
|
|
26
28
|
"keywords": [
|
|
27
29
|
"ai",
|
|
@@ -37,7 +39,13 @@
|
|
|
37
39
|
"image-analysis",
|
|
38
40
|
"image-generation",
|
|
39
41
|
"dall-e",
|
|
42
|
+
"gpt-5",
|
|
40
43
|
"gpt-4o",
|
|
44
|
+
"claude-opus-4.5",
|
|
45
|
+
"claude-sonnet-4.5",
|
|
46
|
+
"o1",
|
|
47
|
+
"o3",
|
|
48
|
+
"frontier-models",
|
|
41
49
|
"javascript",
|
|
42
50
|
"single-file",
|
|
43
51
|
"lightweight",
|
|
@@ -46,7 +54,9 @@
|
|
|
46
54
|
"personality",
|
|
47
55
|
"chatbot",
|
|
48
56
|
"vision",
|
|
49
|
-
"control-panel"
|
|
57
|
+
"control-panel",
|
|
58
|
+
"agentic-orchestration",
|
|
59
|
+
"entrepreneurial-prototyping"
|
|
50
60
|
],
|
|
51
61
|
"author": {
|
|
52
62
|
"name": "Worksona Team",
|
|
@@ -77,6 +87,19 @@
|
|
|
77
87
|
"registry": "https://registry.npmjs.org/"
|
|
78
88
|
},
|
|
79
89
|
"dependencies": {
|
|
80
|
-
"@sodanovels/worksona": "^0.2.0"
|
|
90
|
+
"@sodanovels/worksona": "^0.2.0",
|
|
91
|
+
"axios": "^1.13.2",
|
|
92
|
+
"cheerio": "^1.1.2",
|
|
93
|
+
"cors": "^2.8.5",
|
|
94
|
+
"dotenv": "^17.2.3",
|
|
95
|
+
"express": "^5.2.1",
|
|
96
|
+
"express-rate-limit": "^8.2.1",
|
|
97
|
+
"helmet": "^8.1.0",
|
|
98
|
+
"mammoth": "^1.11.0",
|
|
99
|
+
"marked": "^17.0.1",
|
|
100
|
+
"multer": "^2.0.2",
|
|
101
|
+
"pdf-parse": "^2.4.5",
|
|
102
|
+
"worksona-js": "^0.2.0",
|
|
103
|
+
"xlsx": "^0.18.5"
|
|
81
104
|
}
|
|
82
105
|
}
|
package/worksona.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Worksona.js - LLM Agent Management API
|
|
3
|
-
* Version: 0.
|
|
4
|
-
*
|
|
3
|
+
* Version: 0.2.0
|
|
4
|
+
*
|
|
5
5
|
* A lightweight, single-file solution for deploying and managing AI agents
|
|
6
6
|
* with distinct personalities across multiple LLM providers.
|
|
7
|
+
*
|
|
8
|
+
* Supports latest frontier models:
|
|
9
|
+
* - OpenAI: GPT-5, GPT-5-mini, GPT-5-nano, o1, o3, DALL-E 3, GPT-4o
|
|
10
|
+
* - Anthropic: Claude Opus 4.5, Claude Sonnet 4.5, Claude 3.5 Sonnet
|
|
11
|
+
* - Backward compatible with all previous models
|
|
7
12
|
*/
|
|
8
13
|
|
|
9
14
|
'use strict';
|
|
@@ -98,7 +103,7 @@ class Agent {
|
|
|
98
103
|
this.options = {
|
|
99
104
|
debug: false,
|
|
100
105
|
defaultProvider: 'openai',
|
|
101
|
-
defaultModel: 'gpt-
|
|
106
|
+
defaultModel: 'gpt-4o', // Updated default to latest stable model
|
|
102
107
|
apiKeys: {},
|
|
103
108
|
...options
|
|
104
109
|
};
|
|
@@ -110,8 +115,8 @@ class Agent {
|
|
|
110
115
|
|
|
111
116
|
this._initializeProviders();
|
|
112
117
|
|
|
113
|
-
// Initialize control panel if enabled
|
|
114
|
-
if (options.controlPanel !== false) {
|
|
118
|
+
// Initialize control panel if enabled (browser only)
|
|
119
|
+
if (options.controlPanel !== false && typeof document !== 'undefined') {
|
|
115
120
|
// Create floating control panel by default
|
|
116
121
|
this.createFloatingControlPanel();
|
|
117
122
|
}
|
|
@@ -125,6 +130,7 @@ class Agent {
|
|
|
125
130
|
try {
|
|
126
131
|
// Determine if this is a vision request
|
|
127
132
|
const isVisionRequest = message.content && message.content.type === 'image';
|
|
133
|
+
// Support for latest OpenAI models with backward compatibility
|
|
128
134
|
const modelName = (agent.config.model || this.options.defaultModel || 'gpt-4o').trim();
|
|
129
135
|
|
|
130
136
|
this._log(`Making OpenAI request with model: ${modelName}`, 'info');
|
|
@@ -220,11 +226,15 @@ class Agent {
|
|
|
220
226
|
];
|
|
221
227
|
}
|
|
222
228
|
|
|
229
|
+
// GPT-5 and reasoning models only support temperature=1
|
|
230
|
+
const supportsCustomTemp = !modelName.startsWith('gpt-5') && !modelName.startsWith('o1') && !modelName.startsWith('o3');
|
|
231
|
+
const temperature = supportsCustomTemp ? (agent.config.temperature || 0.7) : 1;
|
|
232
|
+
|
|
223
233
|
const requestBody = {
|
|
224
234
|
model: modelName,
|
|
225
235
|
messages: messages,
|
|
226
|
-
temperature:
|
|
227
|
-
|
|
236
|
+
temperature: temperature,
|
|
237
|
+
max_completion_tokens: agent.config.maxTokens || 500,
|
|
228
238
|
top_p: agent.config.topP || 1,
|
|
229
239
|
frequency_penalty: agent.config.frequencyPenalty || 0,
|
|
230
240
|
presence_penalty: agent.config.presencePenalty || 0,
|
|
@@ -266,13 +276,37 @@ class Agent {
|
|
|
266
276
|
},
|
|
267
277
|
defaultModels: {
|
|
268
278
|
chat: 'gpt-4o',
|
|
269
|
-
vision: 'gpt-4o'
|
|
270
|
-
|
|
279
|
+
vision: 'gpt-4o',
|
|
280
|
+
// Latest frontier models
|
|
281
|
+
reasoning: 'o3',
|
|
282
|
+
reasoningMini: 'o3-mini',
|
|
283
|
+
// GPT-5 series (when available)
|
|
284
|
+
gpt5: 'gpt-5',
|
|
285
|
+
gpt5Mini: 'gpt-5-mini',
|
|
286
|
+
gpt5Nano: 'gpt-5-nano'
|
|
287
|
+
},
|
|
288
|
+
supportedModels: [
|
|
289
|
+
// GPT-5 series (frontier models)
|
|
290
|
+
'gpt-5', 'gpt-5-mini', 'gpt-5-nano',
|
|
291
|
+
// o-series reasoning models
|
|
292
|
+
'o1', 'o1-mini', 'o1-preview',
|
|
293
|
+
'o3', 'o3-mini',
|
|
294
|
+
// GPT-4 series
|
|
295
|
+
'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4-turbo-preview',
|
|
296
|
+
'gpt-4', 'gpt-4-32k', 'gpt-4-vision-preview',
|
|
297
|
+
// GPT-3.5 series (legacy)
|
|
298
|
+
'gpt-3.5-turbo', 'gpt-3.5-turbo-16k',
|
|
299
|
+
// Vision models
|
|
300
|
+
'gpt-4o-vision', 'gpt-4-turbo-vision'
|
|
301
|
+
]
|
|
271
302
|
} : null,
|
|
272
303
|
|
|
273
304
|
anthropic: this.options.apiKeys.anthropic ? {
|
|
274
305
|
chat: async (agent, message) => {
|
|
275
306
|
try {
|
|
307
|
+
// Support for latest Claude models with backward compatibility
|
|
308
|
+
const modelName = agent.config.model || 'claude-sonnet-4-5-20250929';
|
|
309
|
+
|
|
276
310
|
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
277
311
|
method: 'POST',
|
|
278
312
|
headers: {
|
|
@@ -281,7 +315,7 @@ class Agent {
|
|
|
281
315
|
'anthropic-version': '2023-06-01'
|
|
282
316
|
},
|
|
283
317
|
body: JSON.stringify({
|
|
284
|
-
model:
|
|
318
|
+
model: modelName,
|
|
285
319
|
max_tokens: agent.config.maxTokens || 500,
|
|
286
320
|
temperature: agent.config.temperature || 0.7,
|
|
287
321
|
system: agent.config.systemPrompt,
|
|
@@ -308,9 +342,32 @@ class Agent {
|
|
|
308
342
|
}
|
|
309
343
|
},
|
|
310
344
|
defaultModels: {
|
|
311
|
-
chat: 'claude-
|
|
312
|
-
completion: 'claude-
|
|
313
|
-
|
|
345
|
+
chat: 'claude-sonnet-4-5-20250929',
|
|
346
|
+
completion: 'claude-sonnet-4-5-20250929',
|
|
347
|
+
// Latest frontier models
|
|
348
|
+
opus45: 'claude-opus-4-5-20251101',
|
|
349
|
+
sonnet45: 'claude-sonnet-4-5-20250929',
|
|
350
|
+
// Claude 3.5 series
|
|
351
|
+
sonnet35: 'claude-3-5-sonnet-20241022',
|
|
352
|
+
haiku35: 'claude-3-5-haiku-20241022'
|
|
353
|
+
},
|
|
354
|
+
supportedModels: [
|
|
355
|
+
// Claude 4.5 series (latest frontier models)
|
|
356
|
+
'claude-opus-4-5-20251101',
|
|
357
|
+
'claude-sonnet-4-5-20250929',
|
|
358
|
+
// Claude 3.5 series
|
|
359
|
+
'claude-3-5-sonnet-20241022',
|
|
360
|
+
'claude-3-5-sonnet-20240620',
|
|
361
|
+
'claude-3-5-haiku-20241022',
|
|
362
|
+
// Claude 3 series (legacy but still supported)
|
|
363
|
+
'claude-3-opus-20240229',
|
|
364
|
+
'claude-3-sonnet-20240229',
|
|
365
|
+
'claude-3-haiku-20240307',
|
|
366
|
+
// Older models for backward compatibility
|
|
367
|
+
'claude-2.1',
|
|
368
|
+
'claude-2.0',
|
|
369
|
+
'claude-instant-1.2'
|
|
370
|
+
]
|
|
314
371
|
} : null,
|
|
315
372
|
|
|
316
373
|
google: this.options.apiKeys.google ? {
|
|
@@ -2050,11 +2107,15 @@ class Agent {
|
|
|
2050
2107
|
{ type: 'image_url', image_url: { url: imageData, detail: options.detail || 'high' } }
|
|
2051
2108
|
] }
|
|
2052
2109
|
];
|
|
2110
|
+
// GPT-5 and reasoning models only support temperature=1
|
|
2111
|
+
const supportsCustomTemp = !modelName.startsWith('gpt-5') && !modelName.startsWith('o1') && !modelName.startsWith('o3');
|
|
2112
|
+
const temperature = supportsCustomTemp ? (agent.config.temperature || 0.7) : 1;
|
|
2113
|
+
|
|
2053
2114
|
const requestBody = {
|
|
2054
2115
|
model: modelName,
|
|
2055
2116
|
messages,
|
|
2056
|
-
temperature:
|
|
2057
|
-
|
|
2117
|
+
temperature: temperature,
|
|
2118
|
+
max_completion_tokens: agent.config.maxTokens || 500,
|
|
2058
2119
|
top_p: agent.config.topP || 1,
|
|
2059
2120
|
frequency_penalty: agent.config.frequencyPenalty || 0,
|
|
2060
2121
|
presence_penalty: agent.config.presencePenalty || 0,
|
|
@@ -2088,9 +2149,9 @@ class Agent {
|
|
|
2088
2149
|
}
|
|
2089
2150
|
|
|
2090
2151
|
/**
|
|
2091
|
-
* Generate an image from a text prompt using the agent's provider (OpenAI DALL-E
|
|
2092
|
-
* Supports models: '
|
|
2093
|
-
* Model selection order: options.model > agent.config.
|
|
2152
|
+
* Generate an image from a text prompt using the agent's provider (OpenAI DALL-E)
|
|
2153
|
+
* Supports models: 'dall-e-3', 'dall-e-2' (legacy)
|
|
2154
|
+
* Model selection order: options.model > agent.config.imageGenerationModel > 'dall-e-3'
|
|
2094
2155
|
*/
|
|
2095
2156
|
async generateImage(agentId, prompt, options = {}) {
|
|
2096
2157
|
const agent = this.agents.get(agentId);
|
|
@@ -2102,7 +2163,7 @@ class Agent {
|
|
|
2102
2163
|
this._emit('image-generation-start', { agentId, provider, prompt, options });
|
|
2103
2164
|
try {
|
|
2104
2165
|
if (provider === 'openai') {
|
|
2105
|
-
// Model selection logic
|
|
2166
|
+
// Model selection logic - DALL-E 3 is the latest stable image generation model
|
|
2106
2167
|
const modelName = (options.model || agent.config.imageGenerationModel || 'dall-e-3').trim();
|
|
2107
2168
|
// DALL-E endpoint supports model param for dalle-3
|
|
2108
2169
|
const requestBody = {
|
|
@@ -2137,8 +2198,8 @@ class Agent {
|
|
|
2137
2198
|
|
|
2138
2199
|
/**
|
|
2139
2200
|
* Edit an image based on a prompt using the agent's provider (OpenAI DALL-E)
|
|
2140
|
-
* Supports models: '
|
|
2141
|
-
* Model selection order: options.model > agent.config.model > '
|
|
2201
|
+
* Supports models: 'dall-e-3', 'dall-e-2' (legacy)
|
|
2202
|
+
* Model selection order: options.model > agent.config.model > 'dall-e-3'
|
|
2142
2203
|
*/
|
|
2143
2204
|
async editImage(agentId, imageData, prompt, options = {}) {
|
|
2144
2205
|
const agent = this.agents.get(agentId);
|
|
@@ -2185,8 +2246,8 @@ class Agent {
|
|
|
2185
2246
|
|
|
2186
2247
|
/**
|
|
2187
2248
|
* Create a variation of an image using the agent's provider (OpenAI DALL-E)
|
|
2188
|
-
* Supports models: '
|
|
2189
|
-
* Model selection order: options.model > agent.config.model > '
|
|
2249
|
+
* Supports models: 'dall-e-3', 'dall-e-2' (legacy)
|
|
2250
|
+
* Model selection order: options.model > agent.config.model > 'dall-e-3'
|
|
2190
2251
|
*/
|
|
2191
2252
|
async variationImage(agentId, imageData, options = {}) {
|
|
2192
2253
|
const agent = this.agents.get(agentId);
|
package/worksona.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";class Agent{constructor(n){this.id=n.id,this.name=n.name,this.description=n.description,n.config?(this.config={...n,...n.config},delete this.config.config):this.config=n,this.systemPrompt=this.config.systemPrompt,this.examples=this.config.examples||[],this.config.traits&&(this.traits=this.config.traits),this.transactions=[],this.metrics={totalQueries:0,avgResponseTime:0,lastActive:null,successRate:1,errorCount:0},this.state={isActive:!0,currentProvider:this.config.provider||"openai",currentModel:this.config.model,lastError:null}}addTransaction(n){if(this.transactions.push(n),this.metrics.totalQueries++,this.metrics.lastActive=new Date,n.duration){const e=this.metrics.avgResponseTime*(this.metrics.totalQueries-1)+n.duration;this.metrics.avgResponseTime=e/this.metrics.totalQueries}n.error&&(this.metrics.errorCount++,this.metrics.successRate=(this.metrics.totalQueries-this.metrics.errorCount)/this.metrics.totalQueries,this.state.lastError=n.error),this.transactions.length>100&&(this.transactions=this.transactions.slice(-100))}getHistory(){return this.transactions}getMetrics(){return this.metrics}getState(){return this.state}}!function(n){class e{constructor(n={}){this.options={debug:!1,defaultProvider:"openai",defaultModel:"gpt-3.5-turbo",apiKeys:{},...n},this.agents=new Map,this.activeProvider=null,this.controlPanelId=null,this.eventHandlers={},this._initializeProviders(),!1!==n.controlPanel&&this.createFloatingControlPanel()}_initializeProviders(){this.providers={openai:this.options.apiKeys.openai?{chat:async(n,e)=>{try{const t=e.content&&"image"===e.content.type,o=(n.config.model||this.options.defaultModel||"gpt-4o").trim();let a;if(this._log(`Making OpenAI request with model: ${o}`,"info"),t||e&&"image"===e.type||e&&e.content&&"object"==typeof e.content&&"image"===e.content.type){let o;if(t?o=e.content:"image"===e.type?o=e:e.content&&"image"===e.content.type&&(o=e.content),!o||!o.imageUrl)throw new Error("Invalid image data: Missing required imageUrl property");a=[{role:"system",content:n.config.systemPrompt||"You are a helpful vision analysis assistant."},{role:"user",content:[{type:"text",text:o.prompt||"Please analyze this image."},{type:"image_url",image_url:{url:o.imageUrl,detail:o.detail||"high"}}]}],this._log(`Vision message structure: ${JSON.stringify(a)}`,"info")}else{let t="";if("string"==typeof e)t=e;else if(e&&"string"==typeof e.content)t=e.content;else if(e&&e.content)try{t=JSON.stringify(e.content)}catch(n){t="Unable to process message content"}else if(e)try{t=JSON.stringify(e)}catch(n){t="Unable to process message"}else t="No message provided";this._log(`Processed user content: ${t.substring(0,100)}${t.length>100?"...":""}`,"info"),a=[{role:"system",content:n.config.systemPrompt||"You are a helpful assistant."},...(n.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:t}]}const s={model:o,messages:a,temperature:n.config.temperature||.7,max_tokens:n.config.maxTokens||500,top_p:n.config.topP||1,frequency_penalty:n.config.frequencyPenalty||0,presence_penalty:n.config.presencePenalty||0,stream:!1},r="https://api.openai.com/v1/chat/completions",i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`,"OpenAI-Organization":n.config.organization||""},body:JSON.stringify(s)}),l=await i.json();if(!i.ok)throw this._log(`OpenAI API error: ${JSON.stringify(l)}`,"error"),new Error(l.error?.message||`OpenAI API error: ${i.status}`);return t&&this._log(`Successfully processed vision request with model: ${o}`),l.choices[0].message.content}catch(n){this._log(`OpenAI error details: ${n.message}`,"error"),this._handleError(n,"PROVIDER_ERROR","OpenAI request failed")}},defaultModels:{chat:"gpt-4o",vision:"gpt-4o"}}:null,anthropic:this.options.apiKeys.anthropic?{chat:async(n,e)=>{try{const t=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.options.apiKeys.anthropic,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:n.config.model||"claude-3-opus-20240229",max_tokens:n.config.maxTokens||500,temperature:n.config.temperature||.7,system:n.config.systemPrompt,messages:[...(n.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:e}],top_p:n.config.topP||1,top_k:n.config.topK||50,metadata:{user_id:n.id}})}),o=await t.json();if(!t.ok)throw new Error(o.error?.message||"Anthropic API error");return o.content[0].text}catch(n){this._handleError(n,"PROVIDER_ERROR","Anthropic request failed")}},defaultModels:{chat:"claude-3-opus-20240229",completion:"claude-3-sonnet-20240229"}}:null,google:this.options.apiKeys.google?{chat:async(n,e)=>{try{const t=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${n.config.model||"gemini-pro"}:generateContent?key=${this.options.apiKeys.google}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contents:[{role:"user",parts:[{text:n.config.systemPrompt}]},...(n.config.examples||[]).flatMap(n=>[{role:"user",parts:[{text:n.user}]},{role:"model",parts:[{text:n.assistant}]}]),{role:"user",parts:[{text:e}]}],generationConfig:{temperature:n.config.temperature||.7,maxOutputTokens:n.config.maxTokens||500,topP:n.config.topP||1,topK:n.config.topK||40,candidateCount:1},safetySettings:[{category:"HARM_CATEGORY_HARASSMENT",threshold:"BLOCK_MEDIUM_AND_ABOVE"},{category:"HARM_CATEGORY_HATE_SPEECH",threshold:"BLOCK_MEDIUM_AND_ABOVE"}]})}),o=await t.json();if(!t.ok)throw new Error(o.error?.message||"Google API error");return o.candidates[0].content.parts[0].text}catch(n){this._handleError(n,"PROVIDER_ERROR","Google request failed")}},defaultModels:{chat:"gemini-pro",vision:"gemini-pro-vision"}}:null}}_formatMessages(n,e,t){switch(n){case"openai":return[{role:"system",content:e.config.systemPrompt},...(e.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:t}];case"anthropic":return[...(e.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:t}];case"google":return[{role:"user",parts:[{text:e.config.systemPrompt}]},...(e.config.examples||[]).flatMap(n=>[{role:"user",parts:[{text:n.user}]},{role:"model",parts:[{text:n.assistant}]}]),{role:"user",parts:[{text:t}]}];default:throw new Error(`Unsupported provider: ${n}`)}}async loadAgent(n){if(!n.id||!n.name)return this._handleError(new Error("Invalid agent configuration"),"CONFIG_ERROR"),null;try{const e=new Agent(n);return this.agents.set(e.id,e),this._emit("agent-loaded",{agentId:e.id,name:e.name,description:e.description,provider:e.state.currentProvider,model:e.state.currentModel}),this.updateControlPanel(),this._log(`Agent loaded: ${e.name} (${e.id})`),e}catch(e){return this._handleError(e,"AGENT_LOAD_ERROR",`Failed to load agent: ${n.id}`),null}}async chat(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||t.provider||this.options.defaultProvider;if(!this.providers[a])return this._handleError(new Error(`Provider not available: ${a}`),"PROVIDER_ERROR"),null;o.state.currentProvider=a,o.state.currentModel=o.config.model||this.options.defaultModel;const s={timestamp:new Date,query:e,response:null,duration:0,error:null,provider:a,model:o.state.currentModel};this._emit("chat-start",{agentId:n,message:e}),this._log(`Chat request to ${n}: ${e}`);const r=Date.now();try{const t=await this.providers[a].chat(o,e);return s.duration=Date.now()-r,s.response=t,o.addTransaction(s),this.updateControlPanel(),this._emit("chat-complete",{agentId:n,message:e,response:t,duration:s.duration}),this._log(`Chat response from ${n}: ${t}`),t}catch(e){return s.error=e,s.duration=Date.now()-r,o.addTransaction(s),this.updateControlPanel(),this._handleError(e,"CHAT_ERROR",`Chat failed with ${n}`),null}}getAgentHistory(n){const e=this.agents.get(n);return e?e.getHistory():[]}getAgentMetrics(n){const e=this.agents.get(n);return e?e.getMetrics():null}getAgentState(n){const e=this.agents.get(n);return e?e.getState():null}getAgent(n){return this.agents.get(n)}getAllAgents(){return Array.from(this.agents.values())}removeAgent(n){const e=this.agents.delete(n);return e&&(this._emit("agent-removed",n),this._log(`Agent removed: ${n}`),this.updateControlPanel()),e}on(n,e){this.eventHandlers[n]||(this.eventHandlers[n]=[]),this.eventHandlers[n].push(e)}off(n,e){this.eventHandlers[n]&&(this.eventHandlers[n]=this.eventHandlers[n].filter(n=>n!==e))}_emit(n,e){this.eventHandlers[n]&&this.eventHandlers[n].forEach(n=>n(e))}_handleError(n,e,t){let o=t||n.message;switch(e){case"IMAGE_PROCESSING_ERROR":n.message.includes("image_too_large")?o="Image size exceeds maximum allowed size. Please reduce the image size.":n.message.includes("invalid_image_format")?o="Invalid image format. Supported formats are: JPEG, PNG, WEBP, GIF.":n.message.includes("vision_model_unavailable")&&(o="Vision model is currently unavailable. Please try again later."),n.message.includes("invalid_api_key")?o="Invalid OpenAI API key. Please check your credentials.":n.message.includes("insufficient_quota")?o="OpenAI API quota exceeded. Please check your usage limits.":n.message.includes("rate_limit_exceeded")&&(o="OpenAI API rate limit exceeded. Please try again later.");break;case"PROVIDER_ERROR":n.message&&n.message.includes("401")?o="API key is invalid or missing. Please check your API key in the control panel.":n.message&&n.message.includes("invalid_api_key")?o="Invalid API key format. Please check your API key in the control panel.":n.message&&n.message.includes("model")&&(o=`Model error: ${n.message}. Please try a different model in the control panel.`);break;case"CONFIG_ERROR":o="Invalid agent configuration. Please check your agent configuration and try again.";break;case"AGENT_LOAD_ERROR":o=`Failed to load agent: ${n.message}. Please check the agent configuration and try again.`;break;case"AGENT_NOT_FOUND":o=`Agent not found: ${n.message}. Please check the agent ID and try again.`;break;case"CHAT_ERROR":o=`Chat failed with ${n.message}. Please check the chat request and try again.`;break;default:o=n.message||"An unknown error occurred. Please try again later."}const a={message:o,code:e,originalError:n};throw this._emit("error",a),this._log(`Error [${e}]: ${a.message}`,"error"),a}_log(n,e="info"){this.options.debug&&console[e](`[Worksona] ${n}`)}createControlPanel(n){this.controlPanelId=n;const e=document.getElementById(n);if(!e)return this._log("Control panel container not found","error"),!1;this.controlPanelContainer=e,e.innerHTML='\n <div class="worksona-control-panel">\n <div class="worksona-panel-header">\n <h2>Worksona Agents Control Panel</h2>\n <div class="worksona-header-buttons">\n <button class="worksona-expand-button" title="Toggle full screen">⛶</button>\n <button class="worksona-close-button">×</button>\n </div>\n </div>\n \n <div class="worksona-llm-status-bar">\n <div class="worksona-status-label">LLM Status</div>\n <div class="worksona-status-indicators">\n <div class="worksona-status-item">\n <div class="worksona-status-dot" id="worksona-openai-status"></div>\n <span>OpenAI</span>\n </div>\n <div class="worksona-status-item">\n <div class="worksona-status-dot" id="worksona-anthropic-status"></div>\n <span>Anthropic</span>\n </div>\n <div class="worksona-status-item">\n <div class="worksona-status-dot" id="worksona-google-status"></div>\n <span>Google</span>\n </div>\n </div>\n </div>\n \n <div class="worksona-tabs">\n <button class="worksona-tab" data-tab="api-keys">API Keys</button>\n <button class="worksona-tab active" data-tab="agents">Agents</button>\n </div>\n \n <div class="worksona-content">\n <div class="worksona-tab-content" id="worksona-api-keys-tab">\n <h3 class="worksona-section-title">LLM Provider API Keys</h3>\n \n <div class="worksona-key-input">\n <label for="worksona-openai-key">OpenAI API Key</label>\n <div class="worksona-input-group">\n <input type="password" id="worksona-openai-key" placeholder="sk-...">\n <button class="worksona-toggle-visibility">👁️</button>\n </div>\n </div>\n \n <div class="worksona-key-input">\n <label for="worksona-anthropic-key">Anthropic API Key</label>\n <div class="worksona-input-group">\n <input type="password" id="worksona-anthropic-key" placeholder="sk-ant-...">\n <button class="worksona-toggle-visibility">👁️</button>\n </div>\n </div>\n \n <div class="worksona-key-input">\n <label for="worksona-google-key">Google API Key</label>\n <div class="worksona-input-group">\n <input type="password" id="worksona-google-key" placeholder="AIza...">\n <button class="worksona-toggle-visibility">👁️</button>\n </div>\n </div>\n \n <div class="worksona-button-group">\n <button id="worksona-save-keys" class="worksona-primary-button">Save API Keys</button>\n <button id="worksona-test-connections" class="worksona-secondary-button">Test Connections</button>\n </div>\n </div>\n \n <div class="worksona-tab-content active" id="worksona-agents-tab">\n <div id="worksona-agent-list"></div>\n </div>\n </div>\n </div>\n ';const t=document.createElement("style");return t.textContent="\n .worksona-control-panel {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n color: #333;\n background: white;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n overflow: hidden;\n width: 100%;\n max-width: 800px;\n margin: 0 auto;\n position: relative;\n }\n\n .worksona-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 15px 20px;\n border-bottom: 1px solid #eee;\n }\n\n .worksona-panel-header h2 {\n margin: 0;\n color: #1a56db;\n font-size: 18px;\n font-weight: 600;\n }\n\n .worksona-header-buttons {\n display: flex;\n gap: 10px;\n align-items: center;\n }\n\n .worksona-expand-button {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #64748b;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n }\n\n .worksona-expand-button:hover {\n color: #334155;\n }\n\n .worksona-llm-status-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 20px;\n background: #111827;\n color: white;\n }\n\n .worksona-status-indicators {\n display: flex;\n gap: 20px;\n }\n\n .worksona-status-item {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 14px;\n }\n\n .worksona-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #6b7280;\n }\n\n .worksona-status-dot.active {\n background: #10b981;\n }\n\n .worksona-tabs {\n display: flex;\n padding: 0 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .worksona-tab {\n padding: 15px 20px;\n background: none;\n border: none;\n cursor: pointer;\n color: #6b7280;\n font-weight: 500;\n position: relative;\n }\n\n .worksona-tab:hover {\n color: #4b5563;\n }\n\n .worksona-tab.active {\n color: #2563eb;\n }\n\n .worksona-tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 2px;\n background: #2563eb;\n }\n\n .worksona-content {\n padding: 20px;\n }\n\n .worksona-tab-content {\n display: none;\n }\n\n .worksona-tab-content.active {\n display: block;\n }\n\n .worksona-section-title {\n font-size: 16px;\n font-weight: 600;\n margin-top: 0;\n margin-bottom: 20px;\n color: #111827;\n }\n\n .worksona-key-input {\n margin-bottom: 15px;\n }\n\n .worksona-key-input label {\n display: block;\n margin-bottom: 5px;\n font-weight: 500;\n color: #374151;\n }\n\n .worksona-input-group {\n display: flex;\n align-items: center;\n }\n\n .worksona-input-group input {\n flex: 1;\n padding: 10px 12px;\n border: 1px solid #d1d5db;\n border-radius: 6px 0 0 6px;\n font-size: 14px;\n }\n\n .worksona-toggle-visibility {\n padding: 10px 12px;\n background: #f9fafb;\n border: 1px solid #d1d5db;\n border-left: none;\n border-radius: 0 6px 6px 0;\n cursor: pointer;\n }\n\n .worksona-button-group {\n display: flex;\n gap: 10px;\n margin-top: 20px;\n }\n\n .worksona-primary-button {\n padding: 8px 16px;\n background: #2563eb;\n color: white;\n border: none;\n border-radius: 6px;\n font-weight: 500;\n cursor: pointer;\n }\n\n .worksona-primary-button:hover {\n background: #1d4ed8;\n }\n\n .worksona-secondary-button {\n padding: 8px 16px;\n background: #f3f4f6;\n color: #374151;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-weight: 500;\n cursor: pointer;\n }\n\n .worksona-secondary-button:hover {\n background: #e5e7eb;\n }\n\n .worksona-agent-card {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 15px;\n margin-bottom: 15px;\n transition: box-shadow 0.2s;\n }\n \n .worksona-agent-card:hover {\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n }\n\n .worksona-agent-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 10px;\n cursor: pointer;\n position: relative;\n }\n \n .worksona-expand-icon {\n font-size: 12px;\n color: #6b7280;\n transition: transform 0.2s;\n }\n \n .worksona-expand-icon.rotated {\n transform: rotate(180deg);\n }\n \n .worksona-agent-details.active + .worksona-expand-icon {\n transform: rotate(180deg);\n }\n\n .worksona-agent-name {\n font-size: 16px;\n font-weight: 600;\n color: #111827;\n margin: 0;\n }\n\n .worksona-agent-id {\n color: #6b7280;\n font-size: 12px;\n font-family: monospace;\n }\n \n .worksona-agent-status {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n \n .worksona-status-label {\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 10px;\n background: #f3f4f6;\n }\n \n .worksona-agent-status.active .worksona-status-label {\n background: #dcfce7;\n color: #166534;\n }\n \n .worksona-agent-status.inactive .worksona-status-label {\n background: #fee2e2;\n color: #991b1b;\n }\n\n .worksona-agent-description {\n color: #4b5563;\n margin-bottom: 15px;\n font-size: 14px;\n }\n \n .worksona-agent-details {\n display: none;\n overflow: hidden;\n border-top: 1px solid #e5e7eb;\n margin-top: 10px;\n padding-top: 15px;\n }\n \n .worksona-agent-details.active {\n display: block;\n }\n \n .worksona-agent-tabs {\n display: flex;\n border-bottom: 1px solid #e5e7eb;\n margin-bottom: 15px;\n }\n \n .worksona-agent-tab {\n padding: 8px 16px;\n border: none;\n background: none;\n cursor: pointer;\n color: #6b7280;\n font-weight: 500;\n position: relative;\n font-size: 14px;\n }\n \n .worksona-agent-tab:hover {\n color: #111827;\n }\n \n .worksona-agent-tab.active {\n color: #2563eb;\n border-bottom: 2px solid #2563eb;\n }\n \n .worksona-agent-tab-content {\n display: none;\n }\n \n .worksona-agent-tab-content.active {\n display: block;\n }\n \n .worksona-agent-tab-content h4 {\n font-size: 14px;\n font-weight: 600;\n margin: 0 0 10px;\n color: #111827;\n }\n \n .worksona-config-details,\n .worksona-traits,\n .worksona-metrics {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 15px;\n font-size: 13px;\n line-height: 1.5;\n }\n \n .worksona-prompt-box {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 15px;\n font-size: 13px;\n line-height: 1.5;\n white-space: pre-wrap;\n font-family: monospace;\n max-height: 200px;\n overflow-y: auto;\n }\n \n .worksona-examples {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-bottom: 20px;\n }\n \n .worksona-example {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n font-size: 13px;\n }\n \n .worksona-example-user {\n margin-bottom: 8px;\n color: #4b5563;\n }\n \n .worksona-example-assistant {\n color: #1f2937;\n }\n \n .worksona-history {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-bottom: 15px;\n max-height: 300px;\n overflow-y: auto;\n }\n \n .worksona-history-item {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n font-size: 13px;\n }\n \n .worksona-history-time {\n font-size: 11px;\n color: #6b7280;\n margin-bottom: 5px;\n }\n \n .worksona-history-query {\n margin-bottom: 8px;\n color: #4b5563;\n }\n \n .worksona-history-response {\n color: #1f2937;\n margin-bottom: 8px;\n }\n \n .worksona-history-meta {\n font-size: 11px;\n color: #6b7280;\n }\n \n .worksona-no-agents {\n text-align: center;\n padding: 40px 20px;\n color: #6b7280;\n background: #f9fafb;\n border-radius: 8px;\n }\n \n .worksona-no-examples {\n color: #6b7280;\n font-style: italic;\n background: #f9fafb;\n padding: 12px;\n border-radius: 6px;\n margin: 10px 0;\n }\n \n .worksona-control-panel {\n box-shadow: 0 5px 20px rgba(0,0,0,0.2);\n max-height: 80vh;\n overflow: auto;\n background: white;\n border-radius: 8px;\n }\n \n .worksona-json-display {\n background: #f8fafc;\n border-radius: 6px;\n padding: 15px;\n margin: 0;\n font-family: monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n max-height: 500px;\n white-space: pre-wrap;\n color: #334155;\n border: 1px solid #e2e8f0;\n }\n \n /* Ensure the json tab content has proper height */\n #worksona-agent-tab-content[id$=\"-json\"] {\n max-height: 500px;\n overflow: auto;\n }\n \n /* JSON syntax highlighting */\n .worksona-json-key {\n color: #0f766e;\n }\n \n .worksona-json-string {\n color: #b91c1c;\n }\n \n .worksona-json-number {\n color: #1d4ed8;\n }\n \n .worksona-json-boolean {\n color: #7e22ce;\n }\n \n .worksona-json-null {\n color: #64748b;\n }\n \n /* Ensure the modal is scrollable on smaller screens */\n @media (max-height: 768px) {\n #worksona-modal-container {\n max-height: 90vh;\n }\n \n .worksona-control-panel {\n max-height: 90vh;\n }\n }\n ",document.head.appendChild(t),this._setupEventListeners(e),this.updateControlPanel(),!0}_setupEventListeners(n){if(!(n=n||this.controlPanelContainer))return void this._log("No container available for event listeners","error");n.querySelectorAll(".worksona-tab").forEach(e=>{e.addEventListener("click",()=>{n.querySelectorAll(".worksona-tab").forEach(n=>n.classList.remove("active")),n.querySelectorAll(".worksona-tab-content").forEach(n=>n.classList.remove("active")),e.classList.add("active"),document.getElementById(`worksona-${e.dataset.tab}-tab`).classList.add("active")})}),n.querySelectorAll(".worksona-toggle-visibility").forEach(n=>{n.addEventListener("click",()=>{const e=n.previousElementSibling;"password"===e.type?(e.type="text",n.textContent="🔒"):(e.type="password",n.textContent="👁️")})});const e=document.getElementById("worksona-save-keys");if(e){const n=e.cloneNode(!0);e.parentNode.replaceChild(n,e),n.addEventListener("click",()=>{const n=document.getElementById("worksona-openai-key").value,e=document.getElementById("worksona-anthropic-key").value,t=document.getElementById("worksona-google-key").value;n&&localStorage.setItem("openai_api_key",n),e&&localStorage.setItem("anthropic_api_key",e),t&&localStorage.setItem("google_api_key",t),this.options.apiKeys={...this.options.apiKeys,...n&&{openai:n},...e&&{anthropic:e},...t&&{google:t}},this._initializeProviders(),this.updateControlPanel(),this._emit("api-keys-updated",{providers:Object.keys(this.options.apiKeys)}),alert("API keys saved successfully!")})}const t=document.getElementById("worksona-test-connections");if(t){const n=t.cloneNode(!0);t.parentNode.replaceChild(n,t),n.addEventListener("click",async()=>{n.disabled=!0,n.textContent="Testing...";try{await this._testProviderConnections(),this.updateControlPanel()}finally{n.disabled=!1,n.textContent="Test Connections"}})}const o=n.querySelector(".worksona-close-button");if(o){const e=o.cloneNode(!0);o.parentNode.replaceChild(e,o),e.addEventListener("click",()=>{const e=n.querySelector(".worksona-control-panel");e&&(e.style.display="none")})}n.querySelectorAll('input[type="range"]').forEach(n=>{const e=n.nextElementSibling;n.addEventListener("input",()=>{e&&(e.textContent=n.value)}),e&&n.value&&(e.textContent=n.value)})}async _testProviderConnections(){const n=["openai","anthropic","google"];for(const e of n){const n=document.getElementById(`worksona-${e}-status`);if(n)if(this.options.apiKeys[e]&&""!==this.options.apiKeys[e].trim())try{let t=!1;switch(e){case"openai":t=this.options.apiKeys.openai&&this.options.apiKeys.openai.startsWith("sk-");break;case"anthropic":t=this.options.apiKeys.anthropic&&this.options.apiKeys.anthropic.startsWith("sk-ant-");break;case"google":t=this.options.apiKeys.google&&this.options.apiKeys.google.length>10}n.className=t?"worksona-status-dot active":"worksona-status-dot",this._log(`Provider ${e} validation result: ${t?"valid":"invalid"}`)}catch(t){n.className="worksona-status-dot",console.error(`Error testing ${e} connection:`,t)}else n.className="worksona-status-dot"}}updateControlPanel(){this.controlPanelId&&(this._updateProviderStatus(),Object.entries(this.options.apiKeys).forEach(([n,e])=>{const t=document.getElementById(`worksona-${n}-key`);t&&e&&(t.value=e)}),this._updateAgentList(),this._setupAgentEventListeners(),this.controlPanelContainer&&this._setupEventListeners(this.controlPanelContainer))}_updateProviderStatus(){["openai","anthropic","google"].forEach(n=>{const e=document.getElementById(`worksona-${n}-status`);if(!e)return;const t=!!this.options.apiKeys[n];e.className=t?"worksona-status-dot active":"worksona-status-dot"})}_updateAgentList(){const n=document.getElementById("worksona-agent-list");if(!n)return;const e=this.getAgents();0!==e.length?(n.innerHTML=e.map(n=>{const e=n.getMetrics(),t=n.getState(),o=n.getHistory(),a=o.length>0?o.slice(-5).map(n=>`\n <div class="worksona-history-item">\n <div class="worksona-history-time">${new Date(n.timestamp).toLocaleTimeString()}</div>\n <div class="worksona-history-query"><strong>Query:</strong> ${this._escapeHtml(n.query)}</div>\n <div class="worksona-history-response"><strong>Response:</strong> ${this._escapeHtml(n.response||"Error: "+(n.error?.message||"Unknown error"))}</div>\n <div class="worksona-history-meta">\n <span>Provider: ${n.provider}</span> | \n <span>Model: ${n.model}</span> | \n <span>Duration: ${n.duration}ms</span>\n </div>\n </div>\n `).join(""):"<p>No interaction history available yet.</p>",s=n=>n.systemPrompt||n.config?.systemPrompt||n.config?.config?.systemPrompt||"",r=n=>{const e=n.examples||n.config?.examples||n.config?.config?.examples||[];return console.log("Agent:",n.id,"Examples:",JSON.stringify(e)),e},i=s(n),l=i?`<div class="worksona-prompt-box">${this._escapeHtml(i)}</div>`:'<p class="worksona-no-examples">No system prompt has been defined for this agent. A system prompt helps establish the agent\'s behavior and capabilities.</p>',d=r(n),c=d&&d.length>0?d.map(n=>`\n <div class="worksona-example">\n <div class="worksona-example-user"><strong>User:</strong> ${this._escapeHtml(n.user||"")}</div>\n <div class="worksona-example-assistant"><strong>Assistant:</strong> ${this._escapeHtml(n.assistant||"")}</div>\n </div>\n `).join(""):'<p class="worksona-no-examples">No examples have been defined for this agent. Examples help demonstrate the expected conversation flow.</p>',p=`\n <div class="worksona-config-details">\n <h4>Model Settings</h4>\n <div><strong>Provider:</strong> ${n.config?.provider||n.state?.currentProvider||"default"}</div>\n <div><strong>Model:</strong> ${n.config?.model||n.state?.currentModel||"default"}</div>\n <div><strong>Temperature:</strong> ${void 0!==n.config?.temperature?n.config.temperature:void 0!==n.config?.config?.temperature?n.config.config.temperature:"default"}</div>\n <div><strong>Max Tokens:</strong> ${void 0!==n.config?.maxTokens?n.config.maxTokens:void 0!==n.config?.config?.maxTokens?n.config.config.maxTokens:"default"}</div>\n ${void 0!==n.config?.topP||void 0!==n.config?.config?.topP?`<div><strong>Top P:</strong> ${void 0!==n.config?.topP?n.config.topP:n.config?.config?.topP}</div>`:""}\n ${void 0!==n.config?.frequencyPenalty||void 0!==n.config?.config?.frequencyPenalty?`<div><strong>Frequency Penalty:</strong> ${void 0!==n.config?.frequencyPenalty?n.config.frequencyPenalty:n.config?.config?.frequencyPenalty}</div>`:""}\n ${void 0!==n.config?.presencePenalty||void 0!==n.config?.config?.presencePenalty?`<div><strong>Presence Penalty:</strong> ${void 0!==n.config?.presencePenalty?n.config.presencePenalty:n.config?.config?.presencePenalty}</div>`:""}\n </div>\n `,g=JSON.stringify({id:n.id,name:n.name,description:n.description,config:{provider:n.config.provider,model:n.config.model,temperature:n.config.temperature,maxTokens:n.config.maxTokens,topP:n.config.topP,frequencyPenalty:n.config.frequencyPenalty,presencePenalty:n.config.presencePenalty},systemPrompt:s(n),examples:r(n),traits:n.traits||{},metrics:n.getMetrics(),state:n.getState(),transactions:n.getHistory().slice(-5)},null,2),u=n.traits||{},m=`\n <div class="worksona-traits">\n ${u.personality?`<div><strong>Personality:</strong> ${u.personality.join(", ")}</div>`:""}\n ${u.knowledge?`<div><strong>Knowledge:</strong> ${u.knowledge.join(", ")}</div>`:""}\n ${u.tone?`<div><strong>Tone:</strong> ${u.tone}</div>`:""}\n ${u.background?`<div><strong>Background:</strong> ${u.background}</div>`:""}\n </div>\n `;return`\n <div class="worksona-agent-card">\n <div class="worksona-agent-header" onclick="document.getElementById('worksona-agent-details-${n.id}').classList.toggle('active'); this.querySelector('.worksona-expand-icon').classList.toggle('rotated')">\n <h3 class="worksona-agent-name">${n.name}</h3>\n <div class="worksona-agent-status ${t.isActive?"active":"inactive"}">\n <span class="worksona-agent-id">${n.id}</span>\n <span class="worksona-status-label">${t.isActive?"Active":"Inactive"}</span>\n </div>\n <div class="worksona-expand-icon">▼</div>\n </div>\n <p class="worksona-agent-description">${n.description||"No description provided"}</p>\n \n <div id="worksona-agent-details-${n.id}" class="worksona-agent-details">\n <div class="worksona-agent-tabs">\n <button class="worksona-agent-tab active" data-agent="${n.id}" data-tab="agent">Agent Details</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="model">Model Settings</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="prompt">System Prompt</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="history">History</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="json">Raw JSON</button>\n </div>\n \n <div class="worksona-agent-tab-content active" id="worksona-agent-${n.id}-agent">\n <h4>Agent Configuration</h4>\n <div class="worksona-config-details">\n <div><strong>ID:</strong> ${n.id}</div>\n <div><strong>Name:</strong> ${n.name}</div>\n <div><strong>Description:</strong> ${n.description||"No description provided"}</div>\n </div>\n <h4>Traits</h4>\n ${m}\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-model">\n <h4>Model Settings</h4>\n ${p}\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-prompt">\n <h4>System Prompt</h4>\n ${l}\n \n <h4>Examples</h4>\n <div class="worksona-examples">\n ${c}\n </div>\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-history">\n <h4>Recent Interactions</h4>\n <div class="worksona-history">\n ${a}\n </div>\n <div class="worksona-metrics">\n <div><strong>Total Queries:</strong> ${e.totalQueries}</div>\n <div><strong>Avg Response Time:</strong> ${Math.round(e.avgResponseTime)}ms</div>\n <div><strong>Success Rate:</strong> ${(100*e.successRate).toFixed(1)}%</div>\n <div><strong>Last Active:</strong> ${e.lastActive?new Date(e.lastActive).toLocaleTimeString():"Never"}</div>\n </div>\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-json">\n <h4>Agent Configuration JSON</h4>\n <div class="worksona-json-display">${this._escapeHtml(g)}</div>\n </div>\n </div>\n </div>\n `}).join(""),this.agentTabEventListeners&&this.agentTabEventListeners.forEach(({element:n,type:e,listener:t})=>{n.removeEventListener(e,t)}),this.agentTabEventListeners=[],n.querySelectorAll(".worksona-agent-tab").forEach(n=>{const e=e=>{const t=n.dataset.agent,o=n.dataset.tab;document.querySelectorAll(`.worksona-agent-tab[data-agent="${t}"]`).forEach(n=>{n.classList.remove("active")}),document.querySelectorAll(`[id^="worksona-agent-${t}-"]`).forEach(n=>{n.classList.remove("active")}),n.classList.add("active"),document.getElementById(`worksona-agent-${t}-${o}`).classList.add("active")};this.agentTabEventListeners.push({element:n,type:"click",listener:e}),n.addEventListener("click",e)})):n.innerHTML='\n <div class="worksona-no-agents">\n <p>No agents have been loaded yet.</p>\n <p>Agents will appear here when they are loaded by your application.</p>\n </div>\n '}_escapeHtml(n){return n?n.toString().replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"):""}_setupAgentEventListeners(){this.off("agent-loaded",this._handleAgentLoaded),this.off("agent-removed",this._handleAgentRemoved),this.on("agent-loaded",this._handleAgentLoaded.bind(this)),this.on("agent-removed",this._handleAgentRemoved.bind(this))}_handleAgentLoaded(){this._updateAgentList()}_handleAgentRemoved(){this._updateAgentList()}getAgents(){return Array.from(this.agents.values())}createFloatingControlPanel(){if(!document.body)return"loading"===document.readyState?void document.addEventListener("DOMContentLoaded",()=>this.createFloatingControlPanel()):void setTimeout(()=>this.createFloatingControlPanel(),100);try{const n=document.createElement("div");n.id="worksona-floating-control";const e=document.createElement("button");e.id="worksona-floating-button",e.innerHTML="⚙️",e.setAttribute("aria-label","Open Worksona Control Panel"),n.appendChild(e);const t=document.createElement("div");t.id="worksona-modal-container";const o=document.createElement("div");o.id="worksona-overlay",n.appendChild(o),n.appendChild(t),document.body.appendChild(n),setTimeout(()=>{this.createControlPanel("worksona-modal-container");t.querySelector(".worksona-control-panel")||(this._log("Failed to create control panel content, retrying...","warn"),setTimeout(()=>{this.createControlPanel("worksona-modal-container")},100))},10);const a=()=>{o.classList.remove("active"),t.classList.remove("active");const n=t.querySelector(".worksona-control-panel");n&&(n.style.display="none")},s=document.createElement("style");s.textContent="\n #worksona-floating-button {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 50px;\n height: 50px;\n border-radius: 50%;\n background: #2563eb;\n color: white;\n border: none;\n font-size: 24px;\n box-shadow: 0 2px 10px rgba(0,0,0,0.2);\n cursor: pointer;\n z-index: 9998;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease-in-out;\n }\n \n #worksona-floating-button:hover {\n transform: scale(1.1);\n background: #1d4ed8;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n }\n \n #worksona-floating-button:active {\n transform: scale(0.95);\n }\n \n @media (max-width: 768px) {\n #worksona-floating-button {\n width: 45px;\n height: 45px;\n font-size: 20px;\n bottom: 15px;\n right: 15px;\n }\n }\n \n #worksona-modal-container {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 10000;\n width: 90%;\n max-width: 800px;\n max-height: 80vh;\n overflow: auto;\n display: none;\n background: white;\n border-radius: 8px;\n }\n \n #worksona-modal-container.active {\n display: block;\n }\n \n #worksona-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 9999;\n display: none;\n }\n \n #worksona-overlay.active {\n display: block;\n }\n \n .worksona-control-panel {\n box-shadow: 0 5px 20px rgba(0,0,0,0.2);\n max-height: 80vh;\n overflow: auto;\n background: white;\n border-radius: 8px;\n transition: all 0.3s ease;\n }\n\n .worksona-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 15px 20px;\n border-bottom: 1px solid #eee;\n background: #fff;\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n .worksona-header-buttons {\n display: flex;\n gap: 10px;\n align-items: center;\n }\n\n .worksona-expand-button {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #64748b;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n }\n\n .worksona-expand-button:hover {\n color: #334155;\n }\n\n .worksona-control-panel.expanded {\n position: fixed;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100vh !important;\n max-height: 100vh !important;\n max-width: 100% !important;\n border-radius: 0;\n z-index: 10001;\n }\n\n #worksona-modal-container.expanded {\n width: 100%;\n max-width: 100%;\n height: 100vh;\n max-height: 100vh;\n top: 0;\n left: 0;\n transform: none;\n border-radius: 0;\n }\n ",document.head.appendChild(s),e.addEventListener("click",()=>{o.classList.add("active"),t.classList.add("active");const n=t.querySelector(".worksona-control-panel");if(n)n.style.display="block";else{this._log("Control panel not found, attempting to recreate","warn");!1!==this.createControlPanel("worksona-modal-container")?setTimeout(()=>{const n=t.querySelector(".worksona-control-panel");n?(n.style.display="block",this._log("Control panel recreated successfully","info")):(this._log("Failed to recreate control panel - panel element not found after creation","error"),this.updateControlPanel())},50):this._log("Failed to recreate control panel - container not found","error")}});const r=t.querySelector(".worksona-expand-button");r&&r.addEventListener("click",()=>{const n=t.querySelector(".worksona-control-panel");n.classList.contains("expanded")?(n.classList.remove("expanded"),t.classList.remove("expanded"),r.innerHTML="⛶",r.title="Expand to full screen"):(n.classList.add("expanded"),t.classList.add("expanded"),r.innerHTML="⛾",r.title="Return to normal size")}),o.addEventListener("click",a);const i=t.querySelector(".worksona-close-button");i&&i.addEventListener("click",n=>{n.preventDefault(),n.stopPropagation(),a()}),document.addEventListener("keydown",n=>{"Escape"===n.key&&o.classList.contains("active")&&a()})}catch(n){this._log(`Error creating floating control panel: ${n.message}`,"error"),setTimeout(()=>this.createFloatingControlPanel(),1e3)}}isControlPanelReady(){const n=document.getElementById(this.controlPanelId),e=n?.querySelector(".worksona-control-panel");return!(!n||!e)}async processImage(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||this.options.defaultProvider;this._emit("image-analysis-start",{agentId:n,provider:a,imageData:e,options:t});try{if("openai"===a){const s=(o.config.model||"gpt-4o").trim(),r={model:s,messages:[{role:"system",content:o.config.systemPrompt||"You are a helpful vision analysis assistant."},{role:"user",content:[{type:"text",text:t.prompt||"Please analyze this image."},{type:"image_url",image_url:{url:e,detail:t.detail||"high"}}]}],temperature:o.config.temperature||.7,max_tokens:o.config.maxTokens||500,top_p:o.config.topP||1,frequency_penalty:o.config.frequencyPenalty||0,presence_penalty:o.config.presencePenalty||0,stream:!1},i=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw new Error(l.error?.message||"OpenAI image analysis error");return this._emit("image-analysis-complete",{agentId:n,provider:a,imageData:e,result:l}),l.choices[0].message.content}throw new Error(`Provider ${a} does not support image analysis`)}catch(e){return this._emit("image-processing-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_PROCESSING_ERROR","Failed to analyze image"),null}}async analyzeImage(n,e,t={}){return this.processImage(n,e,t)}async generateImage(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||this.options.defaultProvider;this._emit("image-generation-start",{agentId:n,provider:a,prompt:e,options:t});try{if("openai"===a){const s=(t.model||o.config.imageGenerationModel||"dall-e-3").trim(),r={prompt:e,n:t.n||1,size:t.size||"1024x1024",response_format:t.response_format||"url",user:n,model:s},i=await fetch("https://api.openai.com/v1/images/generations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw new Error(l.error?.message||"OpenAI image generation error");return this._emit("image-generation-complete",{agentId:n,provider:a,prompt:e,result:l}),l.data[0].url}throw new Error(`Provider ${a} does not support image generation`)}catch(e){return this._emit("image-generation-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_GENERATION_ERROR","Failed to generate image"),null}}async editImage(n,e,t,o={}){const a=this.agents.get(n);if(!a)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const s=a.config.provider||this.options.defaultProvider;this._emit("image-edit-start",{agentId:n,provider:s,prompt:t,options:o});try{if("openai"===s){const r=(o.model||a.config.model||"dalle-3").trim(),i={image:e,prompt:t,n:o.n||1,size:o.size||"1024x1024",response_format:o.response_format||"url",user:n,model:r},l=await fetch("https://api.openai.com/v1/images/edits",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(i)}),d=await l.json();if(!l.ok)throw new Error(d.error?.message||"OpenAI image edit error");return this._emit("image-edit-complete",{agentId:n,provider:s,prompt:t,result:d}),d.data[0].url}throw new Error(`Provider ${s} does not support image editing`)}catch(e){return this._emit("image-edit-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_EDIT_ERROR","Failed to edit image"),null}}async variationImage(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||this.options.defaultProvider;this._emit("image-variation-start",{agentId:n,provider:a,options:t});try{if("openai"===a){const s=(t.model||o.config.model||"dalle-3").trim(),r={image:e,n:t.n||1,size:t.size||"1024x1024",response_format:t.response_format||"url",user:n,model:s},i=await fetch("https://api.openai.com/v1/images/variations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw new Error(l.error?.message||"OpenAI image variation error");return this._emit("image-variation-complete",{agentId:n,provider:a,result:l}),l.data[0].url}throw new Error(`Provider ${a} does not support image variation`)}catch(e){return this._emit("image-variation-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_VARIATION_ERROR","Failed to create image variation"),null}}}"undefined"!=typeof module&&module.exports?module.exports=e:n.Worksona=e}("undefined"!=typeof window?window:global);
|
|
1
|
+
"use strict";class Agent{constructor(n){this.id=n.id,this.name=n.name,this.description=n.description,n.config?(this.config={...n,...n.config},delete this.config.config):this.config=n,this.systemPrompt=this.config.systemPrompt,this.examples=this.config.examples||[],this.config.traits&&(this.traits=this.config.traits),this.transactions=[],this.metrics={totalQueries:0,avgResponseTime:0,lastActive:null,successRate:1,errorCount:0},this.state={isActive:!0,currentProvider:this.config.provider||"openai",currentModel:this.config.model,lastError:null}}addTransaction(n){if(this.transactions.push(n),this.metrics.totalQueries++,this.metrics.lastActive=new Date,n.duration){const e=this.metrics.avgResponseTime*(this.metrics.totalQueries-1)+n.duration;this.metrics.avgResponseTime=e/this.metrics.totalQueries}n.error&&(this.metrics.errorCount++,this.metrics.successRate=(this.metrics.totalQueries-this.metrics.errorCount)/this.metrics.totalQueries,this.state.lastError=n.error),this.transactions.length>100&&(this.transactions=this.transactions.slice(-100))}getHistory(){return this.transactions}getMetrics(){return this.metrics}getState(){return this.state}}!function(n){class e{constructor(n={}){this.options={debug:!1,defaultProvider:"openai",defaultModel:"gpt-4o",apiKeys:{},...n},this.agents=new Map,this.activeProvider=null,this.controlPanelId=null,this.eventHandlers={},this._initializeProviders(),!1!==n.controlPanel&&"undefined"!=typeof document&&this.createFloatingControlPanel()}_initializeProviders(){this.providers={openai:this.options.apiKeys.openai?{chat:async(n,e)=>{try{const t=e.content&&"image"===e.content.type,o=(n.config.model||this.options.defaultModel||"gpt-4o").trim();let a;if(this._log(`Making OpenAI request with model: ${o}`,"info"),t||e&&"image"===e.type||e&&e.content&&"object"==typeof e.content&&"image"===e.content.type){let o;if(t?o=e.content:"image"===e.type?o=e:e.content&&"image"===e.content.type&&(o=e.content),!o||!o.imageUrl)throw new Error("Invalid image data: Missing required imageUrl property");a=[{role:"system",content:n.config.systemPrompt||"You are a helpful vision analysis assistant."},{role:"user",content:[{type:"text",text:o.prompt||"Please analyze this image."},{type:"image_url",image_url:{url:o.imageUrl,detail:o.detail||"high"}}]}],this._log(`Vision message structure: ${JSON.stringify(a)}`,"info")}else{let t="";if("string"==typeof e)t=e;else if(e&&"string"==typeof e.content)t=e.content;else if(e&&e.content)try{t=JSON.stringify(e.content)}catch(n){t="Unable to process message content"}else if(e)try{t=JSON.stringify(e)}catch(n){t="Unable to process message"}else t="No message provided";this._log(`Processed user content: ${t.substring(0,100)}${t.length>100?"...":""}`,"info"),a=[{role:"system",content:n.config.systemPrompt||"You are a helpful assistant."},...(n.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:t}]}const s=!o.startsWith("gpt-5")&&!o.startsWith("o1")&&!o.startsWith("o3"),r={model:o,messages:a,temperature:s?n.config.temperature||.7:1,max_completion_tokens:n.config.maxTokens||500,top_p:n.config.topP||1,frequency_penalty:n.config.frequencyPenalty||0,presence_penalty:n.config.presencePenalty||0,stream:!1},i="https://api.openai.com/v1/chat/completions",l=await fetch(i,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`,"OpenAI-Organization":n.config.organization||""},body:JSON.stringify(r)}),d=await l.json();if(!l.ok)throw this._log(`OpenAI API error: ${JSON.stringify(d)}`,"error"),new Error(d.error?.message||`OpenAI API error: ${l.status}`);return t&&this._log(`Successfully processed vision request with model: ${o}`),d.choices[0].message.content}catch(n){this._log(`OpenAI error details: ${n.message}`,"error"),this._handleError(n,"PROVIDER_ERROR","OpenAI request failed")}},defaultModels:{chat:"gpt-4o",vision:"gpt-4o",reasoning:"o3",reasoningMini:"o3-mini",gpt5:"gpt-5",gpt5Mini:"gpt-5-mini",gpt5Nano:"gpt-5-nano"},supportedModels:["gpt-5","gpt-5-mini","gpt-5-nano","o1","o1-mini","o1-preview","o3","o3-mini","gpt-4o","gpt-4o-mini","gpt-4-turbo","gpt-4-turbo-preview","gpt-4","gpt-4-32k","gpt-4-vision-preview","gpt-3.5-turbo","gpt-3.5-turbo-16k","gpt-4o-vision","gpt-4-turbo-vision"]}:null,anthropic:this.options.apiKeys.anthropic?{chat:async(n,e)=>{try{const t=n.config.model||"claude-sonnet-4-5-20250929",o=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.options.apiKeys.anthropic,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:t,max_tokens:n.config.maxTokens||500,temperature:n.config.temperature||.7,system:n.config.systemPrompt,messages:[...(n.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:e}],top_p:n.config.topP||1,top_k:n.config.topK||50,metadata:{user_id:n.id}})}),a=await o.json();if(!o.ok)throw new Error(a.error?.message||"Anthropic API error");return a.content[0].text}catch(n){this._handleError(n,"PROVIDER_ERROR","Anthropic request failed")}},defaultModels:{chat:"claude-sonnet-4-5-20250929",completion:"claude-sonnet-4-5-20250929",opus45:"claude-opus-4-5-20251101",sonnet45:"claude-sonnet-4-5-20250929",sonnet35:"claude-3-5-sonnet-20241022",haiku35:"claude-3-5-haiku-20241022"},supportedModels:["claude-opus-4-5-20251101","claude-sonnet-4-5-20250929","claude-3-5-sonnet-20241022","claude-3-5-sonnet-20240620","claude-3-5-haiku-20241022","claude-3-opus-20240229","claude-3-sonnet-20240229","claude-3-haiku-20240307","claude-2.1","claude-2.0","claude-instant-1.2"]}:null,google:this.options.apiKeys.google?{chat:async(n,e)=>{try{const t=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${n.config.model||"gemini-pro"}:generateContent?key=${this.options.apiKeys.google}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contents:[{role:"user",parts:[{text:n.config.systemPrompt}]},...(n.config.examples||[]).flatMap(n=>[{role:"user",parts:[{text:n.user}]},{role:"model",parts:[{text:n.assistant}]}]),{role:"user",parts:[{text:e}]}],generationConfig:{temperature:n.config.temperature||.7,maxOutputTokens:n.config.maxTokens||500,topP:n.config.topP||1,topK:n.config.topK||40,candidateCount:1},safetySettings:[{category:"HARM_CATEGORY_HARASSMENT",threshold:"BLOCK_MEDIUM_AND_ABOVE"},{category:"HARM_CATEGORY_HATE_SPEECH",threshold:"BLOCK_MEDIUM_AND_ABOVE"}]})}),o=await t.json();if(!t.ok)throw new Error(o.error?.message||"Google API error");return o.candidates[0].content.parts[0].text}catch(n){this._handleError(n,"PROVIDER_ERROR","Google request failed")}},defaultModels:{chat:"gemini-pro",vision:"gemini-pro-vision"}}:null}}_formatMessages(n,e,t){switch(n){case"openai":return[{role:"system",content:e.config.systemPrompt},...(e.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:t}];case"anthropic":return[...(e.config.examples||[]).flatMap(n=>[{role:"user",content:n.user},{role:"assistant",content:n.assistant}]),{role:"user",content:t}];case"google":return[{role:"user",parts:[{text:e.config.systemPrompt}]},...(e.config.examples||[]).flatMap(n=>[{role:"user",parts:[{text:n.user}]},{role:"model",parts:[{text:n.assistant}]}]),{role:"user",parts:[{text:t}]}];default:throw new Error(`Unsupported provider: ${n}`)}}async loadAgent(n){if(!n.id||!n.name)return this._handleError(new Error("Invalid agent configuration"),"CONFIG_ERROR"),null;try{const e=new Agent(n);return this.agents.set(e.id,e),this._emit("agent-loaded",{agentId:e.id,name:e.name,description:e.description,provider:e.state.currentProvider,model:e.state.currentModel}),this.updateControlPanel(),this._log(`Agent loaded: ${e.name} (${e.id})`),e}catch(e){return this._handleError(e,"AGENT_LOAD_ERROR",`Failed to load agent: ${n.id}`),null}}async chat(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||t.provider||this.options.defaultProvider;if(!this.providers[a])return this._handleError(new Error(`Provider not available: ${a}`),"PROVIDER_ERROR"),null;o.state.currentProvider=a,o.state.currentModel=o.config.model||this.options.defaultModel;const s={timestamp:new Date,query:e,response:null,duration:0,error:null,provider:a,model:o.state.currentModel};this._emit("chat-start",{agentId:n,message:e}),this._log(`Chat request to ${n}: ${e}`);const r=Date.now();try{const t=await this.providers[a].chat(o,e);return s.duration=Date.now()-r,s.response=t,o.addTransaction(s),this.updateControlPanel(),this._emit("chat-complete",{agentId:n,message:e,response:t,duration:s.duration}),this._log(`Chat response from ${n}: ${t}`),t}catch(e){return s.error=e,s.duration=Date.now()-r,o.addTransaction(s),this.updateControlPanel(),this._handleError(e,"CHAT_ERROR",`Chat failed with ${n}`),null}}getAgentHistory(n){const e=this.agents.get(n);return e?e.getHistory():[]}getAgentMetrics(n){const e=this.agents.get(n);return e?e.getMetrics():null}getAgentState(n){const e=this.agents.get(n);return e?e.getState():null}getAgent(n){return this.agents.get(n)}getAllAgents(){return Array.from(this.agents.values())}removeAgent(n){const e=this.agents.delete(n);return e&&(this._emit("agent-removed",n),this._log(`Agent removed: ${n}`),this.updateControlPanel()),e}on(n,e){this.eventHandlers[n]||(this.eventHandlers[n]=[]),this.eventHandlers[n].push(e)}off(n,e){this.eventHandlers[n]&&(this.eventHandlers[n]=this.eventHandlers[n].filter(n=>n!==e))}_emit(n,e){this.eventHandlers[n]&&this.eventHandlers[n].forEach(n=>n(e))}_handleError(n,e,t){let o=t||n.message;switch(e){case"IMAGE_PROCESSING_ERROR":n.message.includes("image_too_large")?o="Image size exceeds maximum allowed size. Please reduce the image size.":n.message.includes("invalid_image_format")?o="Invalid image format. Supported formats are: JPEG, PNG, WEBP, GIF.":n.message.includes("vision_model_unavailable")&&(o="Vision model is currently unavailable. Please try again later."),n.message.includes("invalid_api_key")?o="Invalid OpenAI API key. Please check your credentials.":n.message.includes("insufficient_quota")?o="OpenAI API quota exceeded. Please check your usage limits.":n.message.includes("rate_limit_exceeded")&&(o="OpenAI API rate limit exceeded. Please try again later.");break;case"PROVIDER_ERROR":n.message&&n.message.includes("401")?o="API key is invalid or missing. Please check your API key in the control panel.":n.message&&n.message.includes("invalid_api_key")?o="Invalid API key format. Please check your API key in the control panel.":n.message&&n.message.includes("model")&&(o=`Model error: ${n.message}. Please try a different model in the control panel.`);break;case"CONFIG_ERROR":o="Invalid agent configuration. Please check your agent configuration and try again.";break;case"AGENT_LOAD_ERROR":o=`Failed to load agent: ${n.message}. Please check the agent configuration and try again.`;break;case"AGENT_NOT_FOUND":o=`Agent not found: ${n.message}. Please check the agent ID and try again.`;break;case"CHAT_ERROR":o=`Chat failed with ${n.message}. Please check the chat request and try again.`;break;default:o=n.message||"An unknown error occurred. Please try again later."}const a={message:o,code:e,originalError:n};throw this._emit("error",a),this._log(`Error [${e}]: ${a.message}`,"error"),a}_log(n,e="info"){this.options.debug&&console[e](`[Worksona] ${n}`)}createControlPanel(n){this.controlPanelId=n;const e=document.getElementById(n);if(!e)return this._log("Control panel container not found","error"),!1;this.controlPanelContainer=e,e.innerHTML='\n <div class="worksona-control-panel">\n <div class="worksona-panel-header">\n <h2>Worksona Agents Control Panel</h2>\n <div class="worksona-header-buttons">\n <button class="worksona-expand-button" title="Toggle full screen">⛶</button>\n <button class="worksona-close-button">×</button>\n </div>\n </div>\n \n <div class="worksona-llm-status-bar">\n <div class="worksona-status-label">LLM Status</div>\n <div class="worksona-status-indicators">\n <div class="worksona-status-item">\n <div class="worksona-status-dot" id="worksona-openai-status"></div>\n <span>OpenAI</span>\n </div>\n <div class="worksona-status-item">\n <div class="worksona-status-dot" id="worksona-anthropic-status"></div>\n <span>Anthropic</span>\n </div>\n <div class="worksona-status-item">\n <div class="worksona-status-dot" id="worksona-google-status"></div>\n <span>Google</span>\n </div>\n </div>\n </div>\n \n <div class="worksona-tabs">\n <button class="worksona-tab" data-tab="api-keys">API Keys</button>\n <button class="worksona-tab active" data-tab="agents">Agents</button>\n </div>\n \n <div class="worksona-content">\n <div class="worksona-tab-content" id="worksona-api-keys-tab">\n <h3 class="worksona-section-title">LLM Provider API Keys</h3>\n \n <div class="worksona-key-input">\n <label for="worksona-openai-key">OpenAI API Key</label>\n <div class="worksona-input-group">\n <input type="password" id="worksona-openai-key" placeholder="sk-...">\n <button class="worksona-toggle-visibility">👁️</button>\n </div>\n </div>\n \n <div class="worksona-key-input">\n <label for="worksona-anthropic-key">Anthropic API Key</label>\n <div class="worksona-input-group">\n <input type="password" id="worksona-anthropic-key" placeholder="sk-ant-...">\n <button class="worksona-toggle-visibility">👁️</button>\n </div>\n </div>\n \n <div class="worksona-key-input">\n <label for="worksona-google-key">Google API Key</label>\n <div class="worksona-input-group">\n <input type="password" id="worksona-google-key" placeholder="AIza...">\n <button class="worksona-toggle-visibility">👁️</button>\n </div>\n </div>\n \n <div class="worksona-button-group">\n <button id="worksona-save-keys" class="worksona-primary-button">Save API Keys</button>\n <button id="worksona-test-connections" class="worksona-secondary-button">Test Connections</button>\n </div>\n </div>\n \n <div class="worksona-tab-content active" id="worksona-agents-tab">\n <div id="worksona-agent-list"></div>\n </div>\n </div>\n </div>\n ';const t=document.createElement("style");return t.textContent="\n .worksona-control-panel {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n color: #333;\n background: white;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n overflow: hidden;\n width: 100%;\n max-width: 800px;\n margin: 0 auto;\n position: relative;\n }\n\n .worksona-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 15px 20px;\n border-bottom: 1px solid #eee;\n }\n\n .worksona-panel-header h2 {\n margin: 0;\n color: #1a56db;\n font-size: 18px;\n font-weight: 600;\n }\n\n .worksona-header-buttons {\n display: flex;\n gap: 10px;\n align-items: center;\n }\n\n .worksona-expand-button {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #64748b;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n }\n\n .worksona-expand-button:hover {\n color: #334155;\n }\n\n .worksona-llm-status-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px 20px;\n background: #111827;\n color: white;\n }\n\n .worksona-status-indicators {\n display: flex;\n gap: 20px;\n }\n\n .worksona-status-item {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 14px;\n }\n\n .worksona-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #6b7280;\n }\n\n .worksona-status-dot.active {\n background: #10b981;\n }\n\n .worksona-tabs {\n display: flex;\n padding: 0 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .worksona-tab {\n padding: 15px 20px;\n background: none;\n border: none;\n cursor: pointer;\n color: #6b7280;\n font-weight: 500;\n position: relative;\n }\n\n .worksona-tab:hover {\n color: #4b5563;\n }\n\n .worksona-tab.active {\n color: #2563eb;\n }\n\n .worksona-tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 2px;\n background: #2563eb;\n }\n\n .worksona-content {\n padding: 20px;\n }\n\n .worksona-tab-content {\n display: none;\n }\n\n .worksona-tab-content.active {\n display: block;\n }\n\n .worksona-section-title {\n font-size: 16px;\n font-weight: 600;\n margin-top: 0;\n margin-bottom: 20px;\n color: #111827;\n }\n\n .worksona-key-input {\n margin-bottom: 15px;\n }\n\n .worksona-key-input label {\n display: block;\n margin-bottom: 5px;\n font-weight: 500;\n color: #374151;\n }\n\n .worksona-input-group {\n display: flex;\n align-items: center;\n }\n\n .worksona-input-group input {\n flex: 1;\n padding: 10px 12px;\n border: 1px solid #d1d5db;\n border-radius: 6px 0 0 6px;\n font-size: 14px;\n }\n\n .worksona-toggle-visibility {\n padding: 10px 12px;\n background: #f9fafb;\n border: 1px solid #d1d5db;\n border-left: none;\n border-radius: 0 6px 6px 0;\n cursor: pointer;\n }\n\n .worksona-button-group {\n display: flex;\n gap: 10px;\n margin-top: 20px;\n }\n\n .worksona-primary-button {\n padding: 8px 16px;\n background: #2563eb;\n color: white;\n border: none;\n border-radius: 6px;\n font-weight: 500;\n cursor: pointer;\n }\n\n .worksona-primary-button:hover {\n background: #1d4ed8;\n }\n\n .worksona-secondary-button {\n padding: 8px 16px;\n background: #f3f4f6;\n color: #374151;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n font-weight: 500;\n cursor: pointer;\n }\n\n .worksona-secondary-button:hover {\n background: #e5e7eb;\n }\n\n .worksona-agent-card {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 15px;\n margin-bottom: 15px;\n transition: box-shadow 0.2s;\n }\n \n .worksona-agent-card:hover {\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n }\n\n .worksona-agent-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 10px;\n cursor: pointer;\n position: relative;\n }\n \n .worksona-expand-icon {\n font-size: 12px;\n color: #6b7280;\n transition: transform 0.2s;\n }\n \n .worksona-expand-icon.rotated {\n transform: rotate(180deg);\n }\n \n .worksona-agent-details.active + .worksona-expand-icon {\n transform: rotate(180deg);\n }\n\n .worksona-agent-name {\n font-size: 16px;\n font-weight: 600;\n color: #111827;\n margin: 0;\n }\n\n .worksona-agent-id {\n color: #6b7280;\n font-size: 12px;\n font-family: monospace;\n }\n \n .worksona-agent-status {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n \n .worksona-status-label {\n font-size: 12px;\n padding: 2px 6px;\n border-radius: 10px;\n background: #f3f4f6;\n }\n \n .worksona-agent-status.active .worksona-status-label {\n background: #dcfce7;\n color: #166534;\n }\n \n .worksona-agent-status.inactive .worksona-status-label {\n background: #fee2e2;\n color: #991b1b;\n }\n\n .worksona-agent-description {\n color: #4b5563;\n margin-bottom: 15px;\n font-size: 14px;\n }\n \n .worksona-agent-details {\n display: none;\n overflow: hidden;\n border-top: 1px solid #e5e7eb;\n margin-top: 10px;\n padding-top: 15px;\n }\n \n .worksona-agent-details.active {\n display: block;\n }\n \n .worksona-agent-tabs {\n display: flex;\n border-bottom: 1px solid #e5e7eb;\n margin-bottom: 15px;\n }\n \n .worksona-agent-tab {\n padding: 8px 16px;\n border: none;\n background: none;\n cursor: pointer;\n color: #6b7280;\n font-weight: 500;\n position: relative;\n font-size: 14px;\n }\n \n .worksona-agent-tab:hover {\n color: #111827;\n }\n \n .worksona-agent-tab.active {\n color: #2563eb;\n border-bottom: 2px solid #2563eb;\n }\n \n .worksona-agent-tab-content {\n display: none;\n }\n \n .worksona-agent-tab-content.active {\n display: block;\n }\n \n .worksona-agent-tab-content h4 {\n font-size: 14px;\n font-weight: 600;\n margin: 0 0 10px;\n color: #111827;\n }\n \n .worksona-config-details,\n .worksona-traits,\n .worksona-metrics {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 15px;\n font-size: 13px;\n line-height: 1.5;\n }\n \n .worksona-prompt-box {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n margin-bottom: 15px;\n font-size: 13px;\n line-height: 1.5;\n white-space: pre-wrap;\n font-family: monospace;\n max-height: 200px;\n overflow-y: auto;\n }\n \n .worksona-examples {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-bottom: 20px;\n }\n \n .worksona-example {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n font-size: 13px;\n }\n \n .worksona-example-user {\n margin-bottom: 8px;\n color: #4b5563;\n }\n \n .worksona-example-assistant {\n color: #1f2937;\n }\n \n .worksona-history {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-bottom: 15px;\n max-height: 300px;\n overflow-y: auto;\n }\n \n .worksona-history-item {\n background: #f9fafb;\n border-radius: 6px;\n padding: 12px;\n font-size: 13px;\n }\n \n .worksona-history-time {\n font-size: 11px;\n color: #6b7280;\n margin-bottom: 5px;\n }\n \n .worksona-history-query {\n margin-bottom: 8px;\n color: #4b5563;\n }\n \n .worksona-history-response {\n color: #1f2937;\n margin-bottom: 8px;\n }\n \n .worksona-history-meta {\n font-size: 11px;\n color: #6b7280;\n }\n \n .worksona-no-agents {\n text-align: center;\n padding: 40px 20px;\n color: #6b7280;\n background: #f9fafb;\n border-radius: 8px;\n }\n \n .worksona-no-examples {\n color: #6b7280;\n font-style: italic;\n background: #f9fafb;\n padding: 12px;\n border-radius: 6px;\n margin: 10px 0;\n }\n \n .worksona-control-panel {\n box-shadow: 0 5px 20px rgba(0,0,0,0.2);\n max-height: 80vh;\n overflow: auto;\n background: white;\n border-radius: 8px;\n }\n \n .worksona-json-display {\n background: #f8fafc;\n border-radius: 6px;\n padding: 15px;\n margin: 0;\n font-family: monospace;\n font-size: 13px;\n line-height: 1.5;\n overflow: auto;\n max-height: 500px;\n white-space: pre-wrap;\n color: #334155;\n border: 1px solid #e2e8f0;\n }\n \n /* Ensure the json tab content has proper height */\n #worksona-agent-tab-content[id$=\"-json\"] {\n max-height: 500px;\n overflow: auto;\n }\n \n /* JSON syntax highlighting */\n .worksona-json-key {\n color: #0f766e;\n }\n \n .worksona-json-string {\n color: #b91c1c;\n }\n \n .worksona-json-number {\n color: #1d4ed8;\n }\n \n .worksona-json-boolean {\n color: #7e22ce;\n }\n \n .worksona-json-null {\n color: #64748b;\n }\n \n /* Ensure the modal is scrollable on smaller screens */\n @media (max-height: 768px) {\n #worksona-modal-container {\n max-height: 90vh;\n }\n \n .worksona-control-panel {\n max-height: 90vh;\n }\n }\n ",document.head.appendChild(t),this._setupEventListeners(e),this.updateControlPanel(),!0}_setupEventListeners(n){if(!(n=n||this.controlPanelContainer))return void this._log("No container available for event listeners","error");n.querySelectorAll(".worksona-tab").forEach(e=>{e.addEventListener("click",()=>{n.querySelectorAll(".worksona-tab").forEach(n=>n.classList.remove("active")),n.querySelectorAll(".worksona-tab-content").forEach(n=>n.classList.remove("active")),e.classList.add("active"),document.getElementById(`worksona-${e.dataset.tab}-tab`).classList.add("active")})}),n.querySelectorAll(".worksona-toggle-visibility").forEach(n=>{n.addEventListener("click",()=>{const e=n.previousElementSibling;"password"===e.type?(e.type="text",n.textContent="🔒"):(e.type="password",n.textContent="👁️")})});const e=document.getElementById("worksona-save-keys");if(e){const n=e.cloneNode(!0);e.parentNode.replaceChild(n,e),n.addEventListener("click",()=>{const n=document.getElementById("worksona-openai-key").value,e=document.getElementById("worksona-anthropic-key").value,t=document.getElementById("worksona-google-key").value;n&&localStorage.setItem("openai_api_key",n),e&&localStorage.setItem("anthropic_api_key",e),t&&localStorage.setItem("google_api_key",t),this.options.apiKeys={...this.options.apiKeys,...n&&{openai:n},...e&&{anthropic:e},...t&&{google:t}},this._initializeProviders(),this.updateControlPanel(),this._emit("api-keys-updated",{providers:Object.keys(this.options.apiKeys)}),alert("API keys saved successfully!")})}const t=document.getElementById("worksona-test-connections");if(t){const n=t.cloneNode(!0);t.parentNode.replaceChild(n,t),n.addEventListener("click",async()=>{n.disabled=!0,n.textContent="Testing...";try{await this._testProviderConnections(),this.updateControlPanel()}finally{n.disabled=!1,n.textContent="Test Connections"}})}const o=n.querySelector(".worksona-close-button");if(o){const e=o.cloneNode(!0);o.parentNode.replaceChild(e,o),e.addEventListener("click",()=>{const e=n.querySelector(".worksona-control-panel");e&&(e.style.display="none")})}n.querySelectorAll('input[type="range"]').forEach(n=>{const e=n.nextElementSibling;n.addEventListener("input",()=>{e&&(e.textContent=n.value)}),e&&n.value&&(e.textContent=n.value)})}async _testProviderConnections(){const n=["openai","anthropic","google"];for(const e of n){const n=document.getElementById(`worksona-${e}-status`);if(n)if(this.options.apiKeys[e]&&""!==this.options.apiKeys[e].trim())try{let t=!1;switch(e){case"openai":t=this.options.apiKeys.openai&&this.options.apiKeys.openai.startsWith("sk-");break;case"anthropic":t=this.options.apiKeys.anthropic&&this.options.apiKeys.anthropic.startsWith("sk-ant-");break;case"google":t=this.options.apiKeys.google&&this.options.apiKeys.google.length>10}n.className=t?"worksona-status-dot active":"worksona-status-dot",this._log(`Provider ${e} validation result: ${t?"valid":"invalid"}`)}catch(t){n.className="worksona-status-dot",console.error(`Error testing ${e} connection:`,t)}else n.className="worksona-status-dot"}}updateControlPanel(){this.controlPanelId&&(this._updateProviderStatus(),Object.entries(this.options.apiKeys).forEach(([n,e])=>{const t=document.getElementById(`worksona-${n}-key`);t&&e&&(t.value=e)}),this._updateAgentList(),this._setupAgentEventListeners(),this.controlPanelContainer&&this._setupEventListeners(this.controlPanelContainer))}_updateProviderStatus(){["openai","anthropic","google"].forEach(n=>{const e=document.getElementById(`worksona-${n}-status`);if(!e)return;const t=!!this.options.apiKeys[n];e.className=t?"worksona-status-dot active":"worksona-status-dot"})}_updateAgentList(){const n=document.getElementById("worksona-agent-list");if(!n)return;const e=this.getAgents();0!==e.length?(n.innerHTML=e.map(n=>{const e=n.getMetrics(),t=n.getState(),o=n.getHistory(),a=o.length>0?o.slice(-5).map(n=>`\n <div class="worksona-history-item">\n <div class="worksona-history-time">${new Date(n.timestamp).toLocaleTimeString()}</div>\n <div class="worksona-history-query"><strong>Query:</strong> ${this._escapeHtml(n.query)}</div>\n <div class="worksona-history-response"><strong>Response:</strong> ${this._escapeHtml(n.response||"Error: "+(n.error?.message||"Unknown error"))}</div>\n <div class="worksona-history-meta">\n <span>Provider: ${n.provider}</span> | \n <span>Model: ${n.model}</span> | \n <span>Duration: ${n.duration}ms</span>\n </div>\n </div>\n `).join(""):"<p>No interaction history available yet.</p>",s=n=>n.systemPrompt||n.config?.systemPrompt||n.config?.config?.systemPrompt||"",r=n=>{const e=n.examples||n.config?.examples||n.config?.config?.examples||[];return console.log("Agent:",n.id,"Examples:",JSON.stringify(e)),e},i=s(n),l=i?`<div class="worksona-prompt-box">${this._escapeHtml(i)}</div>`:'<p class="worksona-no-examples">No system prompt has been defined for this agent. A system prompt helps establish the agent\'s behavior and capabilities.</p>',d=r(n),c=d&&d.length>0?d.map(n=>`\n <div class="worksona-example">\n <div class="worksona-example-user"><strong>User:</strong> ${this._escapeHtml(n.user||"")}</div>\n <div class="worksona-example-assistant"><strong>Assistant:</strong> ${this._escapeHtml(n.assistant||"")}</div>\n </div>\n `).join(""):'<p class="worksona-no-examples">No examples have been defined for this agent. Examples help demonstrate the expected conversation flow.</p>',p=`\n <div class="worksona-config-details">\n <h4>Model Settings</h4>\n <div><strong>Provider:</strong> ${n.config?.provider||n.state?.currentProvider||"default"}</div>\n <div><strong>Model:</strong> ${n.config?.model||n.state?.currentModel||"default"}</div>\n <div><strong>Temperature:</strong> ${void 0!==n.config?.temperature?n.config.temperature:void 0!==n.config?.config?.temperature?n.config.config.temperature:"default"}</div>\n <div><strong>Max Tokens:</strong> ${void 0!==n.config?.maxTokens?n.config.maxTokens:void 0!==n.config?.config?.maxTokens?n.config.config.maxTokens:"default"}</div>\n ${void 0!==n.config?.topP||void 0!==n.config?.config?.topP?`<div><strong>Top P:</strong> ${void 0!==n.config?.topP?n.config.topP:n.config?.config?.topP}</div>`:""}\n ${void 0!==n.config?.frequencyPenalty||void 0!==n.config?.config?.frequencyPenalty?`<div><strong>Frequency Penalty:</strong> ${void 0!==n.config?.frequencyPenalty?n.config.frequencyPenalty:n.config?.config?.frequencyPenalty}</div>`:""}\n ${void 0!==n.config?.presencePenalty||void 0!==n.config?.config?.presencePenalty?`<div><strong>Presence Penalty:</strong> ${void 0!==n.config?.presencePenalty?n.config.presencePenalty:n.config?.config?.presencePenalty}</div>`:""}\n </div>\n `,g=JSON.stringify({id:n.id,name:n.name,description:n.description,config:{provider:n.config.provider,model:n.config.model,temperature:n.config.temperature,maxTokens:n.config.maxTokens,topP:n.config.topP,frequencyPenalty:n.config.frequencyPenalty,presencePenalty:n.config.presencePenalty},systemPrompt:s(n),examples:r(n),traits:n.traits||{},metrics:n.getMetrics(),state:n.getState(),transactions:n.getHistory().slice(-5)},null,2),u=n.traits||{},m=`\n <div class="worksona-traits">\n ${u.personality?`<div><strong>Personality:</strong> ${u.personality.join(", ")}</div>`:""}\n ${u.knowledge?`<div><strong>Knowledge:</strong> ${u.knowledge.join(", ")}</div>`:""}\n ${u.tone?`<div><strong>Tone:</strong> ${u.tone}</div>`:""}\n ${u.background?`<div><strong>Background:</strong> ${u.background}</div>`:""}\n </div>\n `;return`\n <div class="worksona-agent-card">\n <div class="worksona-agent-header" onclick="document.getElementById('worksona-agent-details-${n.id}').classList.toggle('active'); this.querySelector('.worksona-expand-icon').classList.toggle('rotated')">\n <h3 class="worksona-agent-name">${n.name}</h3>\n <div class="worksona-agent-status ${t.isActive?"active":"inactive"}">\n <span class="worksona-agent-id">${n.id}</span>\n <span class="worksona-status-label">${t.isActive?"Active":"Inactive"}</span>\n </div>\n <div class="worksona-expand-icon">▼</div>\n </div>\n <p class="worksona-agent-description">${n.description||"No description provided"}</p>\n \n <div id="worksona-agent-details-${n.id}" class="worksona-agent-details">\n <div class="worksona-agent-tabs">\n <button class="worksona-agent-tab active" data-agent="${n.id}" data-tab="agent">Agent Details</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="model">Model Settings</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="prompt">System Prompt</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="history">History</button>\n <button class="worksona-agent-tab" data-agent="${n.id}" data-tab="json">Raw JSON</button>\n </div>\n \n <div class="worksona-agent-tab-content active" id="worksona-agent-${n.id}-agent">\n <h4>Agent Configuration</h4>\n <div class="worksona-config-details">\n <div><strong>ID:</strong> ${n.id}</div>\n <div><strong>Name:</strong> ${n.name}</div>\n <div><strong>Description:</strong> ${n.description||"No description provided"}</div>\n </div>\n <h4>Traits</h4>\n ${m}\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-model">\n <h4>Model Settings</h4>\n ${p}\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-prompt">\n <h4>System Prompt</h4>\n ${l}\n \n <h4>Examples</h4>\n <div class="worksona-examples">\n ${c}\n </div>\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-history">\n <h4>Recent Interactions</h4>\n <div class="worksona-history">\n ${a}\n </div>\n <div class="worksona-metrics">\n <div><strong>Total Queries:</strong> ${e.totalQueries}</div>\n <div><strong>Avg Response Time:</strong> ${Math.round(e.avgResponseTime)}ms</div>\n <div><strong>Success Rate:</strong> ${(100*e.successRate).toFixed(1)}%</div>\n <div><strong>Last Active:</strong> ${e.lastActive?new Date(e.lastActive).toLocaleTimeString():"Never"}</div>\n </div>\n </div>\n \n <div class="worksona-agent-tab-content" id="worksona-agent-${n.id}-json">\n <h4>Agent Configuration JSON</h4>\n <div class="worksona-json-display">${this._escapeHtml(g)}</div>\n </div>\n </div>\n </div>\n `}).join(""),this.agentTabEventListeners&&this.agentTabEventListeners.forEach(({element:n,type:e,listener:t})=>{n.removeEventListener(e,t)}),this.agentTabEventListeners=[],n.querySelectorAll(".worksona-agent-tab").forEach(n=>{const e=e=>{const t=n.dataset.agent,o=n.dataset.tab;document.querySelectorAll(`.worksona-agent-tab[data-agent="${t}"]`).forEach(n=>{n.classList.remove("active")}),document.querySelectorAll(`[id^="worksona-agent-${t}-"]`).forEach(n=>{n.classList.remove("active")}),n.classList.add("active"),document.getElementById(`worksona-agent-${t}-${o}`).classList.add("active")};this.agentTabEventListeners.push({element:n,type:"click",listener:e}),n.addEventListener("click",e)})):n.innerHTML='\n <div class="worksona-no-agents">\n <p>No agents have been loaded yet.</p>\n <p>Agents will appear here when they are loaded by your application.</p>\n </div>\n '}_escapeHtml(n){return n?n.toString().replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"):""}_setupAgentEventListeners(){this.off("agent-loaded",this._handleAgentLoaded),this.off("agent-removed",this._handleAgentRemoved),this.on("agent-loaded",this._handleAgentLoaded.bind(this)),this.on("agent-removed",this._handleAgentRemoved.bind(this))}_handleAgentLoaded(){this._updateAgentList()}_handleAgentRemoved(){this._updateAgentList()}getAgents(){return Array.from(this.agents.values())}createFloatingControlPanel(){if(!document.body)return"loading"===document.readyState?void document.addEventListener("DOMContentLoaded",()=>this.createFloatingControlPanel()):void setTimeout(()=>this.createFloatingControlPanel(),100);try{const n=document.createElement("div");n.id="worksona-floating-control";const e=document.createElement("button");e.id="worksona-floating-button",e.innerHTML="⚙️",e.setAttribute("aria-label","Open Worksona Control Panel"),n.appendChild(e);const t=document.createElement("div");t.id="worksona-modal-container";const o=document.createElement("div");o.id="worksona-overlay",n.appendChild(o),n.appendChild(t),document.body.appendChild(n),setTimeout(()=>{this.createControlPanel("worksona-modal-container");t.querySelector(".worksona-control-panel")||(this._log("Failed to create control panel content, retrying...","warn"),setTimeout(()=>{this.createControlPanel("worksona-modal-container")},100))},10);const a=()=>{o.classList.remove("active"),t.classList.remove("active");const n=t.querySelector(".worksona-control-panel");n&&(n.style.display="none")},s=document.createElement("style");s.textContent="\n #worksona-floating-button {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 50px;\n height: 50px;\n border-radius: 50%;\n background: #2563eb;\n color: white;\n border: none;\n font-size: 24px;\n box-shadow: 0 2px 10px rgba(0,0,0,0.2);\n cursor: pointer;\n z-index: 9998;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease-in-out;\n }\n \n #worksona-floating-button:hover {\n transform: scale(1.1);\n background: #1d4ed8;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n }\n \n #worksona-floating-button:active {\n transform: scale(0.95);\n }\n \n @media (max-width: 768px) {\n #worksona-floating-button {\n width: 45px;\n height: 45px;\n font-size: 20px;\n bottom: 15px;\n right: 15px;\n }\n }\n \n #worksona-modal-container {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 10000;\n width: 90%;\n max-width: 800px;\n max-height: 80vh;\n overflow: auto;\n display: none;\n background: white;\n border-radius: 8px;\n }\n \n #worksona-modal-container.active {\n display: block;\n }\n \n #worksona-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 9999;\n display: none;\n }\n \n #worksona-overlay.active {\n display: block;\n }\n \n .worksona-control-panel {\n box-shadow: 0 5px 20px rgba(0,0,0,0.2);\n max-height: 80vh;\n overflow: auto;\n background: white;\n border-radius: 8px;\n transition: all 0.3s ease;\n }\n\n .worksona-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 15px 20px;\n border-bottom: 1px solid #eee;\n background: #fff;\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n .worksona-header-buttons {\n display: flex;\n gap: 10px;\n align-items: center;\n }\n\n .worksona-expand-button {\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #64748b;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n }\n\n .worksona-expand-button:hover {\n color: #334155;\n }\n\n .worksona-control-panel.expanded {\n position: fixed;\n top: 0;\n left: 0;\n width: 100% !important;\n height: 100vh !important;\n max-height: 100vh !important;\n max-width: 100% !important;\n border-radius: 0;\n z-index: 10001;\n }\n\n #worksona-modal-container.expanded {\n width: 100%;\n max-width: 100%;\n height: 100vh;\n max-height: 100vh;\n top: 0;\n left: 0;\n transform: none;\n border-radius: 0;\n }\n ",document.head.appendChild(s),e.addEventListener("click",()=>{o.classList.add("active"),t.classList.add("active");const n=t.querySelector(".worksona-control-panel");if(n)n.style.display="block";else{this._log("Control panel not found, attempting to recreate","warn");!1!==this.createControlPanel("worksona-modal-container")?setTimeout(()=>{const n=t.querySelector(".worksona-control-panel");n?(n.style.display="block",this._log("Control panel recreated successfully","info")):(this._log("Failed to recreate control panel - panel element not found after creation","error"),this.updateControlPanel())},50):this._log("Failed to recreate control panel - container not found","error")}});const r=t.querySelector(".worksona-expand-button");r&&r.addEventListener("click",()=>{const n=t.querySelector(".worksona-control-panel");n.classList.contains("expanded")?(n.classList.remove("expanded"),t.classList.remove("expanded"),r.innerHTML="⛶",r.title="Expand to full screen"):(n.classList.add("expanded"),t.classList.add("expanded"),r.innerHTML="⛾",r.title="Return to normal size")}),o.addEventListener("click",a);const i=t.querySelector(".worksona-close-button");i&&i.addEventListener("click",n=>{n.preventDefault(),n.stopPropagation(),a()}),document.addEventListener("keydown",n=>{"Escape"===n.key&&o.classList.contains("active")&&a()})}catch(n){this._log(`Error creating floating control panel: ${n.message}`,"error"),setTimeout(()=>this.createFloatingControlPanel(),1e3)}}isControlPanelReady(){const n=document.getElementById(this.controlPanelId),e=n?.querySelector(".worksona-control-panel");return!(!n||!e)}async processImage(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||this.options.defaultProvider;this._emit("image-analysis-start",{agentId:n,provider:a,imageData:e,options:t});try{if("openai"===a){const s=(o.config.model||"gpt-4o").trim(),r=[{role:"system",content:o.config.systemPrompt||"You are a helpful vision analysis assistant."},{role:"user",content:[{type:"text",text:t.prompt||"Please analyze this image."},{type:"image_url",image_url:{url:e,detail:t.detail||"high"}}]}],i=!s.startsWith("gpt-5")&&!s.startsWith("o1")&&!s.startsWith("o3"),l={model:s,messages:r,temperature:i?o.config.temperature||.7:1,max_completion_tokens:o.config.maxTokens||500,top_p:o.config.topP||1,frequency_penalty:o.config.frequencyPenalty||0,presence_penalty:o.config.presencePenalty||0,stream:!1},d=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(l)}),c=await d.json();if(!d.ok)throw new Error(c.error?.message||"OpenAI image analysis error");return this._emit("image-analysis-complete",{agentId:n,provider:a,imageData:e,result:c}),c.choices[0].message.content}throw new Error(`Provider ${a} does not support image analysis`)}catch(e){return this._emit("image-processing-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_PROCESSING_ERROR","Failed to analyze image"),null}}async analyzeImage(n,e,t={}){return this.processImage(n,e,t)}async generateImage(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||this.options.defaultProvider;this._emit("image-generation-start",{agentId:n,provider:a,prompt:e,options:t});try{if("openai"===a){const s=(t.model||o.config.imageGenerationModel||"dall-e-3").trim(),r={prompt:e,n:t.n||1,size:t.size||"1024x1024",response_format:t.response_format||"url",user:n,model:s},i=await fetch("https://api.openai.com/v1/images/generations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw new Error(l.error?.message||"OpenAI image generation error");return this._emit("image-generation-complete",{agentId:n,provider:a,prompt:e,result:l}),l.data[0].url}throw new Error(`Provider ${a} does not support image generation`)}catch(e){return this._emit("image-generation-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_GENERATION_ERROR","Failed to generate image"),null}}async editImage(n,e,t,o={}){const a=this.agents.get(n);if(!a)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const s=a.config.provider||this.options.defaultProvider;this._emit("image-edit-start",{agentId:n,provider:s,prompt:t,options:o});try{if("openai"===s){const r=(o.model||a.config.model||"dalle-3").trim(),i={image:e,prompt:t,n:o.n||1,size:o.size||"1024x1024",response_format:o.response_format||"url",user:n,model:r},l=await fetch("https://api.openai.com/v1/images/edits",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(i)}),d=await l.json();if(!l.ok)throw new Error(d.error?.message||"OpenAI image edit error");return this._emit("image-edit-complete",{agentId:n,provider:s,prompt:t,result:d}),d.data[0].url}throw new Error(`Provider ${s} does not support image editing`)}catch(e){return this._emit("image-edit-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_EDIT_ERROR","Failed to edit image"),null}}async variationImage(n,e,t={}){const o=this.agents.get(n);if(!o)return this._handleError(new Error(`Agent not found: ${n}`),"AGENT_NOT_FOUND"),null;const a=o.config.provider||this.options.defaultProvider;this._emit("image-variation-start",{agentId:n,provider:a,options:t});try{if("openai"===a){const s=(t.model||o.config.model||"dalle-3").trim(),r={image:e,n:t.n||1,size:t.size||"1024x1024",response_format:t.response_format||"url",user:n,model:s},i=await fetch("https://api.openai.com/v1/images/variations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKeys.openai}`},body:JSON.stringify(r)}),l=await i.json();if(!i.ok)throw new Error(l.error?.message||"OpenAI image variation error");return this._emit("image-variation-complete",{agentId:n,provider:a,result:l}),l.data[0].url}throw new Error(`Provider ${a} does not support image variation`)}catch(e){return this._emit("image-variation-error",{agentId:n,error:e}),this._handleError(e,"IMAGE_VARIATION_ERROR","Failed to create image variation"),null}}}"undefined"!=typeof module&&module.exports?module.exports=e:n.Worksona=e}("undefined"!=typeof window?window:global);
|