@squidcloud/cli 1.0.488 → 1.0.489
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 +69 -19
- package/dist/resources/claude/skills/squid-development/reference/ai.md +10 -10
- package/dist/resources/claude/skills/squid-development/reference/chat-widget.md +1 -1
- package/dist/resources/claude/skills/squid-development/reference/client.md +1 -1
- package/dist/resources/claude/skills/squid-development/reference/console.md +1 -1
- package/dist/resources/claude/skills/squid-development/reference/openai.md +1 -1
- package/dist/resources/claude/skills/squid-integrations/reference/connector-functions.md +1 -1
- package/dist/resources/claude/skills/squid-react-development/SKILL.md +21 -4
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -32174,7 +32174,8 @@ module.exports = function toBuffer(data, encoding) {
|
|
|
32174
32174
|
var __webpack_unused_export__;
|
|
32175
32175
|
|
|
32176
32176
|
__webpack_unused_export__ = ({ value: true });
|
|
32177
|
-
__webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = exports.h3 = exports.VF = __webpack_unused_export__ = exports.F3 = exports.eS = exports.Eh = exports.dH = exports.mz = exports.Pq = exports.lZ = exports.I1 = exports.xV = exports.Kq = exports.oL = exports.hp = exports.AI_PROVIDER_TYPES = __webpack_unused_export__ = void 0;
|
|
32177
|
+
__webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = exports.h3 = exports.VF = __webpack_unused_export__ = exports.F3 = exports.eS = exports.Eh = exports.dH = exports.mz = exports.Pq = exports.lZ = exports.I1 = exports.xV = exports.Kq = exports.oL = exports.hp = exports.MD = exports.AI_PROVIDER_TYPES = __webpack_unused_export__ = void 0;
|
|
32178
|
+
__webpack_unused_export__ = isFileCapableProviderType;
|
|
32178
32179
|
__webpack_unused_export__ = isVendorAiChatModelName;
|
|
32179
32180
|
__webpack_unused_export__ = isAiEmbeddingsModelName;
|
|
32180
32181
|
__webpack_unused_export__ = isIntegrationEmbeddingModelSpec;
|
|
@@ -32204,29 +32205,40 @@ exports.AI_PROVIDER_TYPES = [
|
|
|
32204
32205
|
'vertex',
|
|
32205
32206
|
'external', // This is a technicality, referring to user-defined providers.
|
|
32206
32207
|
];
|
|
32208
|
+
/**
|
|
32209
|
+
* The AI providers that support file upload operations, and so are the only ones that resolve a
|
|
32210
|
+
* pre-uploaded file id. Declared as the list, with the type derived from it, so the two cannot drift:
|
|
32211
|
+
* a provider added to one is added to both.
|
|
32212
|
+
*/
|
|
32213
|
+
exports.MD = [
|
|
32214
|
+
'openai',
|
|
32215
|
+
'gemini',
|
|
32216
|
+
'anthropic',
|
|
32217
|
+
'grok',
|
|
32218
|
+
];
|
|
32219
|
+
/**
|
|
32220
|
+
* True when the provider resolves pre-uploaded file ids. Every other provider — the integration-backed
|
|
32221
|
+
* and user-defined ones, which report no vendor identity of their own — ignores `fileIds` outright, so
|
|
32222
|
+
* for them the ids are inert rather than wrong.
|
|
32223
|
+
*/
|
|
32224
|
+
function isFileCapableProviderType(type) {
|
|
32225
|
+
return exports.MD.includes(type);
|
|
32226
|
+
}
|
|
32207
32227
|
/**
|
|
32208
32228
|
* Public OpenAI chat model names (active models only).
|
|
32209
32229
|
* @category AI
|
|
32210
32230
|
*/
|
|
32211
|
-
exports.hp = [
|
|
32212
|
-
'gpt-5.4-mini',
|
|
32213
|
-
'gpt-5.4-nano',
|
|
32214
|
-
'gpt-5.5',
|
|
32215
|
-
'gpt-5.5-pro',
|
|
32216
|
-
'gpt-5.6-sol',
|
|
32217
|
-
'gpt-5.6-terra',
|
|
32218
|
-
'gpt-5.6-luna',
|
|
32219
|
-
];
|
|
32231
|
+
exports.hp = ['gpt-5.5-pro', 'gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna'];
|
|
32220
32232
|
/**
|
|
32221
32233
|
* Public Gemini chat model names (active models only).
|
|
32222
32234
|
* @category AI
|
|
32223
32235
|
*/
|
|
32224
|
-
exports.oL = ['gemini-3.1-pro', 'gemini-3.
|
|
32236
|
+
exports.oL = ['gemini-3.1-pro', 'gemini-3.7-flash', 'gemini-3.5-flash-lite'];
|
|
32225
32237
|
/**
|
|
32226
32238
|
* Public Grok chat model names (active models only).
|
|
32227
32239
|
* @category AI
|
|
32228
32240
|
*/
|
|
32229
|
-
exports.Kq = ['grok-4.
|
|
32241
|
+
exports.Kq = ['grok-4.6', 'grok-4-1-fast-reasoning', 'grok-4-1-fast-non-reasoning'];
|
|
32230
32242
|
/**
|
|
32231
32243
|
* Public Anthropic chat model names (active models only).
|
|
32232
32244
|
* @category AI
|
|
@@ -34735,7 +34747,24 @@ onStagingStarted) {
|
|
|
34735
34747
|
activeJobIds.add(jobId);
|
|
34736
34748
|
const { finalStatus, timedOut } = await waitForJobCompletion(client, jobId, batchLabel, timeoutMillis, isInterrupted);
|
|
34737
34749
|
activeJobIds.delete(jobId);
|
|
34738
|
-
|
|
34750
|
+
// A duplicate found by the deferred extraction pass (a presigned object's bytes are first hashed
|
|
34751
|
+
// there) reports as a failed file with `errorCode: 'DUPLICATE_CONTENT'` — the same skip a
|
|
34752
|
+
// staging-time rejection is, so fold it into the duplicates the summary reconciles by name.
|
|
34753
|
+
const deferredDuplicates = (finalStatus?.files ?? [])
|
|
34754
|
+
.filter(file => file.errorCode === 'DUPLICATE_CONTENT')
|
|
34755
|
+
.map(file => file.title);
|
|
34756
|
+
if (deferredDuplicates.length > 0) {
|
|
34757
|
+
console.log(`${batchLabel}: ${deferredDuplicates.length} file(s) skipped as content this knowledge base already holds.`);
|
|
34758
|
+
}
|
|
34759
|
+
return {
|
|
34760
|
+
batchIndex,
|
|
34761
|
+
batchCount,
|
|
34762
|
+
jobId,
|
|
34763
|
+
uploadFailures,
|
|
34764
|
+
duplicates: [...duplicates, ...deferredDuplicates],
|
|
34765
|
+
finalStatus,
|
|
34766
|
+
timedOut,
|
|
34767
|
+
};
|
|
34739
34768
|
}
|
|
34740
34769
|
/** Mints presigned upload URLs for a batch, chunking requests to the server's per-call cap. */
|
|
34741
34770
|
async function createUploadUrlsForBatch(client, fileNames) {
|
|
@@ -34832,7 +34861,13 @@ async function cancelActiveJobs(client, activeJobIds) {
|
|
|
34832
34861
|
}
|
|
34833
34862
|
function printProgress(batchLabel, jobId, status) {
|
|
34834
34863
|
const { counts, state } = status;
|
|
34835
|
-
|
|
34864
|
+
// Deferred duplicates sit inside counts.failed but are skips to the caller (see printSummary) — shown
|
|
34865
|
+
// raw, the live line says "1 failed" on a job the summary then reports as 0 failed, 1 skipped.
|
|
34866
|
+
const duplicateSkips = status.files.filter(file => file.errorCode === 'DUPLICATE_CONTENT').length;
|
|
34867
|
+
const failed = Math.max(0, counts.failed - duplicateSkips);
|
|
34868
|
+
const skippedPart = duplicateSkips > 0 ? `, ${duplicateSkips} skipped` : '';
|
|
34869
|
+
const line = `${batchLabel} job ${jobId}: ${counts.finalized}/${counts.files} finalized, ` +
|
|
34870
|
+
`${failed} failed${skippedPart}, state=${state}`;
|
|
34836
34871
|
process.stdout.write(`\r${line}${' '.repeat(Math.max(0, PROGRESS_LINE_WIDTH - line.length))}`);
|
|
34837
34872
|
}
|
|
34838
34873
|
/** Narrows a `FileUploadResult` to one that uploaded successfully (has a `stagedObjectKey`, no `error`). */
|
|
@@ -34855,7 +34890,13 @@ async function printDryRun(dir, files, batchSize) {
|
|
|
34855
34890
|
}
|
|
34856
34891
|
function printSummary(totalFiles, results) {
|
|
34857
34892
|
const totalFinalized = results.reduce((sum, result) => sum + (result.finalStatus?.counts.finalized ?? 0), 0);
|
|
34858
|
-
|
|
34893
|
+
// Deferred duplicates sit inside counts.failed but are reported on the "Skipped as duplicate" line
|
|
34894
|
+
// (runBatch folds them into `duplicates`), so subtract them here or the two lines double-count.
|
|
34895
|
+
const totalServerFailed = results.reduce((sum, result) => {
|
|
34896
|
+
const failed = result.finalStatus?.counts.failed ?? 0;
|
|
34897
|
+
const duplicateFailures = (result.finalStatus?.files ?? []).filter(file => file.errorCode === 'DUPLICATE_CONTENT').length;
|
|
34898
|
+
return sum + Math.max(0, failed - duplicateFailures);
|
|
34899
|
+
}, 0);
|
|
34859
34900
|
const totalUploadFailed = results.reduce((sum, result) => sum + result.uploadFailures.length, 0);
|
|
34860
34901
|
const totalDuplicates = results.reduce((sum, result) => sum + result.duplicates.length, 0);
|
|
34861
34902
|
const totalStagedButFailed = results.reduce((sum, result) => sum + (result.stagingError ? (result.stagedCount ?? 0) : 0), 0);
|
|
@@ -34890,9 +34931,15 @@ function printSummary(totalFiles, results) {
|
|
|
34890
34931
|
const state = result.timedOut
|
|
34891
34932
|
? `${result.finalStatus?.state ?? 'unknown'} (timed out waiting)`
|
|
34892
34933
|
: result.finalStatus?.state;
|
|
34893
|
-
|
|
34934
|
+
// Deferred duplicates are excluded from BOTH the failed count and the per-file failure lines: they
|
|
34935
|
+
// are already named on the "skipped" lines below, and a clean idempotent re-run must not read as
|
|
34936
|
+
// "0/1 finalized, 1 failed" while exiting 0 — the CLI tells one story about a skip.
|
|
34937
|
+
const deferredDuplicateCount = result.finalStatus?.files.filter(file => file.errorCode === 'DUPLICATE_CONTENT').length ?? 0;
|
|
34938
|
+
const failedCount = Math.max(0, (result.finalStatus?.counts.failed ?? 0) - deferredDuplicateCount);
|
|
34939
|
+
console.log(` ${label}: job ${result.jobId} — ${result.finalStatus?.counts.finalized ?? 0}/${result.finalStatus?.counts.files ?? 0} finalized, ${failedCount} failed [${state}]`);
|
|
34894
34940
|
// Per-file failure reasons, straight from the job-status response (BulkIngestionFileStatus).
|
|
34895
|
-
const failedFiles = result.finalStatus?.files.filter(file => file.status === 'failed') ??
|
|
34941
|
+
const failedFiles = result.finalStatus?.files.filter(file => file.status === 'failed' && file.errorCode !== 'DUPLICATE_CONTENT') ??
|
|
34942
|
+
[];
|
|
34896
34943
|
for (const failedFile of failedFiles) {
|
|
34897
34944
|
console.log(` - ${failedFile.title}: ${failedFile.errorMessage ?? 'unknown error'}`);
|
|
34898
34945
|
}
|
|
@@ -34908,7 +34955,10 @@ function hasBatchFailed(result) {
|
|
|
34908
34955
|
return true;
|
|
34909
34956
|
if (!result.finalStatus)
|
|
34910
34957
|
return true;
|
|
34911
|
-
|
|
34958
|
+
// Deferred duplicates are skips, not failures: an idempotent re-run over an already-ingested
|
|
34959
|
+
// directory must exit 0, exactly as it does when staging rejects the duplicates synchronously.
|
|
34960
|
+
const duplicateFailures = result.finalStatus.files.filter(file => file.errorCode === 'DUPLICATE_CONTENT').length;
|
|
34961
|
+
return result.finalStatus.state !== 'completed' || result.finalStatus.counts.failed > duplicateFailures;
|
|
34912
34962
|
}
|
|
34913
34963
|
/** Recursively walks `dir`, skipping symlinks and dotfiles/dot-directories, filtered to `extensions`. */
|
|
34914
34964
|
async function collectFiles(dir, extensions) {
|
|
@@ -40729,7 +40779,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"seek-bzip","version":"1.0.6",
|
|
|
40729
40779
|
(module) {
|
|
40730
40780
|
|
|
40731
40781
|
"use strict";
|
|
40732
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.
|
|
40782
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.489","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.489","adm-zip":"^0.5.16","copy-webpack-plugin":"^14.0.0","decompress":"^4.2.1","logpipes":"^1.11.0","nodemon":"^3.1.9","terser-webpack-plugin":"^5.5.0","ts-loader":"^9.5.1","ts-node":"^10.9.2","tsconfig-paths":"^4.2.0","tsconfig-paths-webpack-plugin":"^4.1.0","webpack":"^5.106.2","zip-webpack-plugin":"^4.0.1"},"devDependencies":{"@types/adm-zip":"^0.5.7","@types/decompress":"^4.2.7","terminal-link":"^3.0.0"}}');
|
|
40733
40783
|
|
|
40734
40784
|
/***/ }
|
|
40735
40785
|
|
|
@@ -59,10 +59,10 @@ import {
|
|
|
59
59
|
|
|
60
60
|
| Provider | `*_CHAT_MODEL_NAMES` |
|
|
61
61
|
|---|---|
|
|
62
|
-
| OpenAI | `gpt-5.
|
|
62
|
+
| OpenAI | `gpt-5.5-pro`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` |
|
|
63
63
|
| Anthropic | `claude-fable-5`, `claude-haiku-4-5-20251001`, `claude-opus-5`, `claude-sonnet-5` |
|
|
64
|
-
| Gemini | `gemini-3.1-pro`, `gemini-3.
|
|
65
|
-
| Grok | `grok-4.
|
|
64
|
+
| Gemini | `gemini-3.1-pro`, `gemini-3.7-flash`, `gemini-3.5-flash-lite` |
|
|
65
|
+
| Grok | `grok-4.6`, `grok-4-1-fast-reasoning`, `grok-4-1-fast-non-reasoning` |
|
|
66
66
|
|
|
67
67
|
This list moves. **Don't hardcode a model name from this table into user code** — call
|
|
68
68
|
`squid.ai().listChatModels()`, which also returns the app's custom integration models
|
|
@@ -72,7 +72,7 @@ This list moves. **Don't hardcode a model name from this table into user code**
|
|
|
72
72
|
**Model Categories:**
|
|
73
73
|
- **Chat Models**: Used for AI Agents, AI Query, etc. (OpenAI, Anthropic, Gemini, Grok)
|
|
74
74
|
- **Embedding Models**: Used for Knowledge Bases (OpenAI, Voyage)
|
|
75
|
-
- **Image Generation Models**: Used for image creation (
|
|
75
|
+
- **Image Generation Models**: Used for image creation (OpenAI `gpt-image-*`, Stable Diffusion, Flux)
|
|
76
76
|
- **Audio Models**: Transcription (Whisper, GPT-4o) and Text-to-Speech (TTS-1, GPT-4o-mini-tts)
|
|
77
77
|
|
|
78
78
|
## AI Agents
|
|
@@ -115,7 +115,7 @@ await myAgent.upsert({
|
|
|
115
115
|
isPublic: false, // Whether the agent is publicly accessible
|
|
116
116
|
auditLog: true, // Enable audit logging for compliance
|
|
117
117
|
options: {
|
|
118
|
-
model: 'gpt-5.
|
|
118
|
+
model: 'gpt-5.6-terra', // or 'claude-sonnet-5', 'gemini-3.7-flash' - see Supported Models
|
|
119
119
|
instructions: 'You are a helpful customer support assistant. Be concise and professional.',
|
|
120
120
|
temperature: 0.7
|
|
121
121
|
}
|
|
@@ -386,7 +386,7 @@ const chatObs = agent.chat('What is your return policy?', {
|
|
|
386
386
|
connectedKnowledgeBases: [{ knowledgeBaseId: 'kb1', description: 'When to use this KB' }],
|
|
387
387
|
|
|
388
388
|
// Model & generation
|
|
389
|
-
model: 'gpt-5.
|
|
389
|
+
model: 'gpt-5.6-terra', // Override agent's default model
|
|
390
390
|
temperature: 0.7,
|
|
391
391
|
maxTokens: 4000,
|
|
392
392
|
maxOutputTokens: 2000,
|
|
@@ -433,7 +433,7 @@ const chatObs = agent.chat('What is your return policy?', {
|
|
|
433
433
|
useCodeInterpreter: 'llm', // 'none' | 'llm' (OpenAI/Gemini only)
|
|
434
434
|
executionPlanOptions: {
|
|
435
435
|
enabled: true,
|
|
436
|
-
model: 'gpt-5.
|
|
436
|
+
model: 'gpt-5.6-terra',
|
|
437
437
|
reasoningEffort: 'high',
|
|
438
438
|
allowClarificationQuestions: false
|
|
439
439
|
},
|
|
@@ -818,10 +818,10 @@ REST API: [AI Image API](https://docs.getsquid.ai/reference-docs/api/#tag/AI-Ima
|
|
|
818
818
|
### Image Generation
|
|
819
819
|
|
|
820
820
|
```typescript
|
|
821
|
-
// Generate image
|
|
821
|
+
// Generate image - `modelName` is required
|
|
822
822
|
const imageUrl = await squid.ai().image().generate(
|
|
823
823
|
'A futuristic city',
|
|
824
|
-
{ size: '1024x1024', quality: '
|
|
824
|
+
{ modelName: 'gpt-image-1', size: '1024x1024', quality: 'high' }
|
|
825
825
|
);
|
|
826
826
|
|
|
827
827
|
// Remove background
|
|
@@ -894,7 +894,7 @@ const settings = await aiClient.getApplicationAiSettings();
|
|
|
894
894
|
|
|
895
895
|
// Set application AI settings
|
|
896
896
|
await aiClient.setApplicationAiSettings({
|
|
897
|
-
defaultModel: 'gpt-5.
|
|
897
|
+
defaultModel: 'gpt-5.6-terra',
|
|
898
898
|
// ... other settings
|
|
899
899
|
});
|
|
900
900
|
|
|
@@ -763,7 +763,7 @@ declare namespace JSX {
|
|
|
763
763
|
squid-ai-instructions="Be concise and professional."
|
|
764
764
|
squid-ai-functions="getOrderStatus,lookupAccount"
|
|
765
765
|
squid-ai-connected-agents='[{"agentId":"billing-agent","description":"Handles billing questions"}]'
|
|
766
|
-
squid-ai-override-model="gpt-5.
|
|
766
|
+
squid-ai-override-model="gpt-5.6-terra"
|
|
767
767
|
squid-ai-temperature="0.7"
|
|
768
768
|
squid-ai-max-tokens="2000"
|
|
769
769
|
squid-ai-agent-chat-options='{
|
|
@@ -77,7 +77,7 @@ Every Squid application includes the **Essentials Connector** - a built-in integ
|
|
|
77
77
|
| **Web Utilities** | `squid.web()` | AI-powered web search, URL content extraction, short URLs | [Web section](#web) |
|
|
78
78
|
| **AI Agents** | `squid.ai().agent()` | Chat with built-in or custom AI agents | [ai.md](ai.md) |
|
|
79
79
|
| **Knowledge Bases** | `squid.ai().knowledgeBase()` | RAG with semantic, keyword, and knowledge-graph search plus reranking | [ai.md](ai.md) |
|
|
80
|
-
| **Image Generation** | `squid.ai().image()` | Generate images with
|
|
80
|
+
| **Image Generation** | `squid.ai().image()` | Generate images with `gpt-image-*`, Stable Diffusion, or Flux | [ai.md](ai.md) |
|
|
81
81
|
| **Audio** | `squid.ai().audio()` | Transcription and text-to-speech | [ai.md](ai.md) |
|
|
82
82
|
| **PDF/Extraction** | `squid.extraction()` | Create PDFs, extract data from documents | [Extraction section](#extraction) |
|
|
83
83
|
| **Observability** | `squid.observability` | Report and query custom metrics | [Observability section](#observability--metrics) |
|
|
@@ -7,7 +7,7 @@ OpenAI-specific features in Squid. For general AI usage, see [ai.md](ai.md).
|
|
|
7
7
|
```typescript
|
|
8
8
|
import {
|
|
9
9
|
OPENAI_CHAT_MODEL_NAMES, // Chat models
|
|
10
|
-
OPENAI_IMAGE_MODEL_NAMES, //
|
|
10
|
+
OPENAI_IMAGE_MODEL_NAMES, // gpt-image-*
|
|
11
11
|
OPENAI_AUDIO_TRANSCRIPTION_MODEL_NAMES, // Whisper
|
|
12
12
|
OPENAI_AUDIO_CREATE_SPEECH_MODEL_NAMES, // TTS
|
|
13
13
|
OPENAI_EMBEDDINGS_MODEL_NAMES, // Embeddings
|
|
@@ -12,7 +12,7 @@ Each Squid SaaS connector provides built-in AI functions that AI agents can call
|
|
|
12
12
|
await squid.ai().agent('my-agent').upsert({
|
|
13
13
|
description: 'Support agent',
|
|
14
14
|
options: {
|
|
15
|
-
model: 'gpt-5.
|
|
15
|
+
model: 'gpt-5.6-terra',
|
|
16
16
|
instructions: 'You are a support agent that can search tickets and send messages.'
|
|
17
17
|
}
|
|
18
18
|
});
|
|
@@ -164,12 +164,13 @@ function TaskList({ userId }: { userId: string }) {
|
|
|
164
164
|
const tasksCollection = useCollection<Task>('tasks');
|
|
165
165
|
const query = tasksCollection.query().where('userId', '==', userId);
|
|
166
166
|
|
|
167
|
-
const { loading, data, error } = useQuery(query, {
|
|
167
|
+
const { loading, data, error, enabled } = useQuery(query, {
|
|
168
168
|
enabled: !!userId, // Only run when userId is set
|
|
169
169
|
subscribe: true, // Real-time updates (default)
|
|
170
170
|
initialData: [], // Initial data before first load
|
|
171
171
|
}, [userId]); // Re-subscribe when userId changes
|
|
172
172
|
|
|
173
|
+
if (!enabled) return <div>No user selected</div>; // Check before `loading`
|
|
173
174
|
if (loading) return <div>Loading...</div>;
|
|
174
175
|
if (error) return <div>Error: {error.message}</div>;
|
|
175
176
|
|
|
@@ -201,9 +202,20 @@ interface QueryType<T> {
|
|
|
201
202
|
loading: boolean;
|
|
202
203
|
data: Array<T>;
|
|
203
204
|
error: any;
|
|
205
|
+
enabled: boolean; // Mirrors options.enabled
|
|
204
206
|
}
|
|
205
207
|
```
|
|
206
208
|
|
|
209
|
+
**`loading` stays `true` while the query is disabled.** A disabled query never subscribes, so it
|
|
210
|
+
never resolves — gate on `enabled` first, or `if (loading)` renders a spinner forever:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const { loading, data, error, enabled } = useQuery(query, { enabled: !!userId }, [userId]);
|
|
214
|
+
|
|
215
|
+
if (!enabled) return <SelectUserPrompt />; // Not "loading" - just not running
|
|
216
|
+
if (loading) return <Spinner />;
|
|
217
|
+
```
|
|
218
|
+
|
|
207
219
|
**Single Snapshot vs Real-time:**
|
|
208
220
|
```typescript
|
|
209
221
|
// Real-time updates (subscribe: true) - default
|
|
@@ -940,7 +952,7 @@ function AdvancedFeatures() {
|
|
|
940
952
|
const agent = squid.ai().agent('new-agent');
|
|
941
953
|
await agent.upsert({
|
|
942
954
|
description: 'My new agent',
|
|
943
|
-
options: { model: 'gpt-
|
|
955
|
+
options: { model: 'gpt-5.6-terra' },
|
|
944
956
|
});
|
|
945
957
|
};
|
|
946
958
|
|
|
@@ -1054,13 +1066,18 @@ const { data } = useQuery(
|
|
|
1054
1066
|
### 2. Use `enabled` for Conditional Fetching
|
|
1055
1067
|
|
|
1056
1068
|
```typescript
|
|
1057
|
-
// GOOD: Prevent unnecessary queries
|
|
1058
|
-
const { data } = useQuery(query, { enabled: !!userId }, [userId]);
|
|
1069
|
+
// GOOD: Prevent unnecessary queries, and distinguish "disabled" from "loading"
|
|
1070
|
+
const { data, loading, enabled } = useQuery(query, { enabled: !!userId }, [userId]);
|
|
1071
|
+
if (!enabled) return <EmptyState />; // `loading` is still true here
|
|
1072
|
+
if (loading) return <Spinner />;
|
|
1059
1073
|
|
|
1060
1074
|
// BAD: Query runs even when userId is null
|
|
1061
1075
|
const { data } = useQuery(query, {}, [userId]);
|
|
1062
1076
|
```
|
|
1063
1077
|
|
|
1078
|
+
Only `useQuery` returns `enabled`. For the other hooks, track the same condition yourself rather
|
|
1079
|
+
than relying on `loading` to go false while they are disabled.
|
|
1080
|
+
|
|
1064
1081
|
### 3. Provide Type Parameters
|
|
1065
1082
|
|
|
1066
1083
|
```typescript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squidcloud/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.489",
|
|
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.489",
|
|
32
32
|
"adm-zip": "^0.5.16",
|
|
33
33
|
"copy-webpack-plugin": "^14.0.0",
|
|
34
34
|
"decompress": "^4.2.1",
|