@squidcloud/cli 1.0.489 → 1.0.490

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
@@ -32183,7 +32183,7 @@ __webpack_unused_export__ = isIntegrationModelSpec;
32183
32183
  /**
32184
32184
  * @category AI
32185
32185
  */
32186
- __webpack_unused_export__ = ['cohere', 'none'];
32186
+ __webpack_unused_export__ = ['cohere', 'voyage', 'none'];
32187
32187
  /** List of available AI provider types. See AiProviderType. */
32188
32188
  exports.AI_PROVIDER_TYPES = [
32189
32189
  'anthropic',
@@ -32245,6 +32245,7 @@ exports.Kq = ['grok-4.6', 'grok-4-1-fast-reasoning', 'grok-4-1-fast-non-reasonin
32245
32245
  */
32246
32246
  exports.xV = [
32247
32247
  'claude-fable-5',
32248
+ 'claude-fable-5-1',
32248
32249
  'claude-haiku-4-5-20251001',
32249
32250
  'claude-opus-5',
32250
32251
  'claude-sonnet-5',
@@ -32270,7 +32271,7 @@ exports.lZ = ['text-embedding-3-small'];
32270
32271
  /**
32271
32272
  * @category AI
32272
32273
  */
32273
- exports.Pq = ['voyage-3-large'];
32274
+ exports.Pq = ['voyage-3-large', 'voyage-4-large', 'voyage-4'];
32274
32275
  /**
32275
32276
  * @category AI
32276
32277
  */
@@ -32392,6 +32393,7 @@ exports.CONNECTOR_IDS = [
32392
32393
  'cotomi',
32393
32394
  'essentials',
32394
32395
  'freshdesk',
32396
+ 'generic_site_ingester',
32395
32397
  'github',
32396
32398
  'google_calendar',
32397
32399
  'google_drive',
@@ -32422,6 +32424,7 @@ var __webpack_unused_export__;
32422
32424
 
32423
32425
  __webpack_unused_export__ = ({ value: true });
32424
32426
  exports.EL = exports.y4 = exports.q7 = exports.lO = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = __webpack_unused_export__ = exports.INTEGRATION_TYPES = __webpack_unused_export__ = void 0;
32427
+ __webpack_unused_export__ = isIntegrationDisabled;
32425
32428
  __webpack_unused_export__ = isBuiltInIntegrationId;
32426
32429
  /** @internal */
32427
32430
  __webpack_unused_export__ = 'ai_agents';
@@ -32459,11 +32462,13 @@ exports.INTEGRATION_TYPES = [
32459
32462
  'descope',
32460
32463
  'documentdb',
32461
32464
  'azure-entra-external-id',
32465
+ 'azure-entra-id',
32462
32466
  'dynamodb',
32463
32467
  'elasticsearch',
32464
32468
  'firebase_auth',
32465
32469
  'firestore',
32466
32470
  'gcs',
32471
+ 'generic_site_ingester',
32467
32472
  'github',
32468
32473
  'google_calendar',
32469
32474
  'google_docs',
@@ -32544,6 +32549,7 @@ __webpack_unused_export__ = [
32544
32549
  'descope',
32545
32550
  'firebase_auth',
32546
32551
  'azure-entra-external-id',
32552
+ 'azure-entra-id',
32547
32553
  ];
32548
32554
  /**
32549
32555
  * Auth integration types that can OAuth-protect an MCP server (see `McpOAuthOptions` and
@@ -32570,6 +32576,10 @@ exports.q7 = 'built_in_queue';
32570
32576
  * @category
32571
32577
  */
32572
32578
  exports.y4 = 'built_in_storage';
32579
+ /** Returns true when the integration is explicitly disabled. An absent or null `enabled` means enabled. */
32580
+ function isIntegrationDisabled(integration) {
32581
+ return integration.enabled === false;
32582
+ }
32573
32583
  /** Integration IDs used for built-in integrations by Squid. */
32574
32584
  exports.EL = [
32575
32585
  exports.lO,
@@ -33061,13 +33071,15 @@ exports.sQ = void 0;
33061
33071
  __webpack_unused_export__ = isKotlinPath;
33062
33072
  __webpack_unused_export__ = getEnvironmentPrefix;
33063
33073
  exports.getApplicationUrl = getApplicationUrl;
33074
+ __webpack_unused_export__ = getQueryKotlinServiceUrl;
33064
33075
  exports.sQ = [
33065
33076
  'application',
33066
- 'auth',
33067
33077
  'mutation',
33068
- 'native-query',
33069
33078
  'query',
33070
33079
  // Note: every `/ws/*` WebSocket path is served by the TypeScript core (port 8000), never Kotlin.
33080
+ // Note: `native-query` is absent on purpose — the TypeScript core answers it and forwards the
33081
+ // integration types it has no implementation for to Kotlin itself, via
33082
+ // {@link getQueryKotlinServiceUrl}.
33071
33083
  ];
33072
33084
  /**
33073
33085
  * Returns true if the given path is served by Kotlin core in local dev (port 8001). All `/ws/*`
@@ -33113,6 +33125,26 @@ function getApplicationUrl(environmentPrefix, appId, path, appIdPlaceholder, env
33113
33125
  const cleanPath = path.replace(/^\/+/, '');
33114
33126
  return cleanPath ? `${origin}/${cleanPath}` : origin;
33115
33127
  }
33128
+ /**
33129
+ * Returns the URL of [path] on the `core-query-kotlin` Service, addressed from inside the cluster.
33130
+ *
33131
+ * Naming the Service rather than building the public URL with {@link getApplicationUrl} keeps a
33132
+ * purely intra-cluster call off the external load balancer, which is what the Kotlin core's own
33133
+ * `getApplicationUrlInternal` already does for the hop in the other direction; and it makes the call
33134
+ * independent of where ingress sends [path], so moving that route cannot turn a forward into a
33135
+ * request back to this core.
33136
+ *
33137
+ * The Service is shared and not per-app, so the application is identified by the
33138
+ * `SquidHeaders.APP_ID` header rather than by the hostname. Local development has no cluster DNS and
33139
+ * keeps the per-app host on Kotlin's port.
33140
+ */
33141
+ function getQueryKotlinServiceUrl(environmentPrefix, appId, path) {
33142
+ if (isLocal(environmentPrefix)) {
33143
+ return getApplicationUrl(environmentPrefix, appId, path, undefined, undefined, true);
33144
+ }
33145
+ const cleanPath = path.replace(/^\/+/, '');
33146
+ return `http://core-query-kotlin.default.svc.cluster.local:8001/${cleanPath}`;
33147
+ }
33116
33148
  function isLocal(regionPrefix) {
33117
33149
  return /^local/.test(regionPrefix);
33118
33150
  }
@@ -34467,6 +34499,20 @@ const SIGINT_STAGING_WAIT_MILLIS = 10 * time_units_1.MILLIS_PER_SECOND;
34467
34499
  const DEFAULT_TIMEOUT_MINUTES = 120;
34468
34500
  /** Interval between `bulk/getJob` polls while waiting for a job to reach a terminal state. */
34469
34501
  const POLL_INTERVAL_MILLIS = 10 * time_units_1.MILLIS_PER_SECOND;
34502
+ /**
34503
+ * How old the last successful poll may be for the timeout classification to trust it. A status older
34504
+ * than this (every recent poll failed) says nothing about the job NOW, so the timeout falls back to the
34505
+ * conservative failure exit instead of waving a stale "still draining" snapshot through.
34506
+ */
34507
+ const STALE_STATUS_TOLERANCE_MILLIS = 3 * POLL_INTERVAL_MILLIS;
34508
+ /**
34509
+ * How recently a poll must have observed an ACTIVE provider batch for a timeout to defer when NO work
34510
+ * is queued: the no-pending grace for the tick-long gap between one batch's reconciliation and the
34511
+ * next stage's submission. With `requestsPending > 0` behind an observed batch the deferral holds
34512
+ * regardless of this window (queued work is stalled-but-alive under cluster load); a job past this
34513
+ * window with nothing pending is wedged and takes the failure exit.
34514
+ */
34515
+ const ACTIVE_BATCH_RECENCY_MILLIS = 5 * time_units_1.MILLIS_PER_MINUTE;
34470
34516
  /** Extensions ingested by default when `--extensions` is not provided. */
34471
34517
  const DEFAULT_EXTENSIONS = ['pdf', 'docx', 'txt', 'md', 'html', 'csv', 'xlsx', 'xls', 'xlsm', 'xlsb', 'pptx'];
34472
34518
  /** Job states that end a bulk-ingestion job's lifecycle (`BulkIngestionJobState` in core). */
@@ -34477,6 +34523,7 @@ const UNKNOWN_JOB_STATUS = {
34477
34523
  state: 'unknown',
34478
34524
  counts: { files: 0, finalized: 0, failed: 0, requestsPending: 0, requestsSubmitted: 0 },
34479
34525
  providerBatchIds: [],
34526
+ activeProviderBatchCount: 0,
34480
34527
  files: [],
34481
34528
  };
34482
34529
  /**
@@ -34745,7 +34792,7 @@ onStagingStarted) {
34745
34792
  console.log(`${batchLabel}: ${duplicates.length} file(s) skipped as content this knowledge base already holds.`);
34746
34793
  }
34747
34794
  activeJobIds.add(jobId);
34748
- const { finalStatus, timedOut } = await waitForJobCompletion(client, jobId, batchLabel, timeoutMillis, isInterrupted);
34795
+ const { finalStatus, timedOut, statusStale, lastActiveBatchAtMillis } = await waitForJobCompletion(client, jobId, batchLabel, timeoutMillis, isInterrupted);
34749
34796
  activeJobIds.delete(jobId);
34750
34797
  // A duplicate found by the deferred extraction pass (a presigned object's bytes are first hashed
34751
34798
  // there) reports as a failed file with `errorCode: 'DUPLICATE_CONTENT'` — the same skip a
@@ -34764,6 +34811,21 @@ onStagingStarted) {
34764
34811
  duplicates: [...duplicates, ...deferredDuplicates],
34765
34812
  finalStatus,
34766
34813
  timedOut,
34814
+ // Only a FRESH status may waive the timeout, and only on OBSERVED batch activity: an active batch
34815
+ // on the final poll; one seen within the recency window; or one seen at ANY point of this wait
34816
+ // while queued work remains (`requestsPending > 0`) — inter-stage stalls scale with cluster load
34817
+ // (the submit pass visits ~20 running jobs per 15s tick, and an app at its in-flight batch cap
34818
+ // waits for a sibling to drain), so pending-work-behind-an-observed-batch is stalled-but-alive,
34819
+ // not wedged. A job with batches long drained and NOTHING pending takes the failure exit. The
34820
+ // job's `transport` is deliberately NOT consulted: it is 'batch' from staging for every large
34821
+ // job, batches or none, so it cannot say whether anything is draining NOW.
34822
+ deferredInFlight: timedOut &&
34823
+ !statusStale &&
34824
+ finalStatus.state === 'running' &&
34825
+ ((finalStatus.activeProviderBatchCount ?? 0) > 0 ||
34826
+ (lastActiveBatchAtMillis > 0 &&
34827
+ (Date.now() - lastActiveBatchAtMillis < ACTIVE_BATCH_RECENCY_MILLIS ||
34828
+ finalStatus.counts.requestsPending > 0))),
34767
34829
  };
34768
34830
  }
34769
34831
  /** Mints presigned upload URLs for a batch, chunking requests to the server's per-call cap. */
@@ -34822,7 +34884,10 @@ async function uploadFile(filePath, upload, stagedObjectKey) {
34822
34884
  async function waitForJobCompletion(client, jobId, batchLabel, timeoutMillis, isInterrupted) {
34823
34885
  const deadline = Date.now() + timeoutMillis;
34824
34886
  let status;
34887
+ let statusAtMillis = 0;
34888
+ let lastActiveBatchAtMillis = 0;
34825
34889
  let isFirstPoll = true;
34890
+ let deferralAnnounced = false;
34826
34891
  while (!isInterrupted() && Date.now() < deadline && (!status || !TERMINAL_JOB_STATES.has(status.state))) {
34827
34892
  if (!isFirstPoll) {
34828
34893
  await sleep(POLL_INTERVAL_MILLIS);
@@ -34830,6 +34895,17 @@ async function waitForJobCompletion(client, jobId, batchLabel, timeoutMillis, is
34830
34895
  isFirstPoll = false;
34831
34896
  try {
34832
34897
  status = await client.getJob(jobId);
34898
+ statusAtMillis = Date.now();
34899
+ if ((status.activeProviderBatchCount ?? 0) > 0) {
34900
+ lastActiveBatchAtMillis = statusAtMillis;
34901
+ if (!deferralAnnounced) {
34902
+ deferralAnnounced = true;
34903
+ console.log(`\n${batchLabel}: job ${jobId} submitted a provider batch — half-price processing whose tail can ` +
34904
+ `reach 24 hours, possibly past --timeoutMinutes. A timed-out wait leaves the job running ` +
34905
+ `without failing the run; the job finishes server-side, and re-runs are idempotent ` +
34906
+ `(already-staged content skips as duplicate).`);
34907
+ }
34908
+ }
34833
34909
  printProgress(batchLabel, jobId, status);
34834
34910
  }
34835
34911
  catch (error) {
@@ -34839,13 +34915,18 @@ async function waitForJobCompletion(client, jobId, batchLabel, timeoutMillis, is
34839
34915
  process.stdout.write('\n');
34840
34916
  if (!status) {
34841
34917
  console.warn(`${batchLabel}: could not retrieve job ${jobId}'s status before the timeout.`);
34842
- return { finalStatus: UNKNOWN_JOB_STATUS, timedOut: true };
34918
+ return { finalStatus: UNKNOWN_JOB_STATUS, timedOut: true, statusStale: true, lastActiveBatchAtMillis: 0 };
34843
34919
  }
34844
34920
  const timedOut = !TERMINAL_JOB_STATES.has(status.state) && !isInterrupted();
34845
34921
  if (timedOut) {
34846
34922
  console.warn(`${batchLabel}: job ${jobId} did not finish within the timeout; it may still be running server-side.`);
34847
34923
  }
34848
- return { finalStatus: status, timedOut };
34924
+ return {
34925
+ finalStatus: status,
34926
+ timedOut,
34927
+ statusStale: Date.now() - statusAtMillis > STALE_STATUS_TOLERANCE_MILLIS,
34928
+ lastActiveBatchAtMillis,
34929
+ };
34849
34930
  }
34850
34931
  /** Best-effort cancellation of every job still active when the process is interrupted. */
34851
34932
  async function cancelActiveJobs(client, activeJobIds) {
@@ -34913,6 +34994,17 @@ function printSummary(totalFiles, results) {
34913
34994
  if (totalStagedButFailed > 0) {
34914
34995
  console.log(`Staged but job failed: ${totalStagedButFailed} (uploaded objects remain; auto-expire in 24h)`);
34915
34996
  }
34997
+ const totalStillDeferred = results.reduce((sum, result) => result.deferredInFlight
34998
+ ? sum +
34999
+ Math.max(0, (result.finalStatus?.counts.files ?? 0) -
35000
+ (result.finalStatus?.counts.finalized ?? 0) -
35001
+ (result.finalStatus?.counts.failed ?? 0))
35002
+ : sum, 0);
35003
+ if (totalStillDeferred > 0) {
35004
+ // Reconciles the summary the same way the duplicates line does: these files are neither finalized
35005
+ // nor failed, and without this line they read as silently missing from a run that exits 0.
35006
+ console.log(`Still processing: ${totalStillDeferred} (queued or draining server-side; the job finishes there)`);
35007
+ }
34916
35008
  for (const result of results) {
34917
35009
  const label = `batch ${result.batchIndex + 1}/${result.batchCount}`;
34918
35010
  if (result.stagingError) {
@@ -34928,9 +35020,11 @@ function printSummary(totalFiles, results) {
34928
35020
  console.log(` ${label}: no job created (all uploads failed)`);
34929
35021
  continue;
34930
35022
  }
34931
- const state = result.timedOut
34932
- ? `${result.finalStatus?.state ?? 'unknown'} (timed out waiting)`
34933
- : result.finalStatus?.state;
35023
+ const state = result.deferredInFlight
35024
+ ? 'running work still queued or draining server-side (batch tail can reach 24h); re-runs are idempotent'
35025
+ : result.timedOut
35026
+ ? `${result.finalStatus?.state ?? 'unknown'} (timed out waiting)`
35027
+ : result.finalStatus?.state;
34934
35028
  // Deferred duplicates are excluded from BOTH the failed count and the per-file failure lines: they
34935
35029
  // are already named on the "skipped" lines below, and a clean idempotent re-run must not read as
34936
35030
  // "0/1 finalized, 1 failed" while exiting 0 — the CLI tells one story about a skip.
@@ -34951,14 +35045,21 @@ function printSummary(totalFiles, results) {
34951
35045
  }
34952
35046
  }
34953
35047
  function hasBatchFailed(result) {
34954
- if (result.uploadFailures.length > 0 || result.timedOut)
35048
+ if (result.uploadFailures.length > 0)
34955
35049
  return true;
34956
35050
  if (!result.finalStatus)
34957
35051
  return true;
34958
35052
  // Deferred duplicates are skips, not failures: an idempotent re-run over an already-ingested
34959
35053
  // directory must exit 0, exactly as it does when staging rejects the duplicates synchronously.
34960
35054
  const duplicateFailures = result.finalStatus.files.filter(file => file.errorCode === 'DUPLICATE_CONTENT').length;
34961
- return result.finalStatus.state !== 'completed' || result.finalStatus.counts.failed > duplicateFailures;
35055
+ const nonDuplicateFailed = result.finalStatus.counts.failed - duplicateFailures;
35056
+ // A wait-budget expiry on a still-draining provider batch is not a failure BY ITSELF: the pending
35057
+ // files will finish server-side, and exiting 1 would report success-in-progress as an error to every
35058
+ // unattended corpus load. Files the job has ALREADY failed still fail the run — a deferral must never
35059
+ // hide them behind exit 0. Every other timeout shape fails the run outright.
35060
+ if (result.timedOut)
35061
+ return result.deferredInFlight ? nonDuplicateFailed > 0 : true;
35062
+ return result.finalStatus.state !== 'completed' || nonDuplicateFailed > 0;
34962
35063
  }
34963
35064
  /** Recursively walks `dir`, skipping symlinks and dotfiles/dot-directories, filtered to `extensions`. */
34964
35065
  async function collectFiles(dir, extensions) {
@@ -35554,6 +35655,9 @@ const process_utils_1 = __webpack_require__(8251);
35554
35655
  const report_utils_1 = __webpack_require__(3066);
35555
35656
  const version_check_1 = __webpack_require__(4827);
35556
35657
  const ORG = 'squid-cloud-samples';
35658
+ // Audit and fund are extra registry round-trips that tell the user nothing about a project the
35659
+ // CLI just generated, and the audit request alone can take minutes.
35660
+ const NPM_INSTALL_COMMAND = 'npm install --no-audit --no-fund';
35557
35661
  async function initSample(consoleRegion, isOnPremConsole, dirPath, appId, apiKey, environmentId, squidDeveloperId, region, templateName, verbose = false) {
35558
35662
  (0, global_utils_1.enableDebugLogs)(verbose || (0, global_utils_1.isDebugEnabled)());
35559
35663
  (0, logpipes_1.installConsoleOverrides)(enable_debug_decorator_utils_1.debugLogFilterPipe);
@@ -35602,18 +35706,18 @@ async function initSample(consoleRegion, isOnPremConsole, dirPath, appId, apiKey
35602
35706
  let monorepo = false;
35603
35707
  try {
35604
35708
  await promises_1.default.access(path_1.default.resolve(dirPath, 'package.json'));
35605
- await (0, shell_runner_1.runInShell)('npm install', verbose, path_1.default.resolve(dirPath));
35709
+ await (0, shell_runner_1.runInShell)(NPM_INSTALL_COMMAND, verbose, path_1.default.resolve(dirPath));
35606
35710
  }
35607
35711
  catch { }
35608
35712
  try {
35609
35713
  await promises_1.default.access(path_1.default.resolve(dirPath, 'backend'));
35610
- await (0, shell_runner_1.runInShell)('npm install', verbose, path_1.default.resolve(dirPath, 'backend'));
35714
+ await (0, shell_runner_1.runInShell)(NPM_INSTALL_COMMAND, verbose, path_1.default.resolve(dirPath, 'backend'));
35611
35715
  monorepo = true;
35612
35716
  }
35613
35717
  catch { }
35614
35718
  try {
35615
35719
  await promises_1.default.access(path_1.default.resolve(dirPath, 'frontend'));
35616
- await (0, shell_runner_1.runInShell)('npm install', verbose, path_1.default.resolve(dirPath, 'frontend'));
35720
+ await (0, shell_runner_1.runInShell)(NPM_INSTALL_COMMAND, verbose, path_1.default.resolve(dirPath, 'frontend'));
35617
35721
  }
35618
35722
  catch { }
35619
35723
  const hasEnvars = appId && region && apiKey && environmentId && squidDeveloperId;
@@ -40779,7 +40883,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"seek-bzip","version":"1.0.6",
40779
40883
  (module) {
40780
40884
 
40781
40885
  "use strict";
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"}}');
40886
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@squidcloud/cli","version":"1.0.490","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.490","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"}}');
40783
40887
 
40784
40888
  /***/ }
40785
40889
 
@@ -22,8 +22,8 @@ Squid is a backend-as-a-service platform that provides:
22
22
  ## Feature-Specific Guidance
23
23
 
24
24
  - **[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, allowedDomains, getUrlContent, createShortUrl, jobs, getJob, awaitJob, startJob, completeJob, failJob, events, squid.events(), emit, TriggerEvent, LangGraph, squid.langGraph(), invoke, invokeAsync, resume, getState, deleteThread, observability, metrics, reportMetric, queryMetrics, setMetricAnnotations, notifications, publishNotification, observeNotifications
25
- - **[console.md](reference/console.md)** → Squid Console, web UI, organizations, applications, AI Studio, knowledge bases, knowledge graph toggle, integrations, monitoring, logs, API keys, secrets, testing, debugging, profile settings, management API keys
26
- - **[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, metricAnnotations, voiceOptions, OpenAI, Anthropic, Gemini, Grok, DALL-E, Whisper, MCP, @mcpServer, @mcpTool, agent as MCP server, updateMcpServer, generateMcpDescriptions, agent API key, executeAiQuery, executeAiApiCall, extraction, createPdf, upsert agent, listAgents, listChatModels, listFunctions, spreadsheet understanding, querySpreadsheetsWithAi, searchMode, keyword search, xlsx, csv, grep, literal scan, knowledge graph, GraphRAG, graphRag, graph search, queryGraph, getGraphStatus, rebuildGraph, exploreGraph, searchWithGraphContext, graphOptions, graphFilter, underConcept, entityTypes, queryKnowledgeGraph, bulk ingestion, bulkUpsertContexts, createBulkUploadUrls, observeBulkIngestionJob, listContextsPage, generateMetadataFieldDescriptions
25
+ - **[console.md](reference/console.md)** → Squid Console, web UI, organizations, applications, AI Studio, knowledge bases, knowledge graph toggle, extraction method dropdown, integrations, monitoring, logs, API keys, secrets, testing, debugging, profile settings, management API keys
26
+ - **[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, metricAnnotations, voiceOptions, OpenAI, Anthropic, Gemini, Grok, DALL-E, Whisper, MCP, @mcpServer, @mcpTool, agent as MCP server, updateMcpServer, generateMcpDescriptions, agent API key, executeAiQuery, executeAiApiCall, extraction, createPdf, upsert agent, listAgents, listChatModels, listFunctions, spreadsheet understanding, querySpreadsheetsWithAi, searchMode, keyword search, xlsx, csv, grep, literal scan, knowledge graph, GraphRAG, graphRag, graph search, queryGraph, getGraphStatus, rebuildGraph, exploreGraph, searchWithGraphContext, graphOptions, graphFilter, underConcept, entityTypes, queryKnowledgeGraph, bulk ingestion, bulkUpsertContexts, createBulkUploadUrls, observeBulkIngestionJob, listContextsPage, generateMetadataFieldDescriptions, extraction method, preferredExtractionMethod, legacy_with_llm, mistral_ocr, amazon_textract, azure_document_intelligence, page screenshot, image description, extractImages
27
27
  - **[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
28
28
  - **[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(), docId, docIds, query.delete(), delete by query, projectFields, field projection, __docId__, __id
29
29
  - **[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, getSquid, getPassiveSquid, this.secrets, @clientConnectionStateHandler, @onQueueMessage, QueueMessageRequest, queue message handler, server-side queue consumer, @eventHandler, event handler, workspace, CLI, squid init, squid start, squid deploy, squid build, squid kb-upload, printBundle, project structure, multiple services, service architecture, squidInject, cross-service communication
@@ -128,7 +128,7 @@ console.log(agentInfo.id, agentInfo.description, agentInfo.options.model);
128
128
  // Update specific properties
129
129
  await myAgent.updateInstructions('You are a technical support specialist.');
130
130
  await myAgent.updateModel('claude-sonnet-5');
131
- await myAgent.updateGuardrails(['no-harmful-content']);
131
+ await myAgent.updateGuardrails({ disableProfanity: true, disablePii: true });
132
132
 
133
133
  // Delete an agent
134
134
  await myAgent.delete();
@@ -393,7 +393,11 @@ const chatObs = agent.chat('What is your return policy?', {
393
393
  instructions: 'Additional instructions for this request only',
394
394
  responseFormat: 'json_object', // or 'text'
395
395
  verbosity: 'medium', // 'low' | 'medium' | 'high' (OpenAI only)
396
- reasoningEffort: 'high', // 'minimal' | 'low' | 'medium' | 'high' (for reasoning models)
396
+ reasoningEffort: 'high', // 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'ultra'
397
+ // (for reasoning models). On an `openai_compatible` integration the value
398
+ // is sent to the endpoint as written, so a level outside this list reaches
399
+ // it too — OpenAI's Chat Completions API, for one, serves function tools on
400
+ // a gpt-5.6 model only with reasoning off outright (`'none'`).
397
401
 
398
402
  // Context & RAG
399
403
  disableContext: false,
@@ -404,7 +408,13 @@ const chatObs = agent.chat('What is your return policy?', {
404
408
  },
405
409
 
406
410
  // Guardrails & quotas
407
- guardrails: ['no-harmful-content', 'no-pii'],
411
+ guardrails: {
412
+ disableProfanity: true,
413
+ offTopicAnswers: true,
414
+ professionalTone: true,
415
+ disablePii: true,
416
+ custom: 'Never reveal internal case numbers'
417
+ },
408
418
  quotas: {
409
419
  maxAiCallStackSize: 5
410
420
  },
@@ -530,6 +540,12 @@ await kb.upsertContexts([
530
540
  { contextId: 'doc-2', text: '...' }
531
541
  ], optionalFiles);
532
542
 
543
+ // File contexts can pick how the document is extracted — see "Document Extraction Methods" below
544
+ await kb.upsertContexts(
545
+ [{ contextId: 'report-1', type: 'file', preferredExtractionMethod: 'legacy_with_llm' }],
546
+ [reportPdfFile]
547
+ );
548
+
533
549
  // Search with prompt
534
550
  const results = await kb.searchContextsWithPrompt({
535
551
  prompt: 'How do I reset password?',
@@ -784,6 +800,14 @@ await kb.bulkUpsertContexts(uploads.map(u => ({ type: 'file', stagedObjectKey: u
784
800
  The CLI wraps this whole flow: `squid kb-upload --dir ./docs --knowledgeBase my-kb` (see
785
801
  [backend.md](backend.md#cli-commands)).
786
802
 
803
+ ### Document Extraction Methods
804
+
805
+ File contexts (and `squid.extraction()` calls) accept `preferredExtractionMethod: 'mistral_ocr' | 'legacy' | 'legacy_with_llm' | 'amazon_textract' | 'azure_document_intelligence'`. Default: the deployment's `defaultDocExtractionMethod` (usually `mistral_ocr`). The OCR providers (`mistral_ocr`, `amazon_textract`, `azure_document_intelligence`) are available only where the deployment configures them; `legacy` and `legacy_with_llm` run in-process and are always available. The same option applies to `upsertContexts`, `bulkUpsertContexts`, and the extraction client alike.
806
+
807
+ - `legacy` — reads the PDF's text layer (pdfjs) and extracts embedded images; no external service, but a scanned page yields nothing (there is no text layer to read). Console label: **Basic**.
808
+ - `legacy_with_llm` — the same text extraction, plus a screenshot of each page described by a vision model as a *complement* to the stored page text: figures, charts, layout, handwriting, and scanned regions the text layer cannot carry, without restating the page's prose. Notably, vector-drawn figures/graphs are not embedded images, so `legacy` cannot see them at all; the page screenshot (like provider OCR) is what catches them. Each description lands as its own chunk beside the page's text chunk, with page provenance; a page whose screenshot adds nothing beyond its text stores no extra chunk. Costs one vision call per page, so ingestion of long documents is slower and pricier than `legacy`. Console label: **Basic + page understanding**.
809
+ - `extractImages` (default `true` for file contexts) gates image handling for every method, including the `legacy_with_llm` page screenshots; `imageMinSizePixels` (default 100) filters small embedded images; `imageExtractionModel` overrides the model used for image/screenshot descriptions.
810
+
787
811
  ### Spreadsheet Understanding
788
812
 
789
813
  Spreadsheet files (`.csv`, `.tsv`, `.xlsx`, `.xlsm`, `.xls`, `.xlsb`) uploaded as file context take a dedicated ingestion lane: instead of chunking raw cell text, Squid extracts the workbook structure (sheets, headers, hidden sheets; charts and pivot tables where the format exposes them — absent for CSV/TSV and `.xls`, pivots also absent for `.xlsb`) and embeds a generated whole-workbook summary, so search results describe what a workbook contains.
@@ -389,7 +389,12 @@ const extractedData = await extraction.extractDataFromDocumentFile(
389
389
  { name: 'total', type: 'number', description: 'Total amount' },
390
390
  { name: 'date', type: 'date', description: 'Invoice date' }
391
391
  ]
392
- }
392
+ },
393
+ // 'mistral_ocr' | 'legacy' | 'legacy_with_llm' | 'amazon_textract' | 'azure_document_intelligence'.
394
+ // Default: the deployment's configured method (usually 'mistral_ocr'). Semantics: see the
395
+ // "Document Extraction Methods" section in ai.md.
396
+ preferredExtractionMethod: 'legacy_with_llm',
397
+ extractImages: true // default true; also gates legacy_with_llm's page screenshots
393
398
  }
394
399
  );
395
400
 
@@ -73,6 +73,7 @@ The AI Studio provides visual tools for building and testing AI agents:
73
73
 
74
74
  ### Managing Content
75
75
  - Upload documents (PDF, text, markdown, etc.)
76
+ - Pick the **Extraction Method** in the add-knowledge dialog: **Basic** (`legacy`, in-process text extraction) and **Basic + page understanding** (`legacy_with_llm`, adds an LLM description of each page's screenshot) are always offered; OCR providers (**Mistral OCR**, **Amazon Textract**, **Azure AI Document Intelligence**) appear when the deployment configures them, with the deployment default marked **(Default)**
76
77
  - View and edit contexts
77
78
  - Search and preview indexed content
78
79
  - Monitor indexing status
@@ -194,9 +194,11 @@ const content = await squid.web().getUrlContent('https://example.com');
194
194
  // Short URLs
195
195
  const shortUrl = await squid.web().createShortUrl('https://long-url.com/path');
196
196
 
197
- // Data Extraction from documents
198
- const data = await squid.extraction().extractDataFromDocumentUrl(url, schema);
199
- const data = await squid.extraction().extractDataFromDocumentFile(file, schema);
197
+ // Data Extraction from documents. Optional preferredExtractionMethod:
198
+ // 'mistral_ocr' | 'legacy' | 'legacy_with_llm' | 'amazon_textract' | 'azure_document_intelligence'
199
+ // (see the squid-development skill's ai.md "Document Extraction Methods")
200
+ const data = await squid.extraction().extractDataFromDocumentUrl(url);
201
+ const data = await squid.extraction().extractDataFromDocumentFile(file, { preferredExtractionMethod: 'legacy_with_llm' });
200
202
 
201
203
  // PDF Creation
202
204
  const pdf = await squid.extraction().createPdf(htmlContent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squidcloud/cli",
3
- "version": "1.0.489",
3
+ "version": "1.0.490",
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.489",
31
+ "@squidcloud/local-backend": "^1.0.490",
32
32
  "adm-zip": "^0.5.16",
33
33
  "copy-webpack-plugin": "^14.0.0",
34
34
  "decompress": "^4.2.1",