@squidcloud/cli 1.0.457 → 1.0.458
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/dist/index.js
CHANGED
|
@@ -29744,7 +29744,7 @@ exports.GROK_CHAT_MODEL_NAMES = ['grok-4', 'grok-4-1-fast-reasoning', 'grok-4-1-
|
|
|
29744
29744
|
*/
|
|
29745
29745
|
exports.ANTHROPIC_CHAT_MODEL_NAMES = [
|
|
29746
29746
|
'claude-haiku-4-5-20251001',
|
|
29747
|
-
'claude-opus-4-
|
|
29747
|
+
'claude-opus-4-7',
|
|
29748
29748
|
'claude-sonnet-4-6',
|
|
29749
29749
|
];
|
|
29750
29750
|
/**
|
|
@@ -30444,14 +30444,12 @@ exports.KOTLIN_CONTROLLERS = [
|
|
|
30444
30444
|
'api',
|
|
30445
30445
|
'application',
|
|
30446
30446
|
'auth',
|
|
30447
|
-
'integration',
|
|
30448
30447
|
'internal-storage',
|
|
30449
30448
|
'management-secret',
|
|
30450
30449
|
'mutation',
|
|
30451
30450
|
'native-query',
|
|
30452
30451
|
'query',
|
|
30453
30452
|
'queue',
|
|
30454
|
-
'quota',
|
|
30455
30453
|
'scheduler',
|
|
30456
30454
|
'secret',
|
|
30457
30455
|
'storage',
|
|
@@ -37341,7 +37339,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"seek-bzip","version":"1.0.6",
|
|
|
37341
37339
|
(module) {
|
|
37342
37340
|
|
|
37343
37341
|
"use strict";
|
|
37344
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.
|
|
37342
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.458","description":"The Squid CLI","main":"dist/index.js","scripts":{"start":"node dist/index.js","start-ts":"ts-node -r tsconfig-paths/register src/index.ts","prebuild":"rimraf dist","build":"webpack --mode=production","build:dev":"webpack --mode=development","lint":"eslint","link":"npm run build && chmod 755 dist/index.js && npm link","watch":"webpack --watch","deploy":"npm run build && npm pack --silent | xargs -I {} mv {} package.tgz && npm install -g package.tgz && rm -rf package.tgz","publish:public":"npm run build && npm publish --access public"},"files":["dist/**/*"],"bin":{"squid":"dist/index.js"},"keywords":[],"author":"","license":"ISC","engines":{"node":">=18.0.0"},"dependencies":{"@squidcloud/local-backend":"^1.0.458","adm-zip":"^0.5.16","copy-webpack-plugin":"^12.0.2","decompress":"^4.2.1","logpipes":"^1.11.0","nodemon":"^3.1.9","terser-webpack-plugin":"^5.3.10","ts-loader":"^9.5.1","ts-node":"^10.9.2","tsconfig-paths":"^4.2.0","tsconfig-paths-webpack-plugin":"^4.1.0","webpack":"^5.101.3","zip-webpack-plugin":"^4.0.1"},"devDependencies":{"@types/adm-zip":"^0.5.7","@types/decompress":"^4.2.7","@types/node":"^20.19.9","terminal-link":"^3.0.0"}}');
|
|
37345
37343
|
|
|
37346
37344
|
/***/ }
|
|
37347
37345
|
|
|
@@ -18,6 +18,7 @@ Squid is a backend-as-a-service platform that provides:
|
|
|
18
18
|
- **[client.md](reference/client.md)** → client SDK, initialization, setup, auth, login, tokens, OAuth, appId, region, environmentId, apiKey, authProvider, getToken, setAuthProvider, Squid client, frontend, collection, executeFunction, executeFunctionWithHeaders, getWebhookUrl, externalAuth, saveAuthCode, getAccessToken, storage, uploadFile, downloadUrl, queues, produce, consume, distributed locks, acquireLock, withLock, web, aiSearch, getUrlContent, createShortUrl, jobs, getJob, awaitJob, observability, metrics, reportMetric, queryMetrics, notifications, publishNotification, observeNotifications
|
|
19
19
|
- **[console.md](reference/console.md)** → Squid Console, web UI, organizations, applications, AI Studio, knowledge bases, integrations, monitoring, logs, API keys, secrets, testing, debugging, profile settings, management API keys
|
|
20
20
|
- **[ai.md](reference/ai.md)** → AI agents, chat, ask, askWithAnnotations, askAsync, askWithVoiceResponse, transcribeAndChat, transcribeAndAsk, knowledge bases, RAG, embeddings, image generation, audio, transcription, text-to-speech, TTS, connectedAgents, connectedIntegrations, connectedKnowledgeBases, @aiFunction, @secureAiAgent, @secureAiQuery, memory, memoryOptions, voiceOptions, OpenAI, Anthropic, Gemini, Grok, DALL-E, Whisper, MCP, @mcpServer, @mcpTool, executeAiQuery, executeAiApiCall, extraction, createPdf, upsert agent, listAgents
|
|
21
|
+
- **[chat-widget.md](reference/chat-widget.md)** → AI chat widget, @squidcloud/react-chat-widget, squid-chat-widget, squid-chat-widget-with-fab-button, embeddable chat, custom API webhook, AI query mode, chain-of-thought, status updates, session management, agentContext, memoryOptions, squid-ai-custom-api-url, squid-ai-agent-chat-options, FAB button, theming, CSS variables, localization, RTL, menu items slots, suggested prompts, voice transcription, error formatting, authentication, squid-auth-provider, onChange events
|
|
21
22
|
- **[databases.md](reference/databases.md)** → collections, documents, queries, subscriptions, snapshots, insert, update, delete, CRUD, real-time, dereference, pagination, transactions, query operators, eq, neq, gt, gte, lt, lte, like, in, nin, arrayIncludesSome, arrayIncludesAll, sortBy, limit, join queries, OR queries, @trigger, native queries, SQL, MongoDB, Elasticsearch, incrementInPath, decrementInPath, watch changes, doc(), projectFields, field projection, __docId__, __id
|
|
22
23
|
- **[backend.md](reference/backend.md)** → SquidService, @executable, @webhook, @trigger, TriggerRequest, @scheduler, @limits, rate limiting, quotas, decorators, backend functions, WebhookRequest, CronExpression, cron, file handling, SquidFile, getUserAuth, isAuthenticated, assertIsAuthenticated, createWebhookResponse, this.squid, this.secrets, @clientConnectionStateHandler, CLI, squid init, squid start, squid deploy, squid build, project structure
|
|
23
24
|
- **[security.md](reference/security.md)** → security rules, @secureDatabase, @secureCollection, @secureTopic, @secureStorage, @secureApi, @secureNativeQuery, @secureAiQuery, @secureAiAgent, @secureDistributedLock, @secureGraphQL, QueryContext, MutationContext, isSubqueryOf, affectsPath, permissions, authorization, row-level security, role-based access
|
|
@@ -15,8 +15,9 @@ Docs: https://docs.getsquid.ai/reference-docs/backend/
|
|
|
15
15
|
- Schedulers (@scheduler)
|
|
16
16
|
- Rate Limiting (@limits)
|
|
17
17
|
- Client Connection State (@clientConnectionStateHandler)
|
|
18
|
+
- Cross-Service Communication (squidInject)
|
|
18
19
|
- Using Squid Client in Backend
|
|
19
|
-
- File Handling
|
|
20
|
+
- File Handling``
|
|
20
21
|
|
|
21
22
|
## CLI Commands
|
|
22
23
|
|
|
@@ -418,6 +419,77 @@ export class MyService extends SquidService {
|
|
|
418
419
|
- `'DISCONNECTED'` - Client disconnected but ID still retained
|
|
419
420
|
- `'REMOVED'` - Client disconnected and ID removed
|
|
420
421
|
|
|
422
|
+
## Cross-Service Communication (squidInject)
|
|
423
|
+
|
|
424
|
+
`squidInject` enables one `SquidService` to call methods on another `SquidService` within the same backend. It returns a **singleton instance** of the target service.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import { SquidService, executable, squidInject } from '@squidcloud/backend';
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Basic Usage
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
export class OrderService extends SquidService {
|
|
434
|
+
@executable()
|
|
435
|
+
async placeOrder(items: Item[]): Promise<Order> {
|
|
436
|
+
// Get a reference to another service
|
|
437
|
+
const notificationService = squidInject(NotificationService);
|
|
438
|
+
const order = await this.createOrder(items);
|
|
439
|
+
await notificationService.sendOrderConfirmation(order);
|
|
440
|
+
return order;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### As a Class Property
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
export class OrderService extends SquidService {
|
|
449
|
+
private readonly notifications = squidInject(NotificationService);
|
|
450
|
+
|
|
451
|
+
@executable()
|
|
452
|
+
async placeOrder(items: Item[]): Promise<Order> {
|
|
453
|
+
const order = await this.createOrder(items);
|
|
454
|
+
await this.notifications.sendOrderConfirmation(order);
|
|
455
|
+
return order;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Function Signature
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
function squidInject<T extends SquidService>(
|
|
464
|
+
ctor: new () => T,
|
|
465
|
+
moduleId?: TenantModuleId, // defaults to USER_CODE_MODULE_ID
|
|
466
|
+
): T
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
- `ctor` - The service class constructor to inject
|
|
470
|
+
- `moduleId` - Optional module ID for cross-module injection (e.g., connector services)
|
|
471
|
+
|
|
472
|
+
### Circular Dependency Detection
|
|
473
|
+
|
|
474
|
+
`squidInject` detects circular dependencies and throws a `CIRCULAR_DEPENDENCY` error:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
// BAD: Throws CIRCULAR_DEPENDENCY: ServiceA => ServiceB
|
|
478
|
+
export class ServiceA extends SquidService {
|
|
479
|
+
readonly b = squidInject(ServiceB);
|
|
480
|
+
}
|
|
481
|
+
export class ServiceB extends SquidService {
|
|
482
|
+
readonly a = squidInject(ServiceA);
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Notes
|
|
487
|
+
|
|
488
|
+
- Returns a **singleton** — the same instance is returned on every call for a given service class
|
|
489
|
+
- Can be called inside `@executable` methods, as class property initializers, or in constructors
|
|
490
|
+
- **Do not call from static context** during module loading — the Squid module must be initialized first
|
|
491
|
+
- Replaces the deprecated `getSquidService()` function
|
|
492
|
+
|
|
421
493
|
## Using Squid Client in Backend
|
|
422
494
|
|
|
423
495
|
The pre-initialized `this.squid` client has full permissions:
|
|
@@ -0,0 +1,1030 @@
|
|
|
1
|
+
# AI Chat Widget
|
|
2
|
+
|
|
3
|
+
The Squid AI Chat Widget (`@squidcloud/react-chat-widget`) is an embeddable chat interface that connects to Squid AI agents, AI Query, or custom webhook APIs. It is distributed as both a React component and Web Components (custom elements).
|
|
4
|
+
|
|
5
|
+
**Package:** `@squidcloud/react-chat-widget` (npm)
|
|
6
|
+
**CDN:** `https://widget.squid.cloud/widget.umd.js`
|
|
7
|
+
**Docs:** https://docs.getsquid.ai/docs/sdk/backend-sdk/ai/ai-chat-widget/
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
- Embedding the Widget
|
|
11
|
+
- Three Operation Modes
|
|
12
|
+
- Required & Optional Attributes
|
|
13
|
+
- Agent Chat Options & Context
|
|
14
|
+
- Custom API / Webhook Mode
|
|
15
|
+
- AI Query Mode
|
|
16
|
+
- Session Management
|
|
17
|
+
- Authentication & Access Control
|
|
18
|
+
- Publishing Status Updates (Chain of Thought)
|
|
19
|
+
- Events & Callbacks
|
|
20
|
+
- Styling & Theming
|
|
21
|
+
- Localization
|
|
22
|
+
- Menu Items (Slots)
|
|
23
|
+
- Suggested Prompts
|
|
24
|
+
- Voice Transcription
|
|
25
|
+
- Error Formatting
|
|
26
|
+
- FAB (Floating Action Button) Mode
|
|
27
|
+
- Framework Integration (React, Angular)
|
|
28
|
+
|
|
29
|
+
## Embedding the Widget
|
|
30
|
+
|
|
31
|
+
### Via CDN (any HTML page)
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script async src="https://widget.squid.cloud/widget.umd.js"></script>
|
|
35
|
+
|
|
36
|
+
<!-- Inline chat widget -->
|
|
37
|
+
<squid-chat-widget
|
|
38
|
+
squid-app-id="YOUR_APP_ID"
|
|
39
|
+
squid-region="us-east-1.aws"
|
|
40
|
+
squid-environment-id="prod"
|
|
41
|
+
squid-developer-id="YOUR_DEV_ID"
|
|
42
|
+
squid-ai-agent-id="YOUR_AGENT_ID"
|
|
43
|
+
header-title="Chat Support"
|
|
44
|
+
style="display: block; height: 500px;"
|
|
45
|
+
></squid-chat-widget>
|
|
46
|
+
|
|
47
|
+
<!-- Floating action button variant (bottom-right corner) -->
|
|
48
|
+
<squid-chat-widget-with-fab-button
|
|
49
|
+
squid-app-id="YOUR_APP_ID"
|
|
50
|
+
squid-region="us-east-1.aws"
|
|
51
|
+
squid-environment-id="prod"
|
|
52
|
+
squid-developer-id="YOUR_DEV_ID"
|
|
53
|
+
squid-ai-agent-id="YOUR_AGENT_ID"
|
|
54
|
+
header-title="Chat Support"
|
|
55
|
+
></squid-chat-widget-with-fab-button>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Via npm (React)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install @squidcloud/react-chat-widget @squidcloud/react @squidcloud/client rxjs
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { SquidChatWidgetEntryPoint, SquidChatWidgetWithFabButtonEntryPoint } from '@squidcloud/react-chat-widget';
|
|
66
|
+
|
|
67
|
+
// Inline
|
|
68
|
+
<SquidChatWidgetEntryPoint
|
|
69
|
+
squidAppId="YOUR_APP_ID"
|
|
70
|
+
squidRegion="us-east-1.aws"
|
|
71
|
+
squidAiAgentId="YOUR_AGENT_ID"
|
|
72
|
+
headerTitle="Chat Support"
|
|
73
|
+
/>
|
|
74
|
+
|
|
75
|
+
// FAB
|
|
76
|
+
<SquidChatWidgetWithFabButtonEntryPoint
|
|
77
|
+
squidAppId="YOUR_APP_ID"
|
|
78
|
+
squidRegion="us-east-1.aws"
|
|
79
|
+
squidAiAgentId="YOUR_AGENT_ID"
|
|
80
|
+
headerTitle="Chat Support"
|
|
81
|
+
/>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Both entry points wrap the widget in a `SquidContextProvider` automatically -- you do NOT need to provide one yourself.
|
|
85
|
+
|
|
86
|
+
## Three Operation Modes
|
|
87
|
+
|
|
88
|
+
The widget supports three mutually exclusive modes:
|
|
89
|
+
|
|
90
|
+
### 1. Agent Mode (default)
|
|
91
|
+
Connects to a Squid AI agent. Set `squid-ai-agent-id` to the agent ID.
|
|
92
|
+
|
|
93
|
+
### 2. AI Query Mode
|
|
94
|
+
Natural language queries against a database integration. Set `squid-ai-query="true"` and `squid-ai-integration-id` to the database integration ID.
|
|
95
|
+
|
|
96
|
+
### 3. Custom API / Webhook Mode
|
|
97
|
+
Send prompts to your own backend endpoint. Set `squid-ai-custom-api-url` to your webhook URL. When this is set, `squid-app-id` and `squid-region` are still required for the Squid context, but the agent ID is not needed.
|
|
98
|
+
|
|
99
|
+
**Priority order in code:**
|
|
100
|
+
1. If `squidAiQuery` is true → uses `useAiQuery` hook
|
|
101
|
+
2. Else if `squidAiCustomApiUrl` is set → uses `useAskWithApi` hook
|
|
102
|
+
3. Else → uses `useAiAgent` hook with `squidAiAgentId`
|
|
103
|
+
|
|
104
|
+
## Required & Optional Attributes
|
|
105
|
+
|
|
106
|
+
### Required (for Agent / AI Query modes)
|
|
107
|
+
|
|
108
|
+
| HTML Attribute | React Prop | Type | Description |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `squid-app-id` | `squidAppId` | string | Squid application ID |
|
|
111
|
+
| `squid-region` | `squidRegion` | SquidRegion | Region (e.g., `us-east-1.aws`) |
|
|
112
|
+
| `squid-ai-agent-id` | `squidAiAgentId` | string | AI Agent ID (agent mode) |
|
|
113
|
+
| `header-title` | `headerTitle` | string | Widget header text (default: `'SquidAI Chat'`) |
|
|
114
|
+
|
|
115
|
+
### Squid Cloud Configuration
|
|
116
|
+
|
|
117
|
+
| HTML Attribute | React Prop | Type | Default | Description |
|
|
118
|
+
|---|---|---|---|---|
|
|
119
|
+
| `squid-environment-id` | `squidEnvironmentId` | EnvironmentId | `'prod'` | Environment: `'prod'`, `'dev'` |
|
|
120
|
+
| `squid-developer-id` | `squidDeveloperId` | SquidDeveloperId | - | Developer ID for multi-tenant apps |
|
|
121
|
+
| `squid-api-key` | `squidApiKey` | string | - | API key for authentication |
|
|
122
|
+
| `squid-ai-integration-id` | `squidAiIntegrationId` | string | `'ai_agents'` | Integration ID for AI services |
|
|
123
|
+
|
|
124
|
+
### AI Model & Behavior
|
|
125
|
+
|
|
126
|
+
| HTML Attribute | React Prop | Type | Default | Description |
|
|
127
|
+
|---|---|---|---|---|
|
|
128
|
+
| `squid-ai-override-model` | `squidAiOverrideModel` | AiChatModelName | - | Override the default LLM model |
|
|
129
|
+
| `squid-ai-temperature` | `squidAiTemperature` | number | - | Model temperature (0-1) |
|
|
130
|
+
| `squid-ai-max-tokens` | `squidAiMaxTokens` | number | - | Max tokens in response |
|
|
131
|
+
| `squid-ai-instructions` | `squidAiInstructions` | string | - | Additional instructions (appended to agent instructions) |
|
|
132
|
+
| `squid-ai-context-metadata-filter` | `squidAiContextMetadataFilter` | AiContextMetadataFilter | - | Filter knowledge base context by metadata |
|
|
133
|
+
| `squid-ai-enable-raw-results` | `squidAiEnableRawResults` | boolean | - | Return raw results from AI |
|
|
134
|
+
| `squid-ai-enable-code-interpreter` | `squidAiEnableCodeInterpreter` | boolean | - | Enable code execution in AI response |
|
|
135
|
+
|
|
136
|
+
### Functions & Connected Agents
|
|
137
|
+
|
|
138
|
+
| HTML Attribute | React Prop | Type | Description |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| `squid-ai-functions` | `squidAiFunctions` | string | Comma-separated `@aiFunction` names the agent may call |
|
|
141
|
+
| `squid-ai-functions-json` | `squidAiFunctionsJson` | Array\<FunctionName\> | JSON array of function names (alternative to CSV) |
|
|
142
|
+
| `squid-ai-connected-agents` | `squidAiConnectedAgents` | Array\<AiConnectedAgentMetadata\> | Connected agents for multi-agent delegation |
|
|
143
|
+
|
|
144
|
+
### UI & Display
|
|
145
|
+
|
|
146
|
+
| HTML Attribute | React Prop | Type | Default | Description |
|
|
147
|
+
|---|---|---|---|---|
|
|
148
|
+
| `intro-text` | `introText` | string | - | Welcome message shown before first interaction |
|
|
149
|
+
| `avatar-image-url` | `avatarImageUrl` | string | - | Chat avatar image URL |
|
|
150
|
+
| `chat-icon-url` | `chatIconUrl` | string | - | FAB button icon URL |
|
|
151
|
+
| `widget-width` | `widgetWidth` | string | - | Widget width (CSS units) |
|
|
152
|
+
| `widget-height` | `widgetHeight` | string | - | Widget height (CSS units) |
|
|
153
|
+
| `theme` | `theme` | `'light'` \| `'dark'` | `'light'` | Color theme |
|
|
154
|
+
| `rtl-mode` | `rtlMode` | boolean | - | Right-to-left layout for Hebrew, Arabic |
|
|
155
|
+
| `powered-by-text` | `poweredByText` | string | - | Custom "powered by" text (replaces Squid branding) |
|
|
156
|
+
| `base-stylesheet-url` | `baseStylesheetUrl` | string | `'https://widget.squid.cloud/style.css'` | Base CSS URL |
|
|
157
|
+
| `stylesheet-url` | `stylesheetUrl` | string | - | Additional CSS URL for custom styling |
|
|
158
|
+
|
|
159
|
+
### Feature Toggles
|
|
160
|
+
|
|
161
|
+
| HTML Attribute | React Prop | Type | Default | Description |
|
|
162
|
+
|---|---|---|---|---|
|
|
163
|
+
| `enable-transcription` | `enableTranscription` | boolean | false | Enable voice-to-text (agent mode only) |
|
|
164
|
+
| `include-reference` | `includeReference` | boolean | false | Include source references in responses |
|
|
165
|
+
| `disable-history` | `disableHistory` | boolean | false | Disable chat history persistence (sets memoryMode to `'none'`) |
|
|
166
|
+
| `observe-status` | `observeStatus` | boolean | false | Emit status updates during processing |
|
|
167
|
+
| `chain-of-thought` | `chainOfThought` | boolean | false | Show AI reasoning process (requires `observe-status`) |
|
|
168
|
+
| `show-status-tags` | `showStatusTags` | boolean | false | Display JSON tags in chain-of-thought entries |
|
|
169
|
+
| `enable-debug-logs` | `enableDebugLogs` | boolean | false | Enable debug logging to console |
|
|
170
|
+
|
|
171
|
+
## Agent Chat Options & Context
|
|
172
|
+
|
|
173
|
+
The `squid-ai-agent-chat-options` attribute accepts a JSON object of type `AllAiAgentChatOptions` for advanced agent configuration:
|
|
174
|
+
|
|
175
|
+
```html
|
|
176
|
+
<squid-chat-widget
|
|
177
|
+
squid-ai-agent-chat-options='{
|
|
178
|
+
"agentContext": { "userId": "user-123", "projectId": "proj-456" },
|
|
179
|
+
"instructions": "Always respond in formal English.",
|
|
180
|
+
"memoryOptions": {
|
|
181
|
+
"memoryMode": "read-write",
|
|
182
|
+
"memoryId": "custom-session-id",
|
|
183
|
+
"expirationMinutes": 1440
|
|
184
|
+
},
|
|
185
|
+
"contextMetadataFilterForKnowledgeBase": {
|
|
186
|
+
"kb-id": { "category": "documentation" }
|
|
187
|
+
}
|
|
188
|
+
}'
|
|
189
|
+
...
|
|
190
|
+
></squid-chat-widget>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### agentContext
|
|
194
|
+
|
|
195
|
+
The `agentContext` object is passed to your backend and is accessible in `@aiFunction` methods via the `AiFunctionCallContext`:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Widget configuration
|
|
199
|
+
squid-ai-agent-chat-options='{ "agentContext": { "userId": "u123", "role": "admin" } }'
|
|
200
|
+
|
|
201
|
+
// Backend @aiFunction
|
|
202
|
+
@aiFunction('Gets user data', [
|
|
203
|
+
{ name: 'query', type: 'string', required: true, description: 'Query' }
|
|
204
|
+
])
|
|
205
|
+
async getUserData(
|
|
206
|
+
params: { query: string },
|
|
207
|
+
context: AiFunctionCallContext
|
|
208
|
+
): Promise<string> {
|
|
209
|
+
const userId = context.agentContext?.userId; // "u123"
|
|
210
|
+
const role = context.agentContext?.role; // "admin"
|
|
211
|
+
// Use context to scope data access
|
|
212
|
+
return await fetchDataForUser(userId, query);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### instructions
|
|
217
|
+
|
|
218
|
+
The `instructions` field **appends** to the agent's console-defined instructions. It does not replace them.
|
|
219
|
+
|
|
220
|
+
### memoryOptions
|
|
221
|
+
|
|
222
|
+
Controls chat history persistence:
|
|
223
|
+
- `memoryMode: 'read-write'` (default) - saves and reads history
|
|
224
|
+
- `memoryMode: 'read-only'` - reads history but doesn't save new messages
|
|
225
|
+
- `memoryMode: 'none'` - no history
|
|
226
|
+
- `memoryId` - unique ID per user/session for history isolation
|
|
227
|
+
- `expirationMinutes` - auto-expire history
|
|
228
|
+
|
|
229
|
+
## Custom API / Webhook Mode
|
|
230
|
+
|
|
231
|
+
Use `squid-ai-custom-api-url` to intercept user prompts and handle them with your own backend logic.
|
|
232
|
+
|
|
233
|
+
### Widget Configuration
|
|
234
|
+
|
|
235
|
+
```html
|
|
236
|
+
<squid-chat-widget
|
|
237
|
+
squid-app-id="YOUR_APP_ID"
|
|
238
|
+
squid-region="us-east-1.aws"
|
|
239
|
+
squid-ai-custom-api-url="https://YOUR_APP_URL/webhooks/chat"
|
|
240
|
+
squid-ai-custom-api-headers='{ "x-api-key": "secret123" }'
|
|
241
|
+
header-title="Custom Chat"
|
|
242
|
+
></squid-chat-widget>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
When using a Squid backend webhook, you can get the webhook URL from the Squid client SDK:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const webhookUrl = squid.getWebhookUrl('chat');
|
|
249
|
+
// Use this URL as squid-ai-custom-api-url
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Backend Webhook Handler
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { SquidService, webhook, WebhookRequest } from '@squidcloud/backend';
|
|
256
|
+
|
|
257
|
+
interface ChatRequest {
|
|
258
|
+
prompt: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
interface ChatResponse {
|
|
262
|
+
response: string;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export class ChatService extends SquidService {
|
|
266
|
+
@webhook('chat')
|
|
267
|
+
async handleChat(request: WebhookRequest<ChatRequest>): Promise<ChatResponse> {
|
|
268
|
+
const { prompt } = request.body;
|
|
269
|
+
const sessionId = request.headers['squid-session-id']; // Auto-injected by widget
|
|
270
|
+
const customHeaders = request.headers; // Includes squid-ai-custom-api-headers
|
|
271
|
+
|
|
272
|
+
// Option 1: Process with your own logic
|
|
273
|
+
const result = await processPrompt(prompt);
|
|
274
|
+
return { response: result };
|
|
275
|
+
|
|
276
|
+
// Option 2: Forward to an agent with custom preprocessing
|
|
277
|
+
const agent = this.squid.ai().agent('my-agent');
|
|
278
|
+
const response = await agent.ask(prompt, {
|
|
279
|
+
agentContext: { sessionId },
|
|
280
|
+
functions: ['myFunction']
|
|
281
|
+
});
|
|
282
|
+
return { response };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Session Tracking
|
|
288
|
+
|
|
289
|
+
The widget automatically generates a unique `sessionId` per widget instance and sends it as the `squid-session-id` header with every request. This allows your webhook to maintain per-session state.
|
|
290
|
+
|
|
291
|
+
Any custom headers set via `squid-ai-custom-api-headers` are also included in every request.
|
|
292
|
+
|
|
293
|
+
### Query Parameters
|
|
294
|
+
|
|
295
|
+
The webhook also receives query parameters from the request URL. Access them via `request.queryParams`.
|
|
296
|
+
|
|
297
|
+
## AI Query Mode
|
|
298
|
+
|
|
299
|
+
Use AI Query mode to let users query a database using natural language.
|
|
300
|
+
|
|
301
|
+
```html
|
|
302
|
+
<squid-chat-widget
|
|
303
|
+
squid-app-id="YOUR_APP_ID"
|
|
304
|
+
squid-region="us-east-1.aws"
|
|
305
|
+
squid-environment-id="prod"
|
|
306
|
+
squid-ai-query="true"
|
|
307
|
+
squid-ai-integration-id="built_in_db"
|
|
308
|
+
header-title="Data Explorer"
|
|
309
|
+
></squid-chat-widget>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### AI Query Options
|
|
313
|
+
|
|
314
|
+
For advanced control, use `squid-ai-query-options` (JSON string):
|
|
315
|
+
|
|
316
|
+
```html
|
|
317
|
+
<squid-chat-widget
|
|
318
|
+
squid-ai-query="true"
|
|
319
|
+
squid-ai-integration-id="built_in_db"
|
|
320
|
+
squid-ai-query-options='{
|
|
321
|
+
"enableRawResults": true,
|
|
322
|
+
"analyzeResultsOptions": { "enableCodeInterpreter": true },
|
|
323
|
+
"memoryOptions": { "memoryMode": "read-write" },
|
|
324
|
+
"selectCollectionsOptions": { "collectionsToUse": ["users", "orders"] },
|
|
325
|
+
"generateQueryOptions": { "maxErrorCorrections": 3 }
|
|
326
|
+
}'
|
|
327
|
+
...
|
|
328
|
+
></squid-chat-widget>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
If `squid-ai-query-options` is provided, it takes precedence over individual props like `squid-ai-enable-raw-results` and `squid-ai-enable-code-interpreter`.
|
|
332
|
+
|
|
333
|
+
**Note:** In AI Query mode, voice transcription is not available.
|
|
334
|
+
|
|
335
|
+
## Session Management
|
|
336
|
+
|
|
337
|
+
### Automatic Memory
|
|
338
|
+
|
|
339
|
+
By default, the widget generates a unique `memoryId` (UUID) on mount. All messages in that session share this ID for conversation context.
|
|
340
|
+
|
|
341
|
+
- To **disable history**: set `disable-history="true"` (sets `memoryMode: 'none'`)
|
|
342
|
+
- To **use a custom session ID**: pass it via `squid-ai-agent-chat-options` → `memoryOptions.memoryId`
|
|
343
|
+
- To **expire history**: set `memoryOptions.expirationMinutes`
|
|
344
|
+
|
|
345
|
+
### Session ID for Custom APIs
|
|
346
|
+
|
|
347
|
+
The widget generates a short `sessionId` on mount and sends it as `squid-session-id` header with every custom API request. This is separate from the memory ID used for agent conversation history.
|
|
348
|
+
|
|
349
|
+
## Authentication & Access Control
|
|
350
|
+
|
|
351
|
+
### Public Agents
|
|
352
|
+
|
|
353
|
+
Toggle in Agent Studio > Agent Settings. Public agents bypass `@secureAiAgent` rules but auth credentials are still available in backend functions.
|
|
354
|
+
|
|
355
|
+
### Private Agents (Auth Required)
|
|
356
|
+
|
|
357
|
+
Pass an auth provider via `squid-auth-provider`:
|
|
358
|
+
|
|
359
|
+
```html
|
|
360
|
+
<squid-chat-widget
|
|
361
|
+
squid-auth-provider='{ "integrationId": "AUTH_INTEGRATION_ID", "token": "AUTH_TOKEN" }'
|
|
362
|
+
...
|
|
363
|
+
></squid-chat-widget>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
// React
|
|
368
|
+
<SquidChatWidgetEntryPoint
|
|
369
|
+
squidAuthProvider={{ integrationId: "auth0", token: authToken }}
|
|
370
|
+
...
|
|
371
|
+
/>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
The widget calls `squid.setAuthProvider()` internally with the provided `integrationId` and token.
|
|
375
|
+
|
|
376
|
+
### Backend Security
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
@secureAiAgent('my-agent-id')
|
|
380
|
+
allowAccessToAgent(): boolean {
|
|
381
|
+
return this.isAuthenticated();
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Auth credentials are also accessible inside `@aiFunction` methods via `this.getUserAuth()`.
|
|
386
|
+
|
|
387
|
+
## Publishing Status Updates (Chain of Thought)
|
|
388
|
+
|
|
389
|
+
To show the AI's reasoning process in the widget, enable chain-of-thought display:
|
|
390
|
+
|
|
391
|
+
```html
|
|
392
|
+
<squid-chat-widget
|
|
393
|
+
observe-status="true"
|
|
394
|
+
chain-of-thought="true"
|
|
395
|
+
show-status-tags="true"
|
|
396
|
+
...
|
|
397
|
+
></squid-chat-widget>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### How It Works
|
|
401
|
+
|
|
402
|
+
1. Enable `observe-status` to subscribe to status updates from the agent
|
|
403
|
+
2. Enable `chain-of-thought` to render those updates in the UI
|
|
404
|
+
3. Optionally enable `show-status-tags` to display JSON metadata tags
|
|
405
|
+
|
|
406
|
+
### Status Update Structure
|
|
407
|
+
|
|
408
|
+
Each status update contains:
|
|
409
|
+
- `messageId` - unique ID
|
|
410
|
+
- `title` - display text (shown in the chain-of-thought UI)
|
|
411
|
+
- `tags` - metadata object (shown as JSON when `show-status-tags` is enabled)
|
|
412
|
+
- `body` - markdown content (rendered below the title)
|
|
413
|
+
- `parentStatusUpdateId` - for nested status updates (creates tree structure)
|
|
414
|
+
- `duration` - processing time in milliseconds
|
|
415
|
+
|
|
416
|
+
### Publishing Status Updates from Backend
|
|
417
|
+
|
|
418
|
+
Use the agent's status update mechanism to publish updates that appear in the widget:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// In your @aiFunction or backend code
|
|
422
|
+
// Status updates are published through the agent's observeStatusUpdates() stream
|
|
423
|
+
// The widget subscribes to this stream when observe-status="true"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Nested Status Updates
|
|
427
|
+
|
|
428
|
+
Status updates support parent-child relationships via `parentStatusUpdateId`. The widget renders these as an expandable tree structure, with each parent showing its duration and collapsible children.
|
|
429
|
+
|
|
430
|
+
### Timing Display
|
|
431
|
+
|
|
432
|
+
When chain-of-thought is enabled and processing completes, the widget shows a "Thought for X seconds" summary. Each parent status update also shows its individual duration.
|
|
433
|
+
|
|
434
|
+
## Events & Callbacks
|
|
435
|
+
|
|
436
|
+
### onChange Event
|
|
437
|
+
|
|
438
|
+
Listen for chat history and status changes:
|
|
439
|
+
|
|
440
|
+
```html
|
|
441
|
+
<!-- HTML: via DOM event -->
|
|
442
|
+
<squid-chat-widget id="chat" ...></squid-chat-widget>
|
|
443
|
+
<script>
|
|
444
|
+
document.getElementById('chat').addEventListener('change', (event) => {
|
|
445
|
+
const { type } = event.detail;
|
|
446
|
+
if (type === 'history') {
|
|
447
|
+
console.log('Messages:', event.detail.history);
|
|
448
|
+
}
|
|
449
|
+
if (type === 'status') {
|
|
450
|
+
console.log('Status updates:', event.detail.status);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
</script>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
```tsx
|
|
457
|
+
// React
|
|
458
|
+
<SquidChatWidgetEntryPoint
|
|
459
|
+
onChange={(event: ChatChangeEvent) => {
|
|
460
|
+
if (event.detail.type === 'history') {
|
|
461
|
+
const messages: ChatMessage[] = event.detail.history;
|
|
462
|
+
// Each message: { id, type: 'user'|'ai', message: string, jobId }
|
|
463
|
+
}
|
|
464
|
+
if (event.detail.type === 'status') {
|
|
465
|
+
const updates: AiStatusMessage[] = event.detail.status;
|
|
466
|
+
}
|
|
467
|
+
}}
|
|
468
|
+
...
|
|
469
|
+
/>
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**History events** fire when a user sends a message and when the AI response completes.
|
|
473
|
+
**Status events** fire during processing when `observe-status` is enabled.
|
|
474
|
+
|
|
475
|
+
### Event Types
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
interface HistoryChangeEvent extends CustomEvent {
|
|
479
|
+
detail: { type: 'history'; history: ChatMessage[] };
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
interface StatusChangeEvent extends CustomEvent {
|
|
483
|
+
detail: { type: 'status'; status: AiStatusMessage[] };
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
type ChatChangeEvent = HistoryChangeEvent | StatusChangeEvent;
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Styling & Theming
|
|
490
|
+
|
|
491
|
+
### Themes
|
|
492
|
+
|
|
493
|
+
Two built-in themes: `theme="light"` (default) and `theme="dark"`.
|
|
494
|
+
|
|
495
|
+
### CSS Variables
|
|
496
|
+
|
|
497
|
+
Override any aspect of the widget via CSS custom properties on the element:
|
|
498
|
+
|
|
499
|
+
```css
|
|
500
|
+
squid-chat-widget {
|
|
501
|
+
/* Header */
|
|
502
|
+
--squid-widget-header-background-color: #1a1a2e;
|
|
503
|
+
--squid-widget-header-title-color: #ffffff;
|
|
504
|
+
--squid-widget-header-menu-button-background-color: rgba(255,255,255,0.1);
|
|
505
|
+
--squid-widget-header-menu-button-icon-url: url('/custom-menu.svg');
|
|
506
|
+
--squid-widget-header-menu-item-color: #333;
|
|
507
|
+
--squid-widget-header-menu-item-hover-background-color: #f0f0f0;
|
|
508
|
+
|
|
509
|
+
/* Body */
|
|
510
|
+
--squid-widget-body-background-color: #f8f9fc;
|
|
511
|
+
--squid-widget-ai-message-background-color: #ffffff;
|
|
512
|
+
--squid-widget-user-message-background-color: #188fff;
|
|
513
|
+
--squid-widget-user-message-color: #ffffff;
|
|
514
|
+
--squid-widget-avatar-image-url: url('/avatar.png');
|
|
515
|
+
|
|
516
|
+
/* Input area */
|
|
517
|
+
--squid-widget-textarea-background-color: #ffffff;
|
|
518
|
+
--squid-widget-textarea-border-color: #e0e0e0;
|
|
519
|
+
--squid-widget-textarea-text-color: #333;
|
|
520
|
+
--squid-widget-textarea-submit-image-url: url('/send.svg');
|
|
521
|
+
|
|
522
|
+
/* Code & links */
|
|
523
|
+
--squid-widget-inline-code-background-color: #f5f5f5;
|
|
524
|
+
--squid-widget-inline-code-border-color: #e0e0e0;
|
|
525
|
+
--squid-widget-link-color: #188fff;
|
|
526
|
+
|
|
527
|
+
/* Footer */
|
|
528
|
+
--squid-widget-powered-by-color: #888;
|
|
529
|
+
|
|
530
|
+
/* FAB button */
|
|
531
|
+
--squid-widget-fab-background-color: #188fff;
|
|
532
|
+
--squid-widget-fab-image-url: url('/chat-icon.svg');
|
|
533
|
+
--squid-widget-fab-close-image-url: url('/close.svg');
|
|
534
|
+
|
|
535
|
+
/* Dimensions */
|
|
536
|
+
--widget-width: 400px;
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Custom Stylesheet
|
|
541
|
+
|
|
542
|
+
For deeper customization, provide an additional CSS file:
|
|
543
|
+
|
|
544
|
+
```html
|
|
545
|
+
<squid-chat-widget
|
|
546
|
+
stylesheet-url="https://example.com/custom-widget.css"
|
|
547
|
+
...
|
|
548
|
+
></squid-chat-widget>
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
The base stylesheet loads first, then the custom stylesheet overlays it.
|
|
552
|
+
|
|
553
|
+
## Localization
|
|
554
|
+
|
|
555
|
+
Customize all UI text for internationalization:
|
|
556
|
+
|
|
557
|
+
| HTML Attribute | React Prop | Default | Description |
|
|
558
|
+
|---|---|---|---|
|
|
559
|
+
| `text-placeholder` | `textPlaceholder` | `'Type here and press enter...'` | Input placeholder |
|
|
560
|
+
| `text-thinking` | `textThinking` | `'Thinking...'` | Loading state text |
|
|
561
|
+
| `text-thought-for` | `textThoughtFor` | `'Thought for'` | Chain-of-thought label |
|
|
562
|
+
| `text-suggested-prompts` | `textSuggestedPrompts` | `'Suggested Prompts'` | Suggested prompts title |
|
|
563
|
+
| `text-suggested-prompts-description` | `textSuggestedPromptsDescription` | `'Explore what this agent can do with a few examples.'` | Suggested prompts description |
|
|
564
|
+
| `text-milliseconds` | `textMilliseconds` | `'milliseconds'` | Time unit |
|
|
565
|
+
| `text-seconds` | `textSeconds` | `'seconds'` | Time unit |
|
|
566
|
+
| `text-minutes` | `textMinutes` | `'minutes'` | Time unit |
|
|
567
|
+
|
|
568
|
+
### RTL Support
|
|
569
|
+
|
|
570
|
+
```html
|
|
571
|
+
<squid-chat-widget rtl-mode="true" ...></squid-chat-widget>
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## Menu Items (Slots)
|
|
575
|
+
|
|
576
|
+
Add custom content pages to the widget via dropdown menu items:
|
|
577
|
+
|
|
578
|
+
```html
|
|
579
|
+
<squid-chat-widget
|
|
580
|
+
menu-items-json='[
|
|
581
|
+
{ "title": "Documentation", "slotName": "docs" },
|
|
582
|
+
{ "title": "FAQ", "slotName": "faq" }
|
|
583
|
+
]'
|
|
584
|
+
...
|
|
585
|
+
>
|
|
586
|
+
<div slot="docs">
|
|
587
|
+
<h2>Documentation</h2>
|
|
588
|
+
<p>Your docs content here.</p>
|
|
589
|
+
</div>
|
|
590
|
+
<div slot="faq">
|
|
591
|
+
<h2>FAQ</h2>
|
|
592
|
+
<p>Frequently asked questions...</p>
|
|
593
|
+
</div>
|
|
594
|
+
</squid-chat-widget>
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
// React
|
|
599
|
+
<SquidChatWidgetEntryPoint
|
|
600
|
+
menuItemsJson={[
|
|
601
|
+
{ title: "Documentation", slotName: "docs" },
|
|
602
|
+
{ title: "FAQ", slotName: "faq" }
|
|
603
|
+
]}
|
|
604
|
+
...
|
|
605
|
+
>
|
|
606
|
+
<div slot="docs"><h2>Documentation</h2></div>
|
|
607
|
+
<div slot="faq"><h2>FAQ</h2></div>
|
|
608
|
+
</SquidChatWidgetEntryPoint>
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Programmatic Navigation
|
|
612
|
+
|
|
613
|
+
To navigate back to chat from slot content:
|
|
614
|
+
|
|
615
|
+
```javascript
|
|
616
|
+
const widget = document.querySelector('squid-chat-widget');
|
|
617
|
+
widget.backToChat(); // Returns to the main chat view
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
## Suggested Prompts
|
|
621
|
+
|
|
622
|
+
Show predefined questions to guide users:
|
|
623
|
+
|
|
624
|
+
```html
|
|
625
|
+
<squid-chat-widget
|
|
626
|
+
predefined-prompts='["How do I reset my password?", "What are your business hours?", "Show me pricing"]'
|
|
627
|
+
...
|
|
628
|
+
></squid-chat-widget>
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
Prompts appear in two places:
|
|
632
|
+
1. Below the intro message (on initial load, before any user messages)
|
|
633
|
+
2. In a dropdown menu accessible from the header (always available)
|
|
634
|
+
|
|
635
|
+
Clicking a prompt auto-submits it as a user message.
|
|
636
|
+
|
|
637
|
+
## Voice Transcription
|
|
638
|
+
|
|
639
|
+
Enable microphone input for voice-to-text:
|
|
640
|
+
|
|
641
|
+
```html
|
|
642
|
+
<squid-chat-widget
|
|
643
|
+
enable-transcription="true"
|
|
644
|
+
...
|
|
645
|
+
></squid-chat-widget>
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
- Only available in **agent mode** (not AI Query mode)
|
|
649
|
+
- Uses browser's `MediaRecorder` API to capture audio as WAV
|
|
650
|
+
- Audio is sent to Squid's transcription service, then the transcribed text is submitted as a chat message
|
|
651
|
+
- The microphone button appears when the text input is empty; it's replaced by the submit button when text is typed
|
|
652
|
+
|
|
653
|
+
## Error Formatting
|
|
654
|
+
|
|
655
|
+
Control how errors are displayed to users:
|
|
656
|
+
|
|
657
|
+
```html
|
|
658
|
+
<!-- Show generic message for all errors -->
|
|
659
|
+
<squid-chat-widget error-formatter="generic-error" ...></squid-chat-widget>
|
|
660
|
+
|
|
661
|
+
<!-- Show detailed error (default) -->
|
|
662
|
+
<squid-chat-widget error-formatter="original-error" ...></squid-chat-widget>
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
```tsx
|
|
666
|
+
// React: custom error formatter function
|
|
667
|
+
<SquidChatWidgetEntryPoint
|
|
668
|
+
errorFormatter={(error: unknown) => `Something went wrong: ${getMessageFromError(error)}`}
|
|
669
|
+
...
|
|
670
|
+
/>
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Built-in options:
|
|
674
|
+
- `'generic-error'` - "Oops, something went wrong with your request. Please try again."
|
|
675
|
+
- `'original-error'` (default) - Shows error details from the server
|
|
676
|
+
|
|
677
|
+
## FAB (Floating Action Button) Mode
|
|
678
|
+
|
|
679
|
+
The `<squid-chat-widget-with-fab-button>` variant renders as a floating button in the bottom-right corner that toggles the chat panel.
|
|
680
|
+
|
|
681
|
+
```html
|
|
682
|
+
<squid-chat-widget-with-fab-button
|
|
683
|
+
open-on-load="true"
|
|
684
|
+
use-maximize-button="true"
|
|
685
|
+
...
|
|
686
|
+
></squid-chat-widget-with-fab-button>
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
| Attribute | React Prop | Type | Description |
|
|
690
|
+
|---|---|---|---|
|
|
691
|
+
| `open-on-load` | `openOnLoad` | boolean | Widget opens automatically on page load |
|
|
692
|
+
| `use-maximize-button` | `useMaximizeButton` | boolean | Show maximize/minimize button |
|
|
693
|
+
|
|
694
|
+
### Maximize/Minimize (React controlled)
|
|
695
|
+
|
|
696
|
+
```tsx
|
|
697
|
+
const [isMaximized, setIsMaximized] = useState(false);
|
|
698
|
+
|
|
699
|
+
<SquidChatWidgetWithFabButtonEntryPoint
|
|
700
|
+
useMaximizeButton={true}
|
|
701
|
+
isMaximized={isMaximized}
|
|
702
|
+
onMaximizedChange={setIsMaximized}
|
|
703
|
+
...
|
|
704
|
+
/>
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
## Framework Integration
|
|
708
|
+
|
|
709
|
+
### React
|
|
710
|
+
|
|
711
|
+
Works out of the box with the React entry point components. No extra setup needed.
|
|
712
|
+
|
|
713
|
+
### Angular
|
|
714
|
+
|
|
715
|
+
Add `CUSTOM_ELEMENTS_SCHEMA` to your NgModule to use the web component:
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
719
|
+
|
|
720
|
+
@NgModule({
|
|
721
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
722
|
+
// ...
|
|
723
|
+
})
|
|
724
|
+
export class AppModule {}
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
Then use the HTML custom element in templates:
|
|
728
|
+
|
|
729
|
+
```html
|
|
730
|
+
<squid-chat-widget
|
|
731
|
+
squid-app-id="YOUR_APP_ID"
|
|
732
|
+
squid-region="us-east-1.aws"
|
|
733
|
+
squid-ai-agent-id="YOUR_AGENT_ID"
|
|
734
|
+
header-title="Chat"
|
|
735
|
+
></squid-chat-widget>
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### TypeScript Declaration (React)
|
|
739
|
+
|
|
740
|
+
If TypeScript complains about the custom elements, add a declaration file:
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
// declarations.d.ts
|
|
744
|
+
declare namespace JSX {
|
|
745
|
+
interface IntrinsicElements {
|
|
746
|
+
'squid-chat-widget': any;
|
|
747
|
+
'squid-chat-widget-with-fab-button': any;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
## Complete Example
|
|
753
|
+
|
|
754
|
+
### Full-featured agent chat with all options
|
|
755
|
+
|
|
756
|
+
```html
|
|
757
|
+
<squid-chat-widget-with-fab-button
|
|
758
|
+
squid-app-id="my-app"
|
|
759
|
+
squid-region="us-east-1.aws"
|
|
760
|
+
squid-environment-id="prod"
|
|
761
|
+
squid-developer-id="dev-123"
|
|
762
|
+
squid-ai-agent-id="support-agent"
|
|
763
|
+
squid-ai-instructions="Be concise and professional."
|
|
764
|
+
squid-ai-functions="getOrderStatus,lookupAccount"
|
|
765
|
+
squid-ai-connected-agents='[{"agentId":"billing-agent","description":"Handles billing questions"}]'
|
|
766
|
+
squid-ai-override-model="gpt-5-mini"
|
|
767
|
+
squid-ai-temperature="0.7"
|
|
768
|
+
squid-ai-max-tokens="2000"
|
|
769
|
+
squid-ai-agent-chat-options='{
|
|
770
|
+
"agentContext": { "userId": "user-123" },
|
|
771
|
+
"memoryOptions": { "memoryMode": "read-write", "expirationMinutes": 60 }
|
|
772
|
+
}'
|
|
773
|
+
header-title="Customer Support"
|
|
774
|
+
intro-text="Hi! How can I help you today?"
|
|
775
|
+
predefined-prompts='["Track my order", "Billing question", "Technical support"]'
|
|
776
|
+
theme="dark"
|
|
777
|
+
rtl-mode="false"
|
|
778
|
+
observe-status="true"
|
|
779
|
+
chain-of-thought="true"
|
|
780
|
+
show-status-tags="false"
|
|
781
|
+
include-reference="true"
|
|
782
|
+
enable-transcription="true"
|
|
783
|
+
open-on-load="false"
|
|
784
|
+
use-maximize-button="true"
|
|
785
|
+
error-formatter="original-error"
|
|
786
|
+
text-placeholder="Ask me anything..."
|
|
787
|
+
text-thinking="Processing..."
|
|
788
|
+
powered-by-text="Powered by Acme Corp"
|
|
789
|
+
squid-auth-provider='{"integrationId":"auth0","token":"eyJ..."}'
|
|
790
|
+
menu-items-json='[{"title":"Help Center","slotName":"help"}]'
|
|
791
|
+
>
|
|
792
|
+
<div slot="help"><h2>Help Center</h2><p>Contact us at support@example.com</p></div>
|
|
793
|
+
</squid-chat-widget-with-fab-button>
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
## Real-World Patterns
|
|
797
|
+
|
|
798
|
+
### Pattern 1: AI Query with Predefined SQL Prompts
|
|
799
|
+
|
|
800
|
+
Use the widget as a natural language database explorer with predefined queries:
|
|
801
|
+
|
|
802
|
+
```tsx
|
|
803
|
+
// Frontend component
|
|
804
|
+
function DataExplorer() {
|
|
805
|
+
const squid = useSquid();
|
|
806
|
+
const memoryId = useMemo(() => generateUUID(), []);
|
|
807
|
+
|
|
808
|
+
const aiQueryOptions: AiQueryOptions = {
|
|
809
|
+
memoryOptions: { memoryMode: 'read-write', memoryId },
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
return (
|
|
813
|
+
<squid-chat-widget
|
|
814
|
+
squid-app-id={import.meta.env.VITE_SQUID_APP_ID}
|
|
815
|
+
squid-region={import.meta.env.VITE_SQUID_REGION}
|
|
816
|
+
squid-environment-id={import.meta.env.VITE_SQUID_ENVIRONMENT_ID}
|
|
817
|
+
squid-api-key={import.meta.env.VITE_SQUID_API_KEY}
|
|
818
|
+
squid-developer-id={import.meta.env.VITE_SQUID_DEVELOPER_ID}
|
|
819
|
+
squid-ai-query="true"
|
|
820
|
+
squid-ai-integration-id="my_database"
|
|
821
|
+
squid-ai-query-options={JSON.stringify(aiQueryOptions)}
|
|
822
|
+
header-title="Data Explorer"
|
|
823
|
+
intro-text="Ask questions about your data."
|
|
824
|
+
widget-width="820px"
|
|
825
|
+
chain-of-thought="true"
|
|
826
|
+
predefined-prompts={JSON.stringify([
|
|
827
|
+
'Show sample of 10 recent orders',
|
|
828
|
+
'What is the total revenue by month?',
|
|
829
|
+
'List top customers by order count'
|
|
830
|
+
])}
|
|
831
|
+
/>
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Pattern 2: Custom Webhook with Dynamic Instructions
|
|
837
|
+
|
|
838
|
+
Two-phase pattern where Phase 1 uses built-in AI Query and Phase 2 uses a custom webhook with file-based instructions:
|
|
839
|
+
|
|
840
|
+
```tsx
|
|
841
|
+
// Frontend - Phase 2: Custom webhook with uploaded instructions
|
|
842
|
+
function AdvancedQuery() {
|
|
843
|
+
const squid = useSquid();
|
|
844
|
+
const [webhookUrl, setWebhookUrl] = useState('');
|
|
845
|
+
|
|
846
|
+
useEffect(() => {
|
|
847
|
+
setWebhookUrl(squid.getWebhookUrl('my-custom-query'));
|
|
848
|
+
}, [squid]);
|
|
849
|
+
|
|
850
|
+
if (!webhookUrl) return null;
|
|
851
|
+
|
|
852
|
+
return (
|
|
853
|
+
<squid-chat-widget
|
|
854
|
+
squid-app-id={import.meta.env.VITE_SQUID_APP_ID}
|
|
855
|
+
squid-region={import.meta.env.VITE_SQUID_REGION}
|
|
856
|
+
squid-environment-id={import.meta.env.VITE_SQUID_ENVIRONMENT_ID}
|
|
857
|
+
squid-ai-custom-api-url={webhookUrl}
|
|
858
|
+
header-title="Advanced Query"
|
|
859
|
+
intro-text="Ask anything - I have access to custom instructions."
|
|
860
|
+
widget-width="820px"
|
|
861
|
+
chain-of-thought="true"
|
|
862
|
+
/>
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
```typescript
|
|
868
|
+
// Backend - Webhook handler with dynamic instructions from storage
|
|
869
|
+
import { SquidService, webhook, WebhookRequest } from '@squidcloud/backend';
|
|
870
|
+
|
|
871
|
+
interface QueryWebhookBody {
|
|
872
|
+
prompt: string;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
export class QueryService extends SquidService {
|
|
876
|
+
@webhook('my-custom-query')
|
|
877
|
+
async handleQuery(request: WebhookRequest<QueryWebhookBody>) {
|
|
878
|
+
const { prompt } = request.body;
|
|
879
|
+
const sessionId = request.headers['squid-session-id'];
|
|
880
|
+
|
|
881
|
+
// Load dynamic instructions from storage
|
|
882
|
+
const storage = this.squid.storage('default');
|
|
883
|
+
const files = await storage.listDirectoryContents('/instructions');
|
|
884
|
+
let instructions = '';
|
|
885
|
+
for (const file of files) {
|
|
886
|
+
const url = await storage.downloadUrl(file.path);
|
|
887
|
+
const content = await fetch(url).then(r => r.text());
|
|
888
|
+
instructions += content + '\n';
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// Execute AI query with dynamic instructions and session memory
|
|
892
|
+
const result = await this.squid.ai().executeAiQuery(
|
|
893
|
+
'my_database',
|
|
894
|
+
prompt,
|
|
895
|
+
{
|
|
896
|
+
instructions,
|
|
897
|
+
memoryOptions: { memoryMode: 'read-write', memoryId: sessionId },
|
|
898
|
+
}
|
|
899
|
+
);
|
|
900
|
+
|
|
901
|
+
return { response: result };
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
### Pattern 3: Authenticated Agent with AI Functions
|
|
907
|
+
|
|
908
|
+
Widget connected to a secured agent that calls backend functions with user context:
|
|
909
|
+
|
|
910
|
+
```tsx
|
|
911
|
+
// Frontend - Auth0-authenticated chat widget
|
|
912
|
+
function AuthenticatedChat() {
|
|
913
|
+
const { getAccessTokenSilently } = useAuth0();
|
|
914
|
+
const [authToken, setAuthToken] = useState<string>();
|
|
915
|
+
|
|
916
|
+
useEffect(() => {
|
|
917
|
+
getAccessTokenSilently().then(setAuthToken);
|
|
918
|
+
}, []);
|
|
919
|
+
|
|
920
|
+
if (!authToken) return null;
|
|
921
|
+
|
|
922
|
+
return (
|
|
923
|
+
<squid-chat-widget
|
|
924
|
+
squid-app-id={import.meta.env.VITE_SQUID_APP_ID}
|
|
925
|
+
squid-region={import.meta.env.VITE_SQUID_REGION}
|
|
926
|
+
squid-environment-id={import.meta.env.VITE_SQUID_ENVIRONMENT_ID}
|
|
927
|
+
squid-api-key={import.meta.env.VITE_SQUID_API_KEY}
|
|
928
|
+
squid-developer-id={import.meta.env.VITE_SQUID_DEVELOPER_ID}
|
|
929
|
+
squid-ai-agent-id="support-agent"
|
|
930
|
+
squid-auth-provider={JSON.stringify({
|
|
931
|
+
integrationId: 'auth0',
|
|
932
|
+
token: authToken,
|
|
933
|
+
})}
|
|
934
|
+
header-title="Support"
|
|
935
|
+
intro-text="How may I help you?"
|
|
936
|
+
widget-width="820px"
|
|
937
|
+
chain-of-thought="true"
|
|
938
|
+
/>
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
```typescript
|
|
944
|
+
// Backend - Secured agent with AI functions
|
|
945
|
+
export class SupportService extends SquidService {
|
|
946
|
+
private readonly agent = this.squid.ai().agent('support-agent');
|
|
947
|
+
|
|
948
|
+
@secureAiAgent('support-agent')
|
|
949
|
+
allowAccess(): boolean {
|
|
950
|
+
return this.isAuthenticated();
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
@aiFunction('Searches for customer or account by name', [
|
|
954
|
+
{ name: 'type', type: 'string', required: true, description: 'Entity type', enum: ['customer', 'account'] },
|
|
955
|
+
{ name: 'name', type: 'string', required: true, description: 'Search query' },
|
|
956
|
+
])
|
|
957
|
+
async searchEntity({ type, name }: { type: string; name: string }): Promise<string> {
|
|
958
|
+
const results = await this.squid.collection('entities')
|
|
959
|
+
.query()
|
|
960
|
+
.eq('type', type)
|
|
961
|
+
.like('name', `%${name}%`)
|
|
962
|
+
.snapshot();
|
|
963
|
+
return JSON.stringify(results);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
@aiFunction('Gets detailed customer data from database', [
|
|
967
|
+
{ name: 'customerName', type: 'string', required: true, description: 'Exact customer name' },
|
|
968
|
+
])
|
|
969
|
+
async getCustomerDetails({ customerName }: { customerName: string }): Promise<string> {
|
|
970
|
+
const customer = await this.squid.collection('customers')
|
|
971
|
+
.query()
|
|
972
|
+
.eq('name', customerName)
|
|
973
|
+
.snapshot();
|
|
974
|
+
return JSON.stringify(customer);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
### Pattern 4: Custom CSS to Hide Widget Chrome
|
|
980
|
+
|
|
981
|
+
Strip the widget header and borders to embed seamlessly in your UI:
|
|
982
|
+
|
|
983
|
+
```css
|
|
984
|
+
/* chat-widget.css - loaded via stylesheet-url or linked in HTML */
|
|
985
|
+
.squid_chat_widget_header {
|
|
986
|
+
display: none !important;
|
|
987
|
+
}
|
|
988
|
+
.squid_chat_widget {
|
|
989
|
+
box-shadow: none !important;
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
```html
|
|
994
|
+
<squid-chat-widget
|
|
995
|
+
stylesheet-url="/chat-widget.css"
|
|
996
|
+
...
|
|
997
|
+
></squid-chat-widget>
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
### Pattern 5: Exposing Squid Instance Globally for Widget URL Resolution
|
|
1001
|
+
|
|
1002
|
+
When using the widget as a custom element (not React), you may need the Squid client to resolve webhook URLs dynamically:
|
|
1003
|
+
|
|
1004
|
+
```tsx
|
|
1005
|
+
// In your React app, expose the Squid instance globally
|
|
1006
|
+
function Layout() {
|
|
1007
|
+
const squid = useSquid();
|
|
1008
|
+
|
|
1009
|
+
useEffect(() => {
|
|
1010
|
+
(window as any).squid = squid;
|
|
1011
|
+
}, [squid]);
|
|
1012
|
+
|
|
1013
|
+
return <>{/* your app */}</>;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Then in plain JS:
|
|
1017
|
+
const webhookUrl = window.squid.getWebhookUrl('my-webhook');
|
|
1018
|
+
document.querySelector('squid-chat-widget')
|
|
1019
|
+
.setAttribute('squid-ai-custom-api-url', webhookUrl);
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
## Important Notes
|
|
1023
|
+
|
|
1024
|
+
- The widget uses **Shadow DOM** (open mode) for style isolation
|
|
1025
|
+
- **Markdown rendering**: AI responses are rendered as markdown (with GFM support) including syntax-highlighted code blocks
|
|
1026
|
+
- **Keyboard**: Enter to submit, Shift+Enter for newline
|
|
1027
|
+
- **Auto-scroll**: Widget auto-scrolls to bottom on new messages; pauses when user scrolls up
|
|
1028
|
+
- `squid-ai-profile-id` is **deprecated** -- use `squid-ai-agent-id` instead
|
|
1029
|
+
- When `squid-ai-custom-api-url` is set, `squid-app-id` and `squid-region` are still needed for the SquidContextProvider but the agent ID is not required
|
|
1030
|
+
- The widget auto-generates a unique `memoryId` per mount -- to share history across widget instances, provide a custom `memoryId` via `squid-ai-agent-chat-options`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squidcloud/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.458",
|
|
4
4
|
"description": "The Squid CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"node": ">=18.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@squidcloud/local-backend": "^1.0.
|
|
31
|
+
"@squidcloud/local-backend": "^1.0.458",
|
|
32
32
|
"adm-zip": "^0.5.16",
|
|
33
33
|
"copy-webpack-plugin": "^12.0.2",
|
|
34
34
|
"decompress": "^4.2.1",
|