@squidcloud/cli 1.0.457 → 1.0.459

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-6',
29747
+ 'claude-opus-4-7',
29748
29748
  'claude-sonnet-4-6',
29749
29749
  ];
29750
29750
  /**
@@ -29878,10 +29878,12 @@ exports.INTEGRATION_TYPES = [
29878
29878
  'api',
29879
29879
  'auth0',
29880
29880
  'bedrock',
29881
+ 'azure_blob',
29881
29882
  'azure_cosmosdb',
29882
29883
  'azure_postgresql',
29883
29884
  'azure_sql',
29884
29885
  'bigquery',
29886
+ 'built_in_azure_blob',
29885
29887
  'built_in_db',
29886
29888
  'built_in_gcs',
29887
29889
  'built_in_queue',
@@ -30444,17 +30446,13 @@ exports.KOTLIN_CONTROLLERS = [
30444
30446
  'api',
30445
30447
  'application',
30446
30448
  'auth',
30447
- 'integration',
30448
- 'internal-storage',
30449
30449
  'management-secret',
30450
30450
  'mutation',
30451
30451
  'native-query',
30452
30452
  'query',
30453
30453
  'queue',
30454
- 'quota',
30455
30454
  'scheduler',
30456
30455
  'secret',
30457
- 'storage',
30458
30456
  'ws',
30459
30457
  'internal-extraction',
30460
30458
  'notification',
@@ -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.457","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.457","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"}}');
37342
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.459","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.459","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.457",
3
+ "version": "1.0.459",
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.457",
31
+ "@squidcloud/local-backend": "^1.0.459",
32
32
  "adm-zip": "^0.5.16",
33
33
  "copy-webpack-plugin": "^12.0.2",
34
34
  "decompress": "^4.2.1",