squidcloud

Squid Cloud Python client SDK.

Usage::

from squidcloud import Squid

squid = Squid(
    app_id="my-app",
    api_key="my-api-key",
    region="us-east-1.aws",
    environment_id="dev",
)

# AI agents
response = await squid.ai().agent("my-agent").ask("Hello!")

# Execute backend function
result = await squid.execute_function("MyService:greet", "World")

# Web utilities
content = await squid.web().get_url_content("https://example.com")
  1"""Squid Cloud Python client SDK.
  2
  3Usage::
  4
  5    from squidcloud import Squid
  6
  7    squid = Squid(
  8        app_id="my-app",
  9        api_key="my-api-key",
 10        region="us-east-1.aws",
 11        environment_id="dev",
 12    )
 13
 14    # AI agents
 15    response = await squid.ai().agent("my-agent").ask("Hello!")
 16
 17    # Execute backend function
 18    result = await squid.execute_function("MyService:greet", "World")
 19
 20    # Web utilities
 21    content = await squid.web().get_url_content("https://example.com")
 22"""
 23
 24from squidcloud.ai import (
 25    AgentClient,
 26    AiClient,
 27    AudioClient,
 28    ImageClient,
 29    KnowledgeBaseClient,
 30)
 31from squidcloud.client import Squid
 32from squidcloud.extraction import ExtractionClient
 33from squidcloud.http import SquidHttpError
 34from squidcloud.matchmaking import MatchmakingClient
 35from squidcloud.types import (
 36    AiAgent,
 37    AiAgentExecutionPlanOptions,
 38    AiAgentMcpServerConfig,
 39    AiAgentMemoryOptions,
 40    AiAgentResponseFormat,
 41    AiAudioCreateSpeechOptions,
 42    AiChatModelSelection,
 43    AiChatOptions,
 44    AiChatPromptQuotas,
 45    AiConnectedAgentMetadata,
 46    AiConnectedIntegrationMetadata,
 47    AiConnectedKnowledgeBaseMetadata,
 48    AiContextFileOptions,
 49    AiContextTextOptions,
 50    AiEmbeddingsModelSelection,
 51    AiFileUrl,
 52    AiFunctionAttributes,
 53    AiFunctionMetadata,
 54    AiFunctionParam,
 55    AiKnowledgeBase,
 56    AiKnowledgeBaseGraphConceptsConfig,
 57    AiKnowledgeBaseGraphConfig,
 58    AiKnowledgeBaseGraphFilter,
 59    AiKnowledgeBaseGraphPathFacetConfig,
 60    AiKnowledgeBaseGraphSearchOptions,
 61    AiKnowledgeBaseMetadataField,
 62    AiPiiOptions,
 63    AiQueryAnalyzeResultsOptions,
 64    AiQueryCollectionsSelectionRunMode,
 65    AiQueryGenerateQueryOptions,
 66    AiQueryOptions,
 67    AiQuerySelectCollectionsOptions,
 68    AiQueryValidateWithAiOptions,
 69    AiSessionContext,
 70    AiStructuredOutputFormat,
 71    ContextRequest,
 72    CreatePdfDimensionsOptions,
 73    CreatePdfFormatOptions,
 74    CreatePdfOutputOptions,
 75    ExtractDataFromDocumentOptions,
 76    FileContextRequest,
 77    FluxOptions,
 78    GptImageOptions,
 79    GuardrailsOptions,
 80    ImageGenerateOptions,
 81    IntegrationEmbeddingModelSpec,
 82    IntegrationModelSpec,
 83    KnowledgeBaseGraphQueryOp,
 84    KnowledgeBaseSearchOptions,
 85    MmCategory,
 86    MmEntity,
 87    MmFindMatchesOptions,
 88    MmListEntitiesOptions,
 89    ModelIdSpec,
 90    StableDiffusionOptions,
 91    TextContextRequest,
 92    UpsertAgentOptions,
 93    VectorDbType,
 94    WebAiSearchResponse,
 95    WebShortUrlBulkResponse,
 96    WebShortUrlResponse,
 97)
 98from squidcloud.web import WebClient
 99
100__all__ = [
101    "AgentClient",
102    "AiAgent",
103    "AiAgentExecutionPlanOptions",
104    "AiAgentMcpServerConfig",
105    "AiAgentMemoryOptions",
106    "AiAgentResponseFormat",
107    "AiAudioCreateSpeechOptions",
108    "AiChatModelSelection",
109    # AI Chat
110    "AiChatOptions",
111    "AiChatPromptQuotas",
112    "AiClient",
113    "AiConnectedAgentMetadata",
114    "AiConnectedIntegrationMetadata",
115    "AiConnectedKnowledgeBaseMetadata",
116    "AiContextFileOptions",
117    "AiContextTextOptions",
118    "AiEmbeddingsModelSelection",
119    "AiFileUrl",
120    "AiFunctionAttributes",
121    "AiFunctionMetadata",
122    "AiFunctionParam",
123    # Knowledge Base
124    "AiKnowledgeBase",
125    "AiKnowledgeBaseGraphConceptsConfig",
126    "AiKnowledgeBaseGraphConfig",
127    "AiKnowledgeBaseGraphFilter",
128    "AiKnowledgeBaseGraphPathFacetConfig",
129    "AiKnowledgeBaseGraphSearchOptions",
130    "AiKnowledgeBaseMetadataField",
131    "AiPiiOptions",
132    # AI Query
133    "AiQueryAnalyzeResultsOptions",
134    "AiQueryCollectionsSelectionRunMode",
135    "AiQueryGenerateQueryOptions",
136    "AiQueryOptions",
137    "AiQuerySelectCollectionsOptions",
138    "AiQueryValidateWithAiOptions",
139    "AiSessionContext",
140    "AiStructuredOutputFormat",
141    "AudioClient",
142    "ContextRequest",
143    "CreatePdfDimensionsOptions",
144    "CreatePdfFormatOptions",
145    # Extraction
146    "CreatePdfOutputOptions",
147    "ExtractDataFromDocumentOptions",
148    "ExtractionClient",
149    "FileContextRequest",
150    "FluxOptions",
151    "GptImageOptions",
152    "GuardrailsOptions",
153    # Image
154    "ImageClient",
155    "ImageGenerateOptions",
156    "IntegrationEmbeddingModelSpec",
157    "IntegrationModelSpec",
158    "KnowledgeBaseClient",
159    "KnowledgeBaseGraphQueryOp",
160    "KnowledgeBaseSearchOptions",
161    # Matchmaking
162    "MatchmakingClient",
163    "MmCategory",
164    "MmEntity",
165    "MmFindMatchesOptions",
166    "MmListEntitiesOptions",
167    "ModelIdSpec",
168    "Squid",
169    "SquidHttpError",
170    "StableDiffusionOptions",
171    "TextContextRequest",
172    "UpsertAgentOptions",
173    "VectorDbType",
174    # Web
175    "WebAiSearchResponse",
176    "WebClient",
177    "WebShortUrlBulkResponse",
178    "WebShortUrlResponse",
179]
class AgentClient:
146class AgentClient:
147    """Operations on a single AI agent.
148
149    Provides methods for chatting with an agent, managing its configuration,
150    updating guardrails, and working with revisions.
151
152    Obtained via :meth:`AiClient.agent`.
153
154    Example::
155
156        agent = squid.ai().agent("my-agent")
157        response = await agent.ask("What is the weather?", options={"temperature": 0.7})
158        await agent.update_instructions("Always respond in haiku format.")
159    """
160
161    def __init__(self, http: HttpTransport, agent_id: str) -> None:
162        self._http = http
163        self._agent_id = agent_id
164
165    # --- Chat ---
166
167    async def ask(
168        self,
169        prompt: str,
170        options: AiChatOptions | None = None,
171    ) -> str:
172        """Ask the agent a question and get a text response.
173
174        Args:
175            prompt: The user's question or instruction.
176            options: Chat options controlling model, temperature, memory,
177                functions, guardrails, and more. See :class:`AiChatOptions`.
178
179        Returns:
180            The agent's response as a string.
181
182        Raises:
183            SquidHttpError: If the agent is not found or the request fails.
184
185        Example::
186
187            response = await agent.ask(
188                "Summarize this document",
189                options={
190                    "model": "gemini-3.7-flash",
191                    "temperature": 0.3,
192                    "memoryOptions": {"memoryId": "session-1", "memoryMode": "read-write"},
193                },
194            )
195        """
196        result = await self._http.post(
197            "squid-api/v1/ai/agent/ask",
198            {"agentId": self._agent_id, "prompt": prompt, "options": options or {}},
199        )
200        return result.get("responseString", "") if result else ""
201
202    async def ask_with_annotations(
203        self,
204        prompt: str,
205        options: AiChatOptions | None = None,
206    ) -> dict:
207        """Ask the agent and get a response with annotations.
208
209        Annotations include file references, citations, and other metadata
210        the agent may attach to its response.
211
212        Args:
213            prompt: The user's question or instruction.
214            options: Chat options. See :class:`AiChatOptions`.
215
216        Returns:
217            A dict with:
218                - ``responseString`` (str): The text response.
219                - ``annotations`` (dict): Annotation metadata keyed by ID.
220
221        Example::
222
223            result = await agent.ask_with_annotations("Find relevant docs")
224            print(result["responseString"])
225            for ann_id, ann in result.get("annotations", {}).items():
226                print(f"  Annotation: {ann}")
227        """
228        return await self._http.post(
229            "squid-api/v1/ai/agent/askWithAnnotations",
230            {"agentId": self._agent_id, "prompt": prompt, "options": options or {}},
231        )
232
233    # --- Management ---
234
235    async def get(self) -> dict | None:
236        """Get the agent's configuration.
237
238        Returns:
239            An ``AiAgent`` dict with keys: ``id``, ``createdAt``, ``updatedAt``,
240            ``description``, ``isPublic``, ``auditLog``, ``auditLogFullContext``,
241            ``options``, ``apiKey``.
242            Returns ``None`` if the agent does not exist.
243        """
244        return await self._http.get(f"squid-api/v1/ai/agent/get/{self._agent_id}")
245
246    async def upsert(
247        self,
248        *,
249        description: str | None = None,
250        is_public: bool | None = None,
251        audit_log: bool | None = None,
252        audit_log_full_context: bool | None = None,
253        api_key: str | None = None,
254        mcp_server: AiAgentMcpServerConfig | None = None,
255        options: AiChatOptions | None = None,
256    ) -> None:
257        """Create or update the agent.
258
259        If the agent does not exist, it is created. If it exists, the provided
260        fields are updated (fields set to ``None`` are left unchanged).
261
262        Args:
263            description: A description of the agent's purpose or capabilities.
264            is_public: Whether the agent is publicly accessible (default ``False``).
265            audit_log: Enable audit logging for the agent's activities.
266            audit_log_full_context: Record the full agent context (system
267                instructions and retrieved knowledge-base content) in the audit
268                log; requires ``audit_log``.
269            api_key: Optional API key used specifically for this agent.
270            mcp_server: Configuration for exposing the agent as an MCP server
271                at ``/mcp/<agentId>``. See :class:`AiAgentMcpServerConfig`.
272            options: Default chat options applied to every request unless
273                overridden per-call. See :class:`AiChatOptions`.
274
275        Example::
276
277            await agent.upsert(
278                description="Customer support agent",
279                options={"model": "gemini-3.7-flash", "temperature": 0.5},
280            )
281        """
282        body: dict[str, Any] = {"id": self._agent_id}
283        if description is not None:
284            body["description"] = description
285        if is_public is not None:
286            body["isPublic"] = is_public
287        if audit_log is not None:
288            body["auditLog"] = audit_log
289        if audit_log_full_context is not None:
290            body["auditLogFullContext"] = audit_log_full_context
291        if api_key is not None:
292            body["apiKey"] = api_key
293        if mcp_server is not None:
294            body["mcpServer"] = mcp_server
295        if options is not None:
296            body["options"] = options
297        await self._http.post("squid-api/v1/ai/agent/upsert", body)
298
299    async def delete(self) -> None:
300        """Delete the agent permanently."""
301        await self._http.post("squid-api/v1/ai/agent/delete", {"agentId": self._agent_id})
302
303    async def update_instructions(self, instructions: str) -> None:
304        """Update the agent's system instructions.
305
306        Args:
307            instructions: The new system prompt / instructions text.
308        """
309        await self._http.post(
310            "squid-api/v1/ai/agent/updateInstructions",
311            {"agentId": self._agent_id, "instructions": instructions},
312        )
313
314    async def update_model(self, model: AiChatModelSelection) -> None:
315        """Update the agent's default LLM model.
316
317        Args:
318            model: A model name string (e.g., ``'gemini-3.7-flash'``) or an
319                ``IntegrationModelSpec`` dict (``{'integrationId': str, 'model': str}``).
320        """
321        await self._http.post(
322            "squid-api/v1/ai/agent/updateModel",
323            {"agentId": self._agent_id, "model": model},
324        )
325
326    async def update_connected_agents(
327        self, connected_agents: list[AiConnectedAgentMetadata]
328    ) -> None:
329        """Update the list of connected agents.
330
331        Connected agents can be called by this agent during conversations.
332
333        Args:
334            connected_agents: List of ``{'agentId': str, 'description': str}`` dicts.
335        """
336        await self._http.post(
337            "squid-api/v1/ai/agent/updateConnectedAgents",
338            {"agentId": self._agent_id, "connectedAgents": connected_agents},
339        )
340
341    async def update_guardrails(self, guardrails: GuardrailsOptions) -> None:
342        """Update the agent's guardrail settings.
343
344        Args:
345            guardrails: A :class:`GuardrailsOptions` dict with optional keys:
346                ``custom``, ``disablePii``, ``professionalTone``,
347                ``offTopicAnswers``, ``disableProfanity``.
348
349        Example::
350
351            await agent.update_guardrails(
352                {
353                    "professionalTone": True,
354                    "disableProfanity": True,
355                }
356            )
357        """
358        await self._http.post(
359            "squid-api/v1/ai/agent/updateGuardrails",
360            {"agentId": self._agent_id, "guardrails": guardrails},
361        )
362
363    async def update_custom_guardrails(self, custom_guardrail: str) -> None:
364        """Update the custom guardrail instruction text.
365
366        Args:
367            custom_guardrail: Free-form guardrail instruction string.
368        """
369        await self._http.post(
370            "squid-api/v1/ai/agent/updateCustomGuardrails",
371            {"agentId": self._agent_id, "customGuardrail": custom_guardrail},
372        )
373
374    async def delete_custom_guardrails(self) -> None:
375        """Delete the custom guardrail, reverting to defaults."""
376        await self._http.post(
377            "squid-api/v1/ai/agent/deleteCustomGuardrails",
378            {"agentId": self._agent_id},
379        )
380
381    async def update_pii(self, pii: AiPiiOptions) -> None:
382        """Update the agent's PII screening, merging with its existing settings.
383
384        With ``onDetect`` set to ``"reject"`` the agent refuses any prompt carrying
385        PII before it reaches the model, so the prompt is never answered and never
386        stored. This is the inverse of ``GuardrailsOptions.disablePii``, which asks
387        the agent's own model not to emit PII in its answer.
388
389        Args:
390            pii: An :class:`AiPiiOptions` dict with optional keys: ``onDetect``,
391                ``entities``, ``customRules``, ``classifierModel``, ``allowList``.
392
393        Example::
394
395            await agent.update_pii(
396                {
397                    "onDetect": "reject",
398                    "customRules": ["internal case numbers like CASE-12345"],
399                }
400            )
401        """
402        agent = await self.get()
403        existing = (agent or {}).get("options", {}).get("pii", {})
404        merged = {"onDetect": "off", **existing, **pii}
405        await self._http.post(
406            "squid-api/v1/ai/agent/setAgentOptionInPath",
407            {"agentId": self._agent_id, "path": "pii", "value": merged},
408        )
409
410    # --- Revisions ---
411
412    async def list_revisions(self) -> list[dict]:
413        """List all revisions of this agent.
414
415        Returns:
416            A list of ``AiAgentRevision`` dicts, each containing:
417            ``agentId``, ``revisionNumber``, ``action``, ``createdAt``,
418            ``agentSnapshot``.
419        """
420        result = await self._http.get(f"squid-api/v1/ai/agent/revisions/{self._agent_id}")
421        return result.get("revisions", []) if result else []
422
423    async def restore_revision(self, revision_number: int) -> None:
424        """Restore the agent to a previous revision.
425
426        Args:
427            revision_number: The revision number to restore.
428        """
429        await self._http.post(
430            "squid-api/v1/ai/agent/restoreRevision",
431            {"agentId": self._agent_id, "revisionNumber": revision_number},
432        )
433
434    async def delete_revision(self, revision_number: int) -> None:
435        """Delete a specific revision.
436
437        Args:
438            revision_number: The revision number to delete.
439        """
440        await self._http.post(
441            "squid-api/v1/ai/agent/deleteRevision",
442            {"agentId": self._agent_id, "revisionNumber": revision_number},
443        )

Operations on a single AI agent.

Provides methods for chatting with an agent, managing its configuration, updating guardrails, and working with revisions.

Obtained via AiClient.agent().

Example::

agent = squid.ai().agent("my-agent")
response = await agent.ask("What is the weather?", options={"temperature": 0.7})
await agent.update_instructions("Always respond in haiku format.")
AgentClient(http: squidcloud.http.HttpTransport, agent_id: str)
161    def __init__(self, http: HttpTransport, agent_id: str) -> None:
162        self._http = http
163        self._agent_id = agent_id
async def ask( self, prompt: str, options: AiChatOptions | None = None) -> str:
167    async def ask(
168        self,
169        prompt: str,
170        options: AiChatOptions | None = None,
171    ) -> str:
172        """Ask the agent a question and get a text response.
173
174        Args:
175            prompt: The user's question or instruction.
176            options: Chat options controlling model, temperature, memory,
177                functions, guardrails, and more. See :class:`AiChatOptions`.
178
179        Returns:
180            The agent's response as a string.
181
182        Raises:
183            SquidHttpError: If the agent is not found or the request fails.
184
185        Example::
186
187            response = await agent.ask(
188                "Summarize this document",
189                options={
190                    "model": "gemini-3.7-flash",
191                    "temperature": 0.3,
192                    "memoryOptions": {"memoryId": "session-1", "memoryMode": "read-write"},
193                },
194            )
195        """
196        result = await self._http.post(
197            "squid-api/v1/ai/agent/ask",
198            {"agentId": self._agent_id, "prompt": prompt, "options": options or {}},
199        )
200        return result.get("responseString", "") if result else ""

Ask the agent a question and get a text response.

Arguments:
  • prompt: The user's question or instruction.
  • options: Chat options controlling model, temperature, memory, functions, guardrails, and more. See AiChatOptions.
Returns:

The agent's response as a string.

Raises:
  • SquidHttpError: If the agent is not found or the request fails.

Example::

response = await agent.ask(
    "Summarize this document",
    options={
        "model": "gemini-3.7-flash",
        "temperature": 0.3,
        "memoryOptions": {"memoryId": "session-1", "memoryMode": "read-write"},
    },
)
async def ask_with_annotations( self, prompt: str, options: AiChatOptions | None = None) -> dict:
202    async def ask_with_annotations(
203        self,
204        prompt: str,
205        options: AiChatOptions | None = None,
206    ) -> dict:
207        """Ask the agent and get a response with annotations.
208
209        Annotations include file references, citations, and other metadata
210        the agent may attach to its response.
211
212        Args:
213            prompt: The user's question or instruction.
214            options: Chat options. See :class:`AiChatOptions`.
215
216        Returns:
217            A dict with:
218                - ``responseString`` (str): The text response.
219                - ``annotations`` (dict): Annotation metadata keyed by ID.
220
221        Example::
222
223            result = await agent.ask_with_annotations("Find relevant docs")
224            print(result["responseString"])
225            for ann_id, ann in result.get("annotations", {}).items():
226                print(f"  Annotation: {ann}")
227        """
228        return await self._http.post(
229            "squid-api/v1/ai/agent/askWithAnnotations",
230            {"agentId": self._agent_id, "prompt": prompt, "options": options or {}},
231        )

Ask the agent and get a response with annotations.

Annotations include file references, citations, and other metadata the agent may attach to its response.

Arguments:
  • prompt: The user's question or instruction.
  • options: Chat options. See AiChatOptions.
Returns:

A dict with: - responseString (str): The text response. - annotations (dict): Annotation metadata keyed by ID.

Example::

result = await agent.ask_with_annotations("Find relevant docs")
print(result["responseString"])
for ann_id, ann in result.get("annotations", {}).items():
    print(f"  Annotation: {ann}")
async def get(self) -> dict | None:
235    async def get(self) -> dict | None:
236        """Get the agent's configuration.
237
238        Returns:
239            An ``AiAgent`` dict with keys: ``id``, ``createdAt``, ``updatedAt``,
240            ``description``, ``isPublic``, ``auditLog``, ``auditLogFullContext``,
241            ``options``, ``apiKey``.
242            Returns ``None`` if the agent does not exist.
243        """
244        return await self._http.get(f"squid-api/v1/ai/agent/get/{self._agent_id}")

Get the agent's configuration.

Returns:

An AiAgent dict with keys: id, createdAt, updatedAt, description, isPublic, auditLog, auditLogFullContext, options, apiKey. Returns None if the agent does not exist.

async def upsert( self, *, description: str | None = None, is_public: bool | None = None, audit_log: bool | None = None, audit_log_full_context: bool | None = None, api_key: str | None = None, mcp_server: AiAgentMcpServerConfig | None = None, options: AiChatOptions | None = None) -> None:
246    async def upsert(
247        self,
248        *,
249        description: str | None = None,
250        is_public: bool | None = None,
251        audit_log: bool | None = None,
252        audit_log_full_context: bool | None = None,
253        api_key: str | None = None,
254        mcp_server: AiAgentMcpServerConfig | None = None,
255        options: AiChatOptions | None = None,
256    ) -> None:
257        """Create or update the agent.
258
259        If the agent does not exist, it is created. If it exists, the provided
260        fields are updated (fields set to ``None`` are left unchanged).
261
262        Args:
263            description: A description of the agent's purpose or capabilities.
264            is_public: Whether the agent is publicly accessible (default ``False``).
265            audit_log: Enable audit logging for the agent's activities.
266            audit_log_full_context: Record the full agent context (system
267                instructions and retrieved knowledge-base content) in the audit
268                log; requires ``audit_log``.
269            api_key: Optional API key used specifically for this agent.
270            mcp_server: Configuration for exposing the agent as an MCP server
271                at ``/mcp/<agentId>``. See :class:`AiAgentMcpServerConfig`.
272            options: Default chat options applied to every request unless
273                overridden per-call. See :class:`AiChatOptions`.
274
275        Example::
276
277            await agent.upsert(
278                description="Customer support agent",
279                options={"model": "gemini-3.7-flash", "temperature": 0.5},
280            )
281        """
282        body: dict[str, Any] = {"id": self._agent_id}
283        if description is not None:
284            body["description"] = description
285        if is_public is not None:
286            body["isPublic"] = is_public
287        if audit_log is not None:
288            body["auditLog"] = audit_log
289        if audit_log_full_context is not None:
290            body["auditLogFullContext"] = audit_log_full_context
291        if api_key is not None:
292            body["apiKey"] = api_key
293        if mcp_server is not None:
294            body["mcpServer"] = mcp_server
295        if options is not None:
296            body["options"] = options
297        await self._http.post("squid-api/v1/ai/agent/upsert", body)

Create or update the agent.

If the agent does not exist, it is created. If it exists, the provided fields are updated (fields set to None are left unchanged).

Arguments:
  • description: A description of the agent's purpose or capabilities.
  • is_public: Whether the agent is publicly accessible (default False).
  • audit_log: Enable audit logging for the agent's activities.
  • audit_log_full_context: Record the full agent context (system instructions and retrieved knowledge-base content) in the audit log; requires audit_log.
  • api_key: Optional API key used specifically for this agent.
  • mcp_server: Configuration for exposing the agent as an MCP server at /mcp/<agentId>. See AiAgentMcpServerConfig.
  • options: Default chat options applied to every request unless overridden per-call. See AiChatOptions.

Example::

await agent.upsert(
    description="Customer support agent",
    options={"model": "gemini-3.7-flash", "temperature": 0.5},
)
async def delete(self) -> None:
299    async def delete(self) -> None:
300        """Delete the agent permanently."""
301        await self._http.post("squid-api/v1/ai/agent/delete", {"agentId": self._agent_id})

Delete the agent permanently.

async def update_instructions(self, instructions: str) -> None:
303    async def update_instructions(self, instructions: str) -> None:
304        """Update the agent's system instructions.
305
306        Args:
307            instructions: The new system prompt / instructions text.
308        """
309        await self._http.post(
310            "squid-api/v1/ai/agent/updateInstructions",
311            {"agentId": self._agent_id, "instructions": instructions},
312        )

Update the agent's system instructions.

Arguments:
  • instructions: The new system prompt / instructions text.
async def update_model(self, model: str | IntegrationModelSpec) -> None:
314    async def update_model(self, model: AiChatModelSelection) -> None:
315        """Update the agent's default LLM model.
316
317        Args:
318            model: A model name string (e.g., ``'gemini-3.7-flash'``) or an
319                ``IntegrationModelSpec`` dict (``{'integrationId': str, 'model': str}``).
320        """
321        await self._http.post(
322            "squid-api/v1/ai/agent/updateModel",
323            {"agentId": self._agent_id, "model": model},
324        )

Update the agent's default LLM model.

Arguments:
  • model: A model name string (e.g., 'gemini-3.7-flash') or an IntegrationModelSpec dict ({'integrationId': str, 'model': str}).
async def update_connected_agents( self, connected_agents: list[AiConnectedAgentMetadata]) -> None:
326    async def update_connected_agents(
327        self, connected_agents: list[AiConnectedAgentMetadata]
328    ) -> None:
329        """Update the list of connected agents.
330
331        Connected agents can be called by this agent during conversations.
332
333        Args:
334            connected_agents: List of ``{'agentId': str, 'description': str}`` dicts.
335        """
336        await self._http.post(
337            "squid-api/v1/ai/agent/updateConnectedAgents",
338            {"agentId": self._agent_id, "connectedAgents": connected_agents},
339        )

Update the list of connected agents.

Connected agents can be called by this agent during conversations.

Arguments:
  • connected_agents: List of {'agentId': str, 'description': str} dicts.
async def update_guardrails(self, guardrails: GuardrailsOptions) -> None:
341    async def update_guardrails(self, guardrails: GuardrailsOptions) -> None:
342        """Update the agent's guardrail settings.
343
344        Args:
345            guardrails: A :class:`GuardrailsOptions` dict with optional keys:
346                ``custom``, ``disablePii``, ``professionalTone``,
347                ``offTopicAnswers``, ``disableProfanity``.
348
349        Example::
350
351            await agent.update_guardrails(
352                {
353                    "professionalTone": True,
354                    "disableProfanity": True,
355                }
356            )
357        """
358        await self._http.post(
359            "squid-api/v1/ai/agent/updateGuardrails",
360            {"agentId": self._agent_id, "guardrails": guardrails},
361        )

Update the agent's guardrail settings.

Arguments:
  • guardrails: A GuardrailsOptions dict with optional keys: custom, disablePii, professionalTone, offTopicAnswers, disableProfanity.

Example::

await agent.update_guardrails(
    {
        "professionalTone": True,
        "disableProfanity": True,
    }
)
async def update_custom_guardrails(self, custom_guardrail: str) -> None:
363    async def update_custom_guardrails(self, custom_guardrail: str) -> None:
364        """Update the custom guardrail instruction text.
365
366        Args:
367            custom_guardrail: Free-form guardrail instruction string.
368        """
369        await self._http.post(
370            "squid-api/v1/ai/agent/updateCustomGuardrails",
371            {"agentId": self._agent_id, "customGuardrail": custom_guardrail},
372        )

Update the custom guardrail instruction text.

Arguments:
  • custom_guardrail: Free-form guardrail instruction string.
async def delete_custom_guardrails(self) -> None:
374    async def delete_custom_guardrails(self) -> None:
375        """Delete the custom guardrail, reverting to defaults."""
376        await self._http.post(
377            "squid-api/v1/ai/agent/deleteCustomGuardrails",
378            {"agentId": self._agent_id},
379        )

Delete the custom guardrail, reverting to defaults.

async def update_pii(self, pii: AiPiiOptions) -> None:
381    async def update_pii(self, pii: AiPiiOptions) -> None:
382        """Update the agent's PII screening, merging with its existing settings.
383
384        With ``onDetect`` set to ``"reject"`` the agent refuses any prompt carrying
385        PII before it reaches the model, so the prompt is never answered and never
386        stored. This is the inverse of ``GuardrailsOptions.disablePii``, which asks
387        the agent's own model not to emit PII in its answer.
388
389        Args:
390            pii: An :class:`AiPiiOptions` dict with optional keys: ``onDetect``,
391                ``entities``, ``customRules``, ``classifierModel``, ``allowList``.
392
393        Example::
394
395            await agent.update_pii(
396                {
397                    "onDetect": "reject",
398                    "customRules": ["internal case numbers like CASE-12345"],
399                }
400            )
401        """
402        agent = await self.get()
403        existing = (agent or {}).get("options", {}).get("pii", {})
404        merged = {"onDetect": "off", **existing, **pii}
405        await self._http.post(
406            "squid-api/v1/ai/agent/setAgentOptionInPath",
407            {"agentId": self._agent_id, "path": "pii", "value": merged},
408        )

Update the agent's PII screening, merging with its existing settings.

With onDetect set to "reject" the agent refuses any prompt carrying PII before it reaches the model, so the prompt is never answered and never stored. This is the inverse of GuardrailsOptions.disablePii, which asks the agent's own model not to emit PII in its answer.

Arguments:
  • pii: An AiPiiOptions dict with optional keys: onDetect, entities, customRules, classifierModel, allowList.

Example::

await agent.update_pii(
    {
        "onDetect": "reject",
        "customRules": ["internal case numbers like CASE-12345"],
    }
)
async def list_revisions(self) -> list[dict]:
412    async def list_revisions(self) -> list[dict]:
413        """List all revisions of this agent.
414
415        Returns:
416            A list of ``AiAgentRevision`` dicts, each containing:
417            ``agentId``, ``revisionNumber``, ``action``, ``createdAt``,
418            ``agentSnapshot``.
419        """
420        result = await self._http.get(f"squid-api/v1/ai/agent/revisions/{self._agent_id}")
421        return result.get("revisions", []) if result else []

List all revisions of this agent.

Returns:

A list of AiAgentRevision dicts, each containing: agentId, revisionNumber, action, createdAt, agentSnapshot.

async def restore_revision(self, revision_number: int) -> None:
423    async def restore_revision(self, revision_number: int) -> None:
424        """Restore the agent to a previous revision.
425
426        Args:
427            revision_number: The revision number to restore.
428        """
429        await self._http.post(
430            "squid-api/v1/ai/agent/restoreRevision",
431            {"agentId": self._agent_id, "revisionNumber": revision_number},
432        )

Restore the agent to a previous revision.

Arguments:
  • revision_number: The revision number to restore.
async def delete_revision(self, revision_number: int) -> None:
434    async def delete_revision(self, revision_number: int) -> None:
435        """Delete a specific revision.
436
437        Args:
438            revision_number: The revision number to delete.
439        """
440        await self._http.post(
441            "squid-api/v1/ai/agent/deleteRevision",
442            {"agentId": self._agent_id, "revisionNumber": revision_number},
443        )

Delete a specific revision.

Arguments:
  • revision_number: The revision number to delete.
class AiAgent(typing.TypedDict):
399class AiAgent(TypedDict, total=False):
400    """A definition of an AI agent with its properties and default chat options.
401
402    Returned by :meth:`AiClient.list_agents`.
403    """
404
405    id: str
406    """The unique identifier of the AI agent. Required."""
407    createdAt: str
408    """ISO 8601 timestamp of when the agent was created. Required."""
409    updatedAt: str
410    """ISO 8601 timestamp of when the agent was last updated. Required."""
411    description: str
412    """An optional description of the agent's purpose or capabilities."""
413    isPublic: bool
414    """Whether the agent is publicly accessible; defaults to False."""
415    auditLog: bool
416    """Whether audit logging is enabled for the agent's activities; defaults to False."""
417    auditLogFullContext: bool
418    """Whether the full agent context (system instructions and retrieved knowledge-base content) is recorded in the audit log; requires auditLog; defaults to False."""
419    options: AiChatOptions
420    """The agent's default chat options, overridable by the user during use. Required."""
421    apiKey: str
422    """Optional API key used specifically for operations on this agent."""
423    mcpServer: AiAgentMcpServerConfig
424    """Optional configuration for exposing the agent as an MCP server."""

A definition of an AI agent with its properties and default chat options.

Returned by AiClient.list_agents().

id: str

The unique identifier of the AI agent. Required.

createdAt: str

ISO 8601 timestamp of when the agent was created. Required.

updatedAt: str

ISO 8601 timestamp of when the agent was last updated. Required.

description: str

An optional description of the agent's purpose or capabilities.

isPublic: bool

Whether the agent is publicly accessible; defaults to False.

auditLog: bool

Whether audit logging is enabled for the agent's activities; defaults to False.

auditLogFullContext: bool

Whether the full agent context (system instructions and retrieved knowledge-base content) is recorded in the audit log; requires auditLog; defaults to False.

options: AiChatOptions

The agent's default chat options, overridable by the user during use. Required.

apiKey: str

Optional API key used specifically for operations on this agent.

Optional configuration for exposing the agent as an MCP server.

class AiAgentExecutionPlanOptions(typing.TypedDict):
142class AiAgentExecutionPlanOptions(TypedDict, total=False):
143    """Options for AI agent execution plan."""
144
145    enabled: bool

Options for AI agent execution plan.

enabled: bool
class AiAgentMcpServerConfig(typing.TypedDict):
365class AiAgentMcpServerConfig(TypedDict, total=False):
366    """Configuration for exposing an AI agent as an MCP server at ``/mcp/<agentId>``."""
367
368    enabled: bool
369    """Whether the agent is exposed as an MCP server. Required."""
370    description: str
371    """Description of the MCP server, served as the ``instructions`` field of the MCP initialize result."""
372    toolDescription: str
373    """Description of the MCP ``ask`` tool, exposed in the tools manifest."""
374    oauthIntegrationId: str
375    """ID of an auth integration used to OAuth-protect the MCP server."""
376    requireApiKey: bool
377    """Require the agent's API key as a bearer token; combinable with OAuth (either is accepted)."""

Configuration for exposing an AI agent as an MCP server at /mcp/<agentId>.

enabled: bool

Whether the agent is exposed as an MCP server. Required.

description: str

Description of the MCP server, served as the instructions field of the MCP initialize result.

toolDescription: str

Description of the MCP ask tool, exposed in the tools manifest.

oauthIntegrationId: str

ID of an auth integration used to OAuth-protect the MCP server.

requireApiKey: bool

Require the agent's API key as a bearer token; combinable with OAuth (either is accepted).

class AiAgentMemoryOptions(typing.TypedDict):
68class AiAgentMemoryOptions(TypedDict, total=False):
69    """Memory/session configuration for agent chat."""
70
71    memoryId: str
72    """Unique memory ID. Reuse to continue a conversation."""
73    memoryMode: AiMemoryMode
74    """How memory is used: 'read-write', 'read-only', 'write-only', 'disabled'."""

Memory/session configuration for agent chat.

memoryId: str

Unique memory ID. Reuse to continue a conversation.

memoryMode: Literal['read-write', 'read-only', 'write-only', 'disabled']

How memory is used: 'read-write', 'read-only', 'write-only', 'disabled'.

AiAgentResponseFormat = typing.Literal['text', 'json_object'] | AiStructuredOutputFormat
class AiAudioCreateSpeechOptions(typing.TypedDict):
182class AiAudioCreateSpeechOptions(TypedDict, total=False):
183    """Options for text-to-speech."""
184
185    modelName: str
186    """'tts-1' or 'tts-1-hd'."""
187    voice: str
188    """'alloy'|'ash'|'ballad'|'coral'|'echo'|'fable'|'onyx'|'nova'|'sage'|'shimmer'|'verse'."""
189    responseFormat: str
190    """Audio output format."""
191    instructions: str
192    """Extra instructions for speech generation."""
193    speed: float
194    """Speech speed."""

Options for text-to-speech.

modelName: str

'tts-1' or 'tts-1-hd'.

voice: str

'alloy'|'ash'|'ballad'|'coral'|'echo'|'fable'|'onyx'|'nova'|'sage'|'shimmer'|'verse'.

responseFormat: str

Audio output format.

instructions: str

Extra instructions for speech generation.

speed: float

Speech speed.

AiChatModelSelection = str | IntegrationModelSpec
class AiChatOptions(typing.TypedDict):
197class AiChatOptions(TypedDict, total=False):
198    """Full chat options for AI agent ask/chat operations.
199
200    Mirrors BaseAiChatOptions from the TypeScript SDK.
201    All fields are optional.
202    """
203
204    model: AiChatModelSelection
205    """LLM model to use. String name or IntegrationModelSpec."""
206    maxTokens: int
207    """Max input tokens for the AI model."""
208    maxOutputTokens: int
209    """Max output tokens from the AI model."""
210    temperature: float
211    """Sampling temperature (default 0.5)."""
212    instructions: str
213    """Extra instructions to include with the prompt."""
214    functions: list[str]
215    """AI function IDs to expose to the agent."""
216    memoryOptions: AiAgentMemoryOptions
217    """Memory/session configuration."""
218    responseFormat: AiAgentResponseFormat
219    """Response format: 'text', 'json_object', or structured output."""
220    includeReference: bool
221    """Include source references from context."""
222    citation: bool
223    """Cite the sources behind the agent's statements."""
224    allowSourceDownloads: bool
225    """Allow citation links to the original files. Read from the stored agent only; ignored when passed with a request."""
226    smoothTyping: bool
227    """Smooth typing effect for UI display (default true)."""
228    disableContext: bool
229    """Disable the whole context for this request."""
230    enablePromptRewriteForRag: bool
231    """Rewrite prompt for RAG (default false)."""
232    agentContext: dict[str, Any]
233    """Global context passed to agent and all AI functions."""
234    connectedAgents: list[AiConnectedAgentMetadata]
235    """Connected agents that can be called."""
236    connectedIntegrations: list[AiConnectedIntegrationMetadata]
237    """Connected integrations."""
238    connectedKnowledgeBases: list[AiConnectedKnowledgeBaseMetadata]
239    """Connected knowledge bases."""
240    guardrails: GuardrailsOptions
241    """Guardrail options."""
242    pii: AiPiiOptions
243    """PII screening. Read from the stored agent only; ignored when passed with a request."""
244    contextMetadataFilterForKnowledgeBase: dict[str, Any]
245    """Metadata filters per knowledge base ID."""
246    voiceOptions: AiAudioCreateSpeechOptions
247    """Options for voice response."""
248    quotas: AiChatPromptQuotas
249    """Budget for nested AI calls."""
250    executionPlanOptions: AiAgentExecutionPlanOptions
251    """Execution plan options."""
252    fileUrls: list[AiFileUrl]
253    """File URLs to include in context."""
254    fileIds: list[str]
255    """File IDs from AI provider's Files API."""
256    reasoningEffort: AiReasoningEffort
257    """Reasoning effort level."""
258    verbosity: AiVerbosityLevel
259    """Response verbosity level."""
260    useCodeInterpreter: Literal["none", "llm"]
261    """Enable LLM's built-in code interpreter."""
262    rerankProvider: AiRerankProvider
263    """Reranker provider for context (default 'cohere')."""
264    includeMetadata: bool
265    """Include metadata in context (deprecated)."""
266    timeoutMs: int
267    """Request timeout in milliseconds (default 240000)."""

Full chat options for AI agent ask/chat operations.

Mirrors BaseAiChatOptions from the TypeScript SDK. All fields are optional.

model: str | IntegrationModelSpec

LLM model to use. String name or IntegrationModelSpec.

maxTokens: int

Max input tokens for the AI model.

maxOutputTokens: int

Max output tokens from the AI model.

temperature: float

Sampling temperature (default 0.5).

instructions: str

Extra instructions to include with the prompt.

functions: list[str]

AI function IDs to expose to the agent.

memoryOptions: AiAgentMemoryOptions

Memory/session configuration.

responseFormat: Literal['text', 'json_object'] | AiStructuredOutputFormat

Response format: 'text', 'json_object', or structured output.

includeReference: bool

Include source references from context.

citation: bool

Cite the sources behind the agent's statements.

allowSourceDownloads: bool

Allow citation links to the original files. Read from the stored agent only; ignored when passed with a request.

smoothTyping: bool

Smooth typing effect for UI display (default true).

disableContext: bool

Disable the whole context for this request.

enablePromptRewriteForRag: bool

Rewrite prompt for RAG (default false).

agentContext: dict[str, typing.Any]

Global context passed to agent and all AI functions.

connectedAgents: list[AiConnectedAgentMetadata]

Connected agents that can be called.

connectedIntegrations: list[AiConnectedIntegrationMetadata]

Connected integrations.

connectedKnowledgeBases: list[AiConnectedKnowledgeBaseMetadata]

Connected knowledge bases.

guardrails: GuardrailsOptions

Guardrail options.

PII screening. Read from the stored agent only; ignored when passed with a request.

contextMetadataFilterForKnowledgeBase: dict[str, typing.Any]

Metadata filters per knowledge base ID.

Options for voice response.

Budget for nested AI calls.

executionPlanOptions: AiAgentExecutionPlanOptions

Execution plan options.

fileUrls: list[AiFileUrl]

File URLs to include in context.

fileIds: list[str]

File IDs from AI provider's Files API.

reasoningEffort: Literal['minimal', 'low', 'medium', 'high', 'xhigh', 'max'] | str

Reasoning effort level.

verbosity: Literal['low', 'medium', 'high']

Response verbosity level.

useCodeInterpreter: Literal['none', 'llm']

Enable LLM's built-in code interpreter.

rerankProvider: Literal['cohere']

Reranker provider for context (default 'cohere').

includeMetadata: bool

Include metadata in context (deprecated).

timeoutMs: int

Request timeout in milliseconds (default 240000).

class AiChatPromptQuotas(typing.TypedDict):
136class AiChatPromptQuotas(TypedDict, total=False):
137    """Budget for nested/recursive AI chat calls."""
138
139    maxNestedCalls: int

Budget for nested/recursive AI chat calls.

maxNestedCalls: int
class AiClient:
 37class AiClient:
 38    """Entry point for AI operations: agents, knowledge base, audio, image.
 39
 40    Obtained via :meth:`Squid.ai()`.
 41
 42    Example::
 43
 44        ai = squid.ai()
 45        agent = ai.agent("my-agent")
 46        kb = ai.knowledge_base("my-kb")
 47        image_url = await ai.image().generate("a cat in space")
 48    """
 49
 50    def __init__(self, http: HttpTransport) -> None:
 51        self._http = http
 52
 53    def agent(self, agent_id: str) -> AgentClient:
 54        """Get a client for a specific AI agent.
 55
 56        Args:
 57            agent_id: The unique agent identifier.
 58
 59        Returns:
 60            An :class:`AgentClient` bound to the given agent ID.
 61        """
 62        return AgentClient(self._http, agent_id)
 63
 64    def knowledge_base(self, knowledge_base_id: str) -> KnowledgeBaseClient:
 65        """Get a client for a specific knowledge base.
 66
 67        Args:
 68            knowledge_base_id: The unique knowledge base identifier.
 69
 70        Returns:
 71            A :class:`KnowledgeBaseClient` bound to the given knowledge base ID.
 72        """
 73        return KnowledgeBaseClient(self._http, knowledge_base_id)
 74
 75    def image(self) -> ImageClient:
 76        """Get a client for image generation and processing.
 77
 78        Returns:
 79            An :class:`ImageClient` instance.
 80        """
 81        return ImageClient(self._http)
 82
 83    def audio(self) -> AudioClient:
 84        """Get a client for audio transcription and speech synthesis.
 85
 86        Returns:
 87            An :class:`AudioClient` instance.
 88        """
 89        return AudioClient(self._http)
 90
 91    async def list_agents(self) -> list[AiAgent]:
 92        """List all AI agents defined for the application.
 93
 94        Returns:
 95            A list of ``AiAgent`` dicts. Empty list if no agents are defined.
 96        """
 97        result = await self._http.get("squid-api/v1/ai/agent/listAgents")
 98        return result.get("agents", []) if result else []
 99
100    async def list_knowledge_bases(self) -> list[AiKnowledgeBase]:
101        """List all AI knowledge bases defined for the application.
102
103        Returns:
104            A list of ``AiKnowledgeBase`` dicts. Empty list if no knowledge
105            bases are defined.
106        """
107        result = await self._http.get("squid-api/v1/ai/knowledge-base/listKnowledgeBases")
108        return result.get("knowledgeBases", []) if result else []
109
110    async def list_chat_models(self, include_deprecated: bool = False) -> list[ModelIdSpec]:
111        """List all AI chat models available to the application.
112
113        Includes both Squid-provided vendor models and any custom integration
114        models configured for the app.
115
116        Args:
117            include_deprecated: When True, deprecated vendor models are
118                included and marked with ``replacedBy``. Defaults to False.
119
120        Returns:
121            A list of ``ModelIdSpec`` dicts, each with ``modelId``, an optional
122            ``integrationId``, and a human-readable ``displayName``. Vendor
123            models also carry a ``description``, and deprecated vendor models a
124            ``replacedBy`` with the active model their calls are routed to.
125        """
126        params = {"includeDeprecated": "true"} if include_deprecated else None
127        result = await self._http.get("squid-api/v1/ai/settings/listChatModels", params=params)
128        return result.get("models", []) if result else []
129
130    async def list_functions(self) -> list[AiFunctionMetadata]:
131        """List all AI functions registered for the application's deployed bundle.
132
133        Returns:
134            A list of ``AiFunctionMetadata`` dicts. Empty list if no functions
135            are registered.
136        """
137        result = await self._http.get("squid-api/v1/ai/function/listFunctions")
138        return result.get("functions", []) if result else []

Entry point for AI operations: agents, knowledge base, audio, image.

Obtained via Squid.ai()().

Example::

ai = squid.ai()
agent = ai.agent("my-agent")
kb = ai.knowledge_base("my-kb")
image_url = await ai.image().generate("a cat in space")
AiClient(http: squidcloud.http.HttpTransport)
50    def __init__(self, http: HttpTransport) -> None:
51        self._http = http
def agent(self, agent_id: str) -> AgentClient:
53    def agent(self, agent_id: str) -> AgentClient:
54        """Get a client for a specific AI agent.
55
56        Args:
57            agent_id: The unique agent identifier.
58
59        Returns:
60            An :class:`AgentClient` bound to the given agent ID.
61        """
62        return AgentClient(self._http, agent_id)

Get a client for a specific AI agent.

Arguments:
  • agent_id: The unique agent identifier.
Returns:

An AgentClient bound to the given agent ID.

def knowledge_base(self, knowledge_base_id: str) -> KnowledgeBaseClient:
64    def knowledge_base(self, knowledge_base_id: str) -> KnowledgeBaseClient:
65        """Get a client for a specific knowledge base.
66
67        Args:
68            knowledge_base_id: The unique knowledge base identifier.
69
70        Returns:
71            A :class:`KnowledgeBaseClient` bound to the given knowledge base ID.
72        """
73        return KnowledgeBaseClient(self._http, knowledge_base_id)

Get a client for a specific knowledge base.

Arguments:
  • knowledge_base_id: The unique knowledge base identifier.
Returns:

A KnowledgeBaseClient bound to the given knowledge base ID.

def image(self) -> ImageClient:
75    def image(self) -> ImageClient:
76        """Get a client for image generation and processing.
77
78        Returns:
79            An :class:`ImageClient` instance.
80        """
81        return ImageClient(self._http)

Get a client for image generation and processing.

Returns:

An ImageClient instance.

def audio(self) -> AudioClient:
83    def audio(self) -> AudioClient:
84        """Get a client for audio transcription and speech synthesis.
85
86        Returns:
87            An :class:`AudioClient` instance.
88        """
89        return AudioClient(self._http)

Get a client for audio transcription and speech synthesis.

Returns:

An AudioClient instance.

async def list_agents(self) -> list[AiAgent]:
91    async def list_agents(self) -> list[AiAgent]:
92        """List all AI agents defined for the application.
93
94        Returns:
95            A list of ``AiAgent`` dicts. Empty list if no agents are defined.
96        """
97        result = await self._http.get("squid-api/v1/ai/agent/listAgents")
98        return result.get("agents", []) if result else []

List all AI agents defined for the application.

Returns:

A list of AiAgent dicts. Empty list if no agents are defined.

async def list_knowledge_bases(self) -> list[AiKnowledgeBase]:
100    async def list_knowledge_bases(self) -> list[AiKnowledgeBase]:
101        """List all AI knowledge bases defined for the application.
102
103        Returns:
104            A list of ``AiKnowledgeBase`` dicts. Empty list if no knowledge
105            bases are defined.
106        """
107        result = await self._http.get("squid-api/v1/ai/knowledge-base/listKnowledgeBases")
108        return result.get("knowledgeBases", []) if result else []

List all AI knowledge bases defined for the application.

Returns:

A list of AiKnowledgeBase dicts. Empty list if no knowledge bases are defined.

async def list_chat_models( self, include_deprecated: bool = False) -> list[ModelIdSpec]:
110    async def list_chat_models(self, include_deprecated: bool = False) -> list[ModelIdSpec]:
111        """List all AI chat models available to the application.
112
113        Includes both Squid-provided vendor models and any custom integration
114        models configured for the app.
115
116        Args:
117            include_deprecated: When True, deprecated vendor models are
118                included and marked with ``replacedBy``. Defaults to False.
119
120        Returns:
121            A list of ``ModelIdSpec`` dicts, each with ``modelId``, an optional
122            ``integrationId``, and a human-readable ``displayName``. Vendor
123            models also carry a ``description``, and deprecated vendor models a
124            ``replacedBy`` with the active model their calls are routed to.
125        """
126        params = {"includeDeprecated": "true"} if include_deprecated else None
127        result = await self._http.get("squid-api/v1/ai/settings/listChatModels", params=params)
128        return result.get("models", []) if result else []

List all AI chat models available to the application.

Includes both Squid-provided vendor models and any custom integration models configured for the app.

Arguments:
  • include_deprecated: When True, deprecated vendor models are included and marked with replacedBy. Defaults to False.
Returns:

A list of ModelIdSpec dicts, each with modelId, an optional integrationId, and a human-readable displayName. Vendor models also carry a description, and deprecated vendor models a replacedBy with the active model their calls are routed to.

async def list_functions(self) -> list[AiFunctionMetadata]:
130    async def list_functions(self) -> list[AiFunctionMetadata]:
131        """List all AI functions registered for the application's deployed bundle.
132
133        Returns:
134            A list of ``AiFunctionMetadata`` dicts. Empty list if no functions
135            are registered.
136        """
137        result = await self._http.get("squid-api/v1/ai/function/listFunctions")
138        return result.get("functions", []) if result else []

List all AI functions registered for the application's deployed bundle.

Returns:

A list of AiFunctionMetadata dicts. Empty list if no functions are registered.

class AiConnectedAgentMetadata(typing.TypedDict):
77class AiConnectedAgentMetadata(TypedDict):
78    """Metadata for a connected agent."""
79
80    agentId: str
81    description: str

Metadata for a connected agent.

agentId: str
description: str
class AiConnectedIntegrationMetadata(typing.TypedDict):
 84class AiConnectedIntegrationMetadata(TypedDict, total=False):
 85    """Metadata for a connected integration.
 86
 87    ``integrationId`` and ``integrationType`` are required by the platform API;
 88    the remaining fields are optional.
 89    """
 90
 91    integrationId: str
 92    """The ID of the connected integration. Required."""
 93    integrationType: str
 94    """The integration type, e.g. 'hubspot', 'slack', 'api'. Required."""
 95    description: str
 96    """Optional description used as the AI function description for the parent agent."""
 97    instructions: str
 98    """Optional instructions for the connected integration agent, overriding the default."""
 99    functionsToUse: list[str]
100    """AI function IDs the agent may use. Omit for all functions; [] for none."""
101    options: dict[str, Any]
102    """Additional integration options interpreted by Squid Core or connector AI functions."""
103    connectedAsMcp: bool
104    """Treat this integration as an MCP server (API integrations with exposeAsMcpServer)."""

Metadata for a connected integration.

integrationId and integrationType are required by the platform API; the remaining fields are optional.

integrationId: str

The ID of the connected integration. Required.

integrationType: str

The integration type, e.g. 'hubspot', 'slack', 'api'. Required.

description: str

Optional description used as the AI function description for the parent agent.

instructions: str

Optional instructions for the connected integration agent, overriding the default.

functionsToUse: list[str]

AI function IDs the agent may use. Omit for all functions; [] for none.

options: dict[str, typing.Any]

Additional integration options interpreted by Squid Core or connector AI functions.

connectedAsMcp: bool

Treat this integration as an MCP server (API integrations with exposeAsMcpServer).

class AiConnectedKnowledgeBaseMetadata(typing.TypedDict):
107class AiConnectedKnowledgeBaseMetadata(TypedDict, total=False):
108    """Metadata for a connected knowledge base."""
109
110    knowledgeBaseId: str
111    description: str
112    includeMetadata: bool

Metadata for a connected knowledge base.

knowledgeBaseId: str
description: str
includeMetadata: bool
class AiContextFileOptions(typing.TypedDict):
578class AiContextFileOptions(TypedDict, total=False):
579    """Options for file context processing."""
580
581    chunkOverlap: int
582    ragType: str

Options for file context processing.

chunkOverlap: int
ragType: str
class AiContextTextOptions(typing.TypedDict):
558class AiContextTextOptions(TypedDict, total=False):
559    """Options for text context processing."""
560
561    chunkOverlap: int
562    """Amount of chunk overlap in characters."""
563    ragType: str
564    """The type of RAG to use."""

Options for text context processing.

chunkOverlap: int

Amount of chunk overlap in characters.

ragType: str

The type of RAG to use.

AiEmbeddingsModelSelection = str | IntegrationEmbeddingModelSpec
class AiFileUrl(typing.TypedDict):
115class AiFileUrl(TypedDict, total=False):
116    """File URL to include in chat context."""
117
118    id: str
119    type: str
120    purpose: str
121    url: str
122    description: str
123    fileName: str

File URL to include in chat context.

id: str
type: str
purpose: str
url: str
description: str
fileName: str
class AiFunctionAttributes(typing.TypedDict):
696class AiFunctionAttributes(TypedDict, total=False):
697    """Additional optional readonly metadata for an AI function."""
698
699    integrationType: list[str]
700    """Types of integration this function is used for. Functions with a defined
701    'integrationType' require 'integrationId' to be passed as part of the function context."""

Additional optional readonly metadata for an AI function.

integrationType: list[str]

Types of integration this function is used for. Functions with a defined 'integrationType' require 'integrationId' to be passed as part of the function context.

class AiFunctionMetadata(typing.TypedDict):
704class AiFunctionMetadata(TypedDict, total=False):
705    """Metadata describing an AI function available in the application.
706
707    Returned by :meth:`AiClient.list_functions`.
708    """
709
710    serviceFunction: str
711    """The fully qualified name of the function ('ServiceName:functionName'). Required."""
712    description: str
713    """Description of what the function does."""
714    promptId: str
715    """Opaque ID of a registered prompt that supplies this function's description;
716    resolved server-side."""
717    params: list[AiFunctionParam]
718    """Parameters that the function accepts. Required."""
719    attributes: AiFunctionAttributes
720    """Additional attributes for the function."""
721    categories: list[str]
722    """Categories this function belongs to."""
723    internal: bool
724    """Whether this function is internal and not meant for direct use."""

Metadata describing an AI function available in the application.

Returned by AiClient.list_functions().

serviceFunction: str

The fully qualified name of the function ('ServiceName:functionName'). Required.

description: str

Description of what the function does.

promptId: str

Opaque ID of a registered prompt that supplies this function's description; resolved server-side.

params: list[AiFunctionParam]

Parameters that the function accepts. Required.

attributes: AiFunctionAttributes

Additional attributes for the function.

categories: list[str]

Categories this function belongs to.

internal: bool

Whether this function is internal and not meant for direct use.

class AiFunctionParam(typing.TypedDict):
681class AiFunctionParam(TypedDict, total=False):
682    """Defines the structure of a parameter for an AI function."""
683
684    name: str
685    """Name of the parameter. Required."""
686    description: str
687    """Description of the parameter's purpose. Required."""
688    type: AiFunctionParamType
689    """Data type of the parameter. Required."""
690    required: bool
691    """Indicates if the parameter is mandatory. Required."""
692    enum: list[str]
693    """List of possible values for the parameter, if applicable."""

Defines the structure of a parameter for an AI function.

name: str

Name of the parameter. Required.

description: str

Description of the parameter's purpose. Required.

type: Literal['string', 'number', 'boolean', 'date', 'files']

Data type of the parameter. Required.

required: bool

Indicates if the parameter is mandatory. Required.

enum: list[str]

List of possible values for the parameter, if applicable.

class AiKnowledgeBase(typing.TypedDict):
529class AiKnowledgeBase(TypedDict, total=False):
530    """An AI knowledge base that can be attached to an AI agent.
531
532    Returned by :meth:`AiClient.list_knowledge_bases`.
533    """
534
535    id: str
536    """The unique identifier of the knowledge base. Required."""
537    appId: str
538    """The app ID that the knowledge base belongs to. Required."""
539    description: str
540    """The user's description of the knowledge base. Required."""
541    metadataFields: list[AiKnowledgeBaseMetadataField]
542    """Predefined metadata fields that can be used for filtering. Required."""
543    embeddingModel: AiEmbeddingsModelSelection
544    """The embedding model used by this knowledge base. Required."""
545    chatModel: AiChatModelSelection
546    """The model used when asking questions of this knowledge base. Required."""
547    vectorDbType: VectorDbType
548    """The vector store backend the knowledge base reads/writes from. Set at creation
549    and immutable thereafter. Absent on older records."""
550    graphRag: AiKnowledgeBaseGraphConfig
551    """Opt-in GraphRAG configuration. Only honored for ``vectorDbType: 'mongoAtlas'``
552    knowledge bases; enables per-chunk entity/relationship extraction at ingest and
553    ``searchMode: 'graph'`` at query time."""
554    updatedAt: str
555    """ISO 8601 timestamp of when the knowledge base was last updated. Required."""

An AI knowledge base that can be attached to an AI agent.

Returned by AiClient.list_knowledge_bases().

id: str

The unique identifier of the knowledge base. Required.

appId: str

The app ID that the knowledge base belongs to. Required.

description: str

The user's description of the knowledge base. Required.

metadataFields: list[AiKnowledgeBaseMetadataField]

Predefined metadata fields that can be used for filtering. Required.

embeddingModel: str | IntegrationEmbeddingModelSpec

The embedding model used by this knowledge base. Required.

chatModel: str | IntegrationModelSpec

The model used when asking questions of this knowledge base. Required.

vectorDbType: Literal['postgres', 'mongoAtlas']

The vector store backend the knowledge base reads/writes from. Set at creation and immutable thereafter. Absent on older records.

Opt-in GraphRAG configuration. Only honored for vectorDbType: 'mongoAtlas' knowledge bases; enables per-chunk entity/relationship extraction at ingest and searchMode: 'graph' at query time.

updatedAt: str

ISO 8601 timestamp of when the knowledge base was last updated. Required.

class AiKnowledgeBaseGraphConceptsConfig(typing.TypedDict):
482class AiKnowledgeBaseGraphConceptsConfig(TypedDict, total=False):
483    """Configuration of the graph's concept layer (facet taxonomies)."""
484
485    facets: Union[list[str], Literal["auto"]]
486    """Which metadata fields become value facets. ``'auto'`` (the default) profiles the KB's
487    context metadata and selects the categorical fields; an explicit list overrides
488    auto-selection; an empty list disables value facets."""
489    pathFacets: list[AiKnowledgeBaseGraphPathFacetConfig]
490    """Explicit path facets, e.g. ``[{'field': 'folderPath', 'type': 'path'}]``. A path facet
491    always builds when its field has values, independent of ``facets``."""

Configuration of the graph's concept layer (facet taxonomies).

facets: list[str] | Literal['auto']

Which metadata fields become value facets. 'auto' (the default) profiles the KB's context metadata and selects the categorical fields; an explicit list overrides auto-selection; an empty list disables value facets.

Explicit path facets, e.g. [{'field': 'folderPath', 'type': 'path'}]. A path facet always builds when its field has values, independent of facets.

class AiKnowledgeBaseGraphConfig(squidcloud.types._AiKnowledgeBaseGraphConfigRequired):
506class AiKnowledgeBaseGraphConfig(_AiKnowledgeBaseGraphConfigRequired, total=False):
507    """Per-knowledge-base GraphRAG configuration.
508
509    Opt-in and mutable (unlike ``embeddingModel``/``vectorDbType``); only honored for
510    ``vectorDbType: 'mongoAtlas'`` knowledge bases. Enabling it on a knowledge base that
511    already has content backfills the graph automatically once the KB goes quiet.
512
513    On upsert the supplied value replaces the stored config rather than merging into it,
514    so include every key that should remain set.
515    """
516
517    extractionModel: AiChatModelSelection
518    """Chat model used for per-chunk entity/relationship extraction. Defaults to the server's
519    graph model."""
520    entityTypes: list[str]
521    """Optional domain taxonomy hint (entity types) injected into the extraction prompt."""
522    autoBuildDebounceMs: int
523    """Quiet window (milliseconds) after the last graph activity before the sweep auto-builds
524    the structure. Must be a positive integer. Defaults to the server's window (5 minutes)."""
525    concepts: AiKnowledgeBaseGraphConceptsConfig
526    """Concept-layer (facet taxonomy) configuration. Omitted means ``facets: 'auto'``."""

Per-knowledge-base GraphRAG configuration.

Opt-in and mutable (unlike embeddingModel/vectorDbType); only honored for vectorDbType: 'mongoAtlas' knowledge bases. Enabling it on a knowledge base that already has content backfills the graph automatically once the KB goes quiet.

On upsert the supplied value replaces the stored config rather than merging into it, so include every key that should remain set.

extractionModel: str | IntegrationModelSpec

Chat model used for per-chunk entity/relationship extraction. Defaults to the server's graph model.

entityTypes: list[str]

Optional domain taxonomy hint (entity types) injected into the extraction prompt.

autoBuildDebounceMs: int

Quiet window (milliseconds) after the last graph activity before the sweep auto-builds the structure. Must be a positive integer. Defaults to the server's window (5 minutes).

Concept-layer (facet taxonomy) configuration. Omitted means facets: 'auto'.

class AiKnowledgeBaseGraphFilter(typing.TypedDict):
622class AiKnowledgeBaseGraphFilter(TypedDict):
623    """Graph scope for a knowledge-base search: restricts results to the documents under one
624    concept of the KB's graph. Composes with every ``searchMode``. Requires ``graphRag.enabled``."""
625
626    underConcept: str
627    """The concept to scope to: a facet nodeId (``facet_…`` — exact) or a concept name,
628    resolved server-side (exact, then alias, then similarity). An unresolvable ref fails with
629    ``CONCEPT_NOT_FOUND`` and the nearest matching concept names."""

Graph scope for a knowledge-base search: restricts results to the documents under one concept of the KB's graph. Composes with every searchMode. Requires graphRag.enabled.

underConcept: str

The concept to scope to: a facet nodeId (facet_… — exact) or a concept name, resolved server-side (exact, then alias, then similarity). An unresolvable ref fails with CONCEPT_NOT_FOUND and the nearest matching concept names.

class AiKnowledgeBaseGraphPathFacetConfig(squidcloud.types._AiKnowledgeBaseGraphPathFacetConfigRequired):
473class AiKnowledgeBaseGraphPathFacetConfig(
474    _AiKnowledgeBaseGraphPathFacetConfigRequired, total=False
475):
476    """A path facet: a deterministic tree built by splitting a hierarchical path field."""
477
478    separator: str
479    """Path segment separator. Defaults to ``'/'``."""

A path facet: a deterministic tree built by splitting a hierarchical path field.

separator: str

Path segment separator. Defaults to '/'.

class AiKnowledgeBaseGraphSearchOptions(typing.TypedDict):
608class AiKnowledgeBaseGraphSearchOptions(TypedDict, total=False):
609    """Tuning for ``searchMode: 'graph'`` (GraphRAG) retrieval. Ignored for other search modes."""
610
611    seedLimit: int
612    """Entities seeded via vector search before graph expansion. Default 8, max 25."""
613    maxHops: int
614    """Number of hops to expand from each seed (traversal depth + 1). Default 2, max 3."""
615    includeGraphContext: bool
616    """When True, the server attaches the traversed subgraph to the search response as
617    ``graphContext``. Default False. Read it via
618    :meth:`~squidcloud.ai.KnowledgeBaseClient.search_with_graph_context`;
619    :meth:`~squidcloud.ai.KnowledgeBaseClient.search` returns only the chunks."""

Tuning for searchMode: 'graph' (GraphRAG) retrieval. Ignored for other search modes.

seedLimit: int

Entities seeded via vector search before graph expansion. Default 8, max 25.

maxHops: int

Number of hops to expand from each seed (traversal depth + 1). Default 2, max 3.

includeGraphContext: bool

When True, the server attaches the traversed subgraph to the search response as graphContext. Default False. Read it via ~squidcloud.ai.KnowledgeBaseClient.search_with_graph_context(); ~squidcloud.ai.KnowledgeBaseClient.search() returns only the chunks.

class AiKnowledgeBaseMetadataField(typing.TypedDict):
430class AiKnowledgeBaseMetadataField(TypedDict, total=False):
431    """Metadata field definition for a knowledge base."""
432
433    name: str
434    dataType: str
435    required: bool
436    description: str

Metadata field definition for a knowledge base.

name: str
dataType: str
required: bool
description: str
class AiPiiOptions(typing.TypedDict):
163class AiPiiOptions(TypedDict, total=False):
164    """Refuses prompts carrying PII before they reach the agent's model.
165
166    The inverse of GuardrailsOptions.disablePii, which asks the agent's own model
167    not to emit PII in its answer.
168    """
169
170    onDetect: str
171    """'reject' refuses a prompt carrying PII; 'off' (default) disables screening."""
172    entities: list[str]
173    """Entity kinds to screen for: 'email', 'phoneNumber', 'creditCard', 'ssn', 'iban', 'passport'."""
174    customRules: list[str]
175    """App-specific PII described in plain language, screened by classifierModel."""
176    classifierModel: AiChatModelSelection
177    """Model screening customRules. Defaults to 'gpt-5.6-luna'."""
178    allowList: list[str]
179    """Literal values that never count as PII."""

Refuses prompts carrying PII before they reach the agent's model.

The inverse of GuardrailsOptions.disablePii, which asks the agent's own model not to emit PII in its answer.

onDetect: str

'reject' refuses a prompt carrying PII; 'off' (default) disables screening.

entities: list[str]

Entity kinds to screen for: 'email', 'phoneNumber', 'creditCard', 'ssn', 'iban', 'passport'.

customRules: list[str]

App-specific PII described in plain language, screened by classifierModel.

classifierModel: str | IntegrationModelSpec

Model screening customRules. Defaults to 'gpt-5.6-luna'.

allowList: list[str]

Literal values that never count as PII.

class AiQueryAnalyzeResultsOptions(typing.TypedDict):
314class AiQueryAnalyzeResultsOptions(TypedDict, total=False):
315    """Options for the result-analysis stage of AI query."""
316
317    disabled: bool
318    """When true, skip analysis and return raw results only."""
319    enableCodeInterpreter: bool
320    """Enable code interpreter mode (default false)."""
321    aiOptions: AiChatOptions
322    """Customize AI agent behavior used by the stage."""
323    agentId: AiAgentId
324    """If set, use this agent to analyze results and produce the final answer."""

Options for the result-analysis stage of AI query.

disabled: bool

When true, skip analysis and return raw results only.

enableCodeInterpreter: bool

Enable code interpreter mode (default false).

aiOptions: AiChatOptions

Customize AI agent behavior used by the stage.

agentId: str

If set, use this agent to analyze results and produce the final answer.

AiQueryCollectionsSelectionRunMode = typing.Literal['default', 'force', 'disable']
class AiQueryGenerateQueryOptions(typing.TypedDict):
300class AiQueryGenerateQueryOptions(TypedDict, total=False):
301    """Options for the query-generation stage of AI query."""
302
303    aiOptions: AiChatOptions
304    """Customize AI agent behavior used by the stage."""
305    maxErrorCorrections: int
306    """Number of retries due to errors in a generated AI query (default 2)."""
307    agentId: AiAgentId
308    """If set, use this agent to generate the query."""
309    allowClarification: bool
310    """When true, allow the AI to ask a clarifying question instead of
311    generating a query for ambiguous prompts (default false)."""

Options for the query-generation stage of AI query.

aiOptions: AiChatOptions

Customize AI agent behavior used by the stage.

maxErrorCorrections: int

Number of retries due to errors in a generated AI query (default 2).

agentId: str

If set, use this agent to generate the query.

allowClarification: bool

When true, allow the AI to ask a clarifying question instead of generating a query for ambiguous prompts (default false).

class AiQueryOptions(typing.TypedDict):
336class AiQueryOptions(TypedDict, total=False):
337    """Options for configuring AI query execution.
338
339    Mirrors ``AiQueryOptions`` from the TypeScript SDK. All fields optional.
340    """
341
342    instructions: str
343    """Custom instructions applied to all stages unless overridden per-stage."""
344    enableRawResults: bool
345    """Enable raw results output."""
346    selectCollectionsOptions: AiQuerySelectCollectionsOptions
347    """Collection-selection stage options."""
348    generateQueryOptions: AiQueryGenerateQueryOptions
349    """Query-generation stage options."""
350    analyzeResultsOptions: AiQueryAnalyzeResultsOptions
351    """Result-analysis stage options."""
352    sessionContext: AiSessionContext
353    """Session information (``agentId`` may be omitted)."""
354    memoryOptions: AiAgentMemoryOptions
355    """Memory/session configuration."""
356    generateQueriesOnly: bool
357    """If true, return generated queries without executing or analyzing them."""
358    validateWithAiOptions: AiQueryValidateWithAiOptions
359    """Optional AI validation of generated queries."""

Options for configuring AI query execution.

Mirrors AiQueryOptions from the TypeScript SDK. All fields optional.

instructions: str

Custom instructions applied to all stages unless overridden per-stage.

enableRawResults: bool

Enable raw results output.

selectCollectionsOptions: AiQuerySelectCollectionsOptions

Collection-selection stage options.

generateQueryOptions: AiQueryGenerateQueryOptions

Query-generation stage options.

analyzeResultsOptions: AiQueryAnalyzeResultsOptions

Result-analysis stage options.

sessionContext: AiSessionContext

Session information (agentId may be omitted).

memoryOptions: AiAgentMemoryOptions

Memory/session configuration.

generateQueriesOnly: bool

If true, return generated queries without executing or analyzing them.

validateWithAiOptions: AiQueryValidateWithAiOptions

Optional AI validation of generated queries.

class AiQuerySelectCollectionsOptions(typing.TypedDict):
289class AiQuerySelectCollectionsOptions(TypedDict, total=False):
290    """Options for the collection-selection stage of AI query."""
291
292    collectionsToUse: list[str]
293    """Restrict query to these collections. Defaults to all collections."""
294    runMode: AiQueryCollectionsSelectionRunMode
295    """Stage behavior: 'default', 'force', or 'disable'."""
296    aiOptions: AiChatOptions
297    """Customize AI agent behavior used by the stage."""

Options for the collection-selection stage of AI query.

collectionsToUse: list[str]

Restrict query to these collections. Defaults to all collections.

runMode: Literal['default', 'force', 'disable']

Stage behavior: 'default', 'force', or 'disable'.

aiOptions: AiChatOptions

Customize AI agent behavior used by the stage.

class AiQueryValidateWithAiOptions(typing.TypedDict):
327class AiQueryValidateWithAiOptions(TypedDict, total=False):
328    """Options for AI-based validation of generated queries."""
329
330    enabled: bool
331    """Whether AI validation is enabled."""
332    aiOptions: AiChatOptions
333    """Defaults to the same model used for query generation."""

Options for AI-based validation of generated queries.

enabled: bool

Whether AI validation is enabled.

aiOptions: AiChatOptions

Defaults to the same model used for query generation.

class AiSessionContext(typing.TypedDict):
276class AiSessionContext(TypedDict, total=False):
277    """Session context for AI query execution.
278
279    Mirrors the TypeScript ``AiSessionContext`` type. All fields optional
280    here because the query endpoint accepts a partial context (``agentId``
281    may be omitted).
282    """
283
284    clientId: str
285    agentId: str
286    jobId: str

Session context for AI query execution.

Mirrors the TypeScript AiSessionContext type. All fields optional here because the query endpoint accepts a partial context (agentId may be omitted).

clientId: str
agentId: str
jobId: str
class AiStructuredOutputFormat(typing.TypedDict):
126class AiStructuredOutputFormat(TypedDict):
127    """Structured output format for JSON responses."""
128
129    type: Literal["json_schema"]
130    schema: dict[str, Any]

Structured output format for JSON responses.

type: Literal['json_schema']
schema: dict[str, typing.Any]
class AudioClient:
915class AudioClient:
916    """Audio transcription and speech synthesis.
917
918    Obtained via :meth:`AiClient.audio`.
919
920    Example::
921
922        text = await squid.ai().audio().transcribe(audio_bytes)
923        speech = await squid.ai().audio().create_speech("Hello!", options={"voice": "nova"})
924    """
925
926    def __init__(self, http: HttpTransport) -> None:
927        self._http = http
928
929    async def transcribe(
930        self,
931        audio_data: bytes,
932        filename: str = "audio.wav",
933        content_type: str = "audio/wav",
934        *,
935        options: dict[str, Any] | None = None,
936    ) -> str:
937        """Transcribe audio to text.
938
939        Args:
940            audio_data: The audio file content as bytes.
941            filename: The filename (used in the multipart upload).
942            content_type: The MIME type of the audio file.
943            options: Provider-specific transcription options.
944
945        Returns:
946            The transcribed text.
947        """
948        form_data: dict[str, str] = {
949            "optionsJson": json.dumps(options or {}),
950        }
951        result = await self._http.post_form(
952            "squid-api/v1/ai/audio/transcribe",
953            data=form_data,
954            files=[("file", (filename, audio_data, content_type))],
955        )
956        return result if isinstance(result, str) else str(result)
957
958    async def create_speech(
959        self,
960        text: str,
961        options: AiAudioCreateSpeechOptions,
962    ) -> bytes:
963        """Generate speech audio from text.
964
965        Args:
966            text: The text to convert to speech.
967            options: Speech generation options. See :class:`AiAudioCreateSpeechOptions`.
968                Required keys: ``modelName`` (e.g., ``'tts-1'``), ``voice``
969                (e.g., ``'nova'``, ``'alloy'``).
970
971        Returns:
972            Raw audio file bytes (e.g., MP3 format by default).
973
974        Example::
975
976            audio_data = (
977                await squid.ai()
978                .audio()
979                .create_speech(
980                    "Hello!",
981                    options={
982                        "modelName": "tts-1",
983                        "voice": "nova",
984                    },
985                )
986            )
987            with open("speech.mp3", "wb") as f:
988                f.write(audio_data)
989        """
990        return await self._http.post(
991            "squid-api/v1/ai/audio/createSpeech",
992            {"input": text, "options": options},
993        )

Audio transcription and speech synthesis.

Obtained via AiClient.audio().

Example::

text = await squid.ai().audio().transcribe(audio_bytes)
speech = await squid.ai().audio().create_speech("Hello!", options={"voice": "nova"})
AudioClient(http: squidcloud.http.HttpTransport)
926    def __init__(self, http: HttpTransport) -> None:
927        self._http = http
async def transcribe( self, audio_data: bytes, filename: str = 'audio.wav', content_type: str = 'audio/wav', *, options: dict[str, Any] | None = None) -> str:
929    async def transcribe(
930        self,
931        audio_data: bytes,
932        filename: str = "audio.wav",
933        content_type: str = "audio/wav",
934        *,
935        options: dict[str, Any] | None = None,
936    ) -> str:
937        """Transcribe audio to text.
938
939        Args:
940            audio_data: The audio file content as bytes.
941            filename: The filename (used in the multipart upload).
942            content_type: The MIME type of the audio file.
943            options: Provider-specific transcription options.
944
945        Returns:
946            The transcribed text.
947        """
948        form_data: dict[str, str] = {
949            "optionsJson": json.dumps(options or {}),
950        }
951        result = await self._http.post_form(
952            "squid-api/v1/ai/audio/transcribe",
953            data=form_data,
954            files=[("file", (filename, audio_data, content_type))],
955        )
956        return result if isinstance(result, str) else str(result)

Transcribe audio to text.

Arguments:
  • audio_data: The audio file content as bytes.
  • filename: The filename (used in the multipart upload).
  • content_type: The MIME type of the audio file.
  • options: Provider-specific transcription options.
Returns:

The transcribed text.

async def create_speech( self, text: str, options: AiAudioCreateSpeechOptions) -> bytes:
958    async def create_speech(
959        self,
960        text: str,
961        options: AiAudioCreateSpeechOptions,
962    ) -> bytes:
963        """Generate speech audio from text.
964
965        Args:
966            text: The text to convert to speech.
967            options: Speech generation options. See :class:`AiAudioCreateSpeechOptions`.
968                Required keys: ``modelName`` (e.g., ``'tts-1'``), ``voice``
969                (e.g., ``'nova'``, ``'alloy'``).
970
971        Returns:
972            Raw audio file bytes (e.g., MP3 format by default).
973
974        Example::
975
976            audio_data = (
977                await squid.ai()
978                .audio()
979                .create_speech(
980                    "Hello!",
981                    options={
982                        "modelName": "tts-1",
983                        "voice": "nova",
984                    },
985                )
986            )
987            with open("speech.mp3", "wb") as f:
988                f.write(audio_data)
989        """
990        return await self._http.post(
991            "squid-api/v1/ai/audio/createSpeech",
992            {"input": text, "options": options},
993        )

Generate speech audio from text.

Arguments:
  • text: The text to convert to speech.
  • options: Speech generation options. See AiAudioCreateSpeechOptions. Required keys: modelName (e.g., 'tts-1'), voice (e.g., 'nova', 'alloy').
Returns:

Raw audio file bytes (e.g., MP3 format by default).

Example::

audio_data = (
    await squid.ai()
    .audio()
    .create_speech(
        "Hello!",
        options={
            "modelName": "tts-1",
            "voice": "nova",
        },
    )
)
with open("speech.mp3", "wb") as f:
    f.write(audio_data)
class CreatePdfDimensionsOptions(typing.TypedDict):
833class CreatePdfDimensionsOptions(TypedDict):
834    """PDF output options by custom dimensions."""
835
836    type: Literal["dimensions"]
837    width: int
838    """Width in pixels."""
839    height: int
840    """Height in pixels."""

PDF output options by custom dimensions.

type: Literal['dimensions']
width: int

Width in pixels.

height: int

Height in pixels.

class CreatePdfFormatOptions(typing.TypedDict):
814class CreatePdfFormatOptions(TypedDict):
815    """PDF output options by format."""
816
817    type: Literal["format"]
818    format: Literal[
819        "letter",
820        "legal",
821        "tabloid",
822        "ledger",
823        "a0",
824        "a1",
825        "a2",
826        "a3",
827        "a4",
828        "a5",
829        "a6",
830    ]

PDF output options by format.

type: Literal['format']
format: Literal['letter', 'legal', 'tabloid', 'ledger', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6']
class ExtractDataFromDocumentOptions(typing.TypedDict):
846class ExtractDataFromDocumentOptions(TypedDict, total=False):
847    """Options for document data extraction."""
848
849    extractImages: bool
850    """Whether to extract embedded images. Defaults to True."""
851    imageMinSizePixels: int
852    """Minimum image size to extract."""
853    pageIndexes: list[int]
854    """Specific pages to extract (0-based)."""
855    preferredExtractionMethod: str
856    discardOriginalFile: bool

Options for document data extraction.

extractImages: bool

Whether to extract embedded images. Defaults to True.

imageMinSizePixels: int

Minimum image size to extract.

pageIndexes: list[int]

Specific pages to extract (0-based).

preferredExtractionMethod: str
discardOriginalFile: bool
class ExtractionClient:
17class ExtractionClient:
18    """Document extraction and PDF creation."""
19
20    def __init__(self, http: HttpTransport) -> None:
21        self._http = http
22
23    async def create_pdf_from_html(
24        self,
25        inner_html: str,
26        *,
27        title: str | None = None,
28        css_url: str | None = None,
29        output_options: CreatePdfOutputOptions | None = None,
30    ) -> dict:
31        """Create a PDF from HTML content.
32
33        Returns CreatePdfResponse with 'url' and 'fileName'.
34        """
35        body: dict[str, Any] = {"type": "html", "innerHtml": inner_html}
36        if title is not None:
37            body["title"] = title
38        if css_url is not None:
39            body["cssUrl"] = css_url
40        if output_options is not None:
41            body["outputOptions"] = output_options
42        return await self._http.post("squid-api/v1/extraction/createPdf", body)
43
44    async def create_pdf_from_url(
45        self,
46        url: str,
47        *,
48        title: str | None = None,
49        output_options: CreatePdfOutputOptions | None = None,
50    ) -> dict:
51        """Create a PDF from a URL.
52
53        Returns CreatePdfResponse with 'url' and 'fileName'.
54        """
55        body: dict[str, Any] = {"type": "url", "url": url}
56        if title is not None:
57            body["title"] = title
58        if output_options is not None:
59            body["outputOptions"] = output_options
60        return await self._http.post("squid-api/v1/extraction/createPdf", body)
61
62    async def extract_data_from_document_url(
63        self,
64        url: str,
65        options: ExtractDataFromDocumentOptions | None = None,
66    ) -> dict:
67        """Extract structured data from a document URL.
68
69        Returns ExtractDataFromDocumentResponse with 'pages' and optional 'longTermStoragePath'.
70        """
71        body: dict[str, Any] = {"url": url}
72        if options is not None:
73            body["options"] = options
74        return await self._http.post("squid-api/v1/extraction/extractDataFromDocumentUrl", body)
75
76    async def extract_data_from_document_file(
77        self,
78        file_data: bytes,
79        filename: str,
80        content_type: str = "application/pdf",
81        options: ExtractDataFromDocumentOptions | None = None,
82    ) -> dict:
83        """Extract structured data from a document file.
84
85        Returns ExtractDataFromDocumentResponse with 'pages' and optional 'longTermStoragePath'.
86        """
87        request: dict[str, Any] = {}
88        if options is not None:
89            request["options"] = options
90        form_data = {"request": json.dumps(request)}
91
92        return await self._http.post_form(
93            "squid-api/v1/extraction/extractDataFromDocumentFile",
94            data=form_data,
95            files=[("file", (filename, file_data, content_type))],
96        )

Document extraction and PDF creation.

ExtractionClient(http: squidcloud.http.HttpTransport)
20    def __init__(self, http: HttpTransport) -> None:
21        self._http = http
async def create_pdf_from_html( self, inner_html: str, *, title: str | None = None, css_url: str | None = None, output_options: CreatePdfFormatOptions | CreatePdfDimensionsOptions | None = None) -> dict:
23    async def create_pdf_from_html(
24        self,
25        inner_html: str,
26        *,
27        title: str | None = None,
28        css_url: str | None = None,
29        output_options: CreatePdfOutputOptions | None = None,
30    ) -> dict:
31        """Create a PDF from HTML content.
32
33        Returns CreatePdfResponse with 'url' and 'fileName'.
34        """
35        body: dict[str, Any] = {"type": "html", "innerHtml": inner_html}
36        if title is not None:
37            body["title"] = title
38        if css_url is not None:
39            body["cssUrl"] = css_url
40        if output_options is not None:
41            body["outputOptions"] = output_options
42        return await self._http.post("squid-api/v1/extraction/createPdf", body)

Create a PDF from HTML content.

Returns CreatePdfResponse with 'url' and 'fileName'.

async def create_pdf_from_url( self, url: str, *, title: str | None = None, output_options: CreatePdfFormatOptions | CreatePdfDimensionsOptions | None = None) -> dict:
44    async def create_pdf_from_url(
45        self,
46        url: str,
47        *,
48        title: str | None = None,
49        output_options: CreatePdfOutputOptions | None = None,
50    ) -> dict:
51        """Create a PDF from a URL.
52
53        Returns CreatePdfResponse with 'url' and 'fileName'.
54        """
55        body: dict[str, Any] = {"type": "url", "url": url}
56        if title is not None:
57            body["title"] = title
58        if output_options is not None:
59            body["outputOptions"] = output_options
60        return await self._http.post("squid-api/v1/extraction/createPdf", body)

Create a PDF from a URL.

Returns CreatePdfResponse with 'url' and 'fileName'.

async def extract_data_from_document_url( self, url: str, options: ExtractDataFromDocumentOptions | None = None) -> dict:
62    async def extract_data_from_document_url(
63        self,
64        url: str,
65        options: ExtractDataFromDocumentOptions | None = None,
66    ) -> dict:
67        """Extract structured data from a document URL.
68
69        Returns ExtractDataFromDocumentResponse with 'pages' and optional 'longTermStoragePath'.
70        """
71        body: dict[str, Any] = {"url": url}
72        if options is not None:
73            body["options"] = options
74        return await self._http.post("squid-api/v1/extraction/extractDataFromDocumentUrl", body)

Extract structured data from a document URL.

Returns ExtractDataFromDocumentResponse with 'pages' and optional 'longTermStoragePath'.

async def extract_data_from_document_file( self, file_data: bytes, filename: str, content_type: str = 'application/pdf', options: ExtractDataFromDocumentOptions | None = None) -> dict:
76    async def extract_data_from_document_file(
77        self,
78        file_data: bytes,
79        filename: str,
80        content_type: str = "application/pdf",
81        options: ExtractDataFromDocumentOptions | None = None,
82    ) -> dict:
83        """Extract structured data from a document file.
84
85        Returns ExtractDataFromDocumentResponse with 'pages' and optional 'longTermStoragePath'.
86        """
87        request: dict[str, Any] = {}
88        if options is not None:
89            request["options"] = options
90        form_data = {"request": json.dumps(request)}
91
92        return await self._http.post_form(
93            "squid-api/v1/extraction/extractDataFromDocumentFile",
94            data=form_data,
95            files=[("file", (filename, file_data, content_type))],
96        )

Extract structured data from a document file.

Returns ExtractDataFromDocumentResponse with 'pages' and optional 'longTermStoragePath'.

class FileContextRequest(typing.TypedDict):
585class FileContextRequest(TypedDict, total=False):
586    """Request to upsert a file context."""
587
588    contextId: str
589    type: Literal["file"]
590    metadata: dict[str, Any]
591    extractImages: bool
592    """Whether to extract and describe images in the file. Defaults to True.
593
594    This is the opposite of the text context default, which is False: a file's charts and
595    scanned pages carry content its text layer does not, while images referenced from pasted
596    markdown/HTML are usually layout chrome.
597    """
598    imageMinSizePixels: int
599    extractionModel: AiChatModelSelection
600    options: AiContextFileOptions
601    preferredExtractionMethod: str
602    discardOriginalFile: bool

Request to upsert a file context.

contextId: str
type: Literal['file']
metadata: dict[str, typing.Any]
extractImages: bool

Whether to extract and describe images in the file. Defaults to True.

This is the opposite of the text context default, which is False: a file's charts and scanned pages carry content its text layer does not, while images referenced from pasted markdown/HTML are usually layout chrome.

imageMinSizePixels: int
extractionModel: str | IntegrationModelSpec
preferredExtractionMethod: str
discardOriginalFile: bool
class FluxOptions(typing.TypedDict):
746class FluxOptions(TypedDict, total=False):
747    """Options for Flux image generation."""
748
749    modelName: Literal["flux-pro-1.1", "flux-kontext-pro"]
750    width: int
751    """Must be multiple of 32, min 256, max 1440."""
752    height: int
753    """Must be multiple of 32, min 256, max 1440."""
754    prompt_upsampling: bool
755    seed: int
756    safety_tolerance: int
757    """1 (strict) to 5 (permissive)."""

Options for Flux image generation.

modelName: Literal['flux-pro-1.1', 'flux-kontext-pro']
width: int

Must be multiple of 32, min 256, max 1440.

height: int

Must be multiple of 32, min 256, max 1440.

prompt_upsampling: bool
seed: int
safety_tolerance: int

1 (strict) to 5 (permissive).

class GptImageOptions(typing.TypedDict):
730class GptImageOptions(TypedDict, total=False):
731    """Options for OpenAI gpt-image-* family image generation."""
732
733    modelName: Literal[
734        "gpt-image-1",
735        "gpt-image-1-mini",
736        "gpt-image-1.5",
737        "gpt-image-2",
738        "gpt-image-2-2026-04-21",
739        "chatgpt-image-latest",
740    ]
741    quality: Literal["auto", "high", "medium", "low"]
742    size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"]
743    numberOfImagesToGenerate: int

Options for OpenAI gpt-image-* family image generation.

modelName: Literal['gpt-image-1', 'gpt-image-1-mini', 'gpt-image-1.5', 'gpt-image-2', 'gpt-image-2-2026-04-21', 'chatgpt-image-latest']
quality: Literal['auto', 'high', 'medium', 'low']
size: Literal['1024x1024', '1024x1536', '1536x1024', 'auto']
numberOfImagesToGenerate: int
class GuardrailsOptions(typing.TypedDict):
148class GuardrailsOptions(TypedDict, total=False):
149    """Guardrail options for agent responses."""
150
151    custom: str
152    """A custom guardrail instruction."""
153    disablePii: bool
154    """Disables personally identifiable information if true."""
155    professionalTone: bool
156    """Enforces a professional tone if true."""
157    offTopicAnswers: bool
158    """Prevents off-topic answers if true."""
159    disableProfanity: bool
160    """Disables profanity if true."""

Guardrail options for agent responses.

custom: str

A custom guardrail instruction.

disablePii: bool

Disables personally identifiable information if true.

professionalTone: bool

Enforces a professional tone if true.

offTopicAnswers: bool

Prevents off-topic answers if true.

disableProfanity: bool

Disables profanity if true.

class ImageClient:
841class ImageClient:
842    """Image generation and processing.
843
844    Supports DALL-E, Stable Diffusion Core, and Flux models.
845
846    Obtained via :meth:`AiClient.image`.
847
848    Example::
849
850        image_url = (
851            await squid.ai()
852            .image()
853            .generate(
854                "a cat astronaut on the moon",
855                options={"modelName": "gpt-image-1", "quality": "high"},
856            )
857        )
858    """
859
860    def __init__(self, http: HttpTransport) -> None:
861        self._http = http
862
863    async def generate(
864        self,
865        prompt: str,
866        options: ImageGenerateOptions | None = None,
867    ) -> str:
868        """Generate an image from a text prompt.
869
870        Args:
871            prompt: A text description of the image to generate.
872            options: Provider-specific generation options. Use one of:
873                - :class:`GptImageOptions`: ``{'modelName': 'gpt-image-1', 'quality': 'high', 'size': '1024x1024'}``
874                - :class:`FluxOptions`: ``{'modelName': 'flux-pro-1.1', 'width': 1024, 'height': 768}``
875                - :class:`StableDiffusionOptions`: ``{'modelName': 'stable-diffusion-core', 'aspectRatio': '16:9'}``
876
877        Returns:
878            The URL of the generated image.
879        """
880        result = await self._http.post(
881            "squid-api/v1/ai/image/generate",
882            {"prompt": prompt, "options": options or {}},
883        )
884        return result if isinstance(result, str) else str(result)
885
886    async def remove_background(
887        self,
888        image_data: bytes,
889        filename: str = "image.png",
890        content_type: str = "image/png",
891    ) -> str:
892        """Remove the background from an image.
893
894        Args:
895            image_data: The image file content as bytes.
896            filename: The filename (used in the multipart upload).
897            content_type: The MIME type of the image.
898
899        Returns:
900            The URL of the processed image with the background removed.
901        """
902        result = await self._http.post_form(
903            "squid-api/v1/ai/image/removeBackground",
904            data={},
905            files=[("file", (filename, image_data, content_type))],
906        )
907        return result if isinstance(result, str) else str(result)

Image generation and processing.

Supports DALL-E, Stable Diffusion Core, and Flux models.

Obtained via AiClient.image().

Example::

image_url = (
    await squid.ai()
    .image()
    .generate(
        "a cat astronaut on the moon",
        options={"modelName": "gpt-image-1", "quality": "high"},
    )
)
ImageClient(http: squidcloud.http.HttpTransport)
860    def __init__(self, http: HttpTransport) -> None:
861        self._http = http
async def generate( self, prompt: str, options: GptImageOptions | FluxOptions | StableDiffusionOptions | None = None) -> str:
863    async def generate(
864        self,
865        prompt: str,
866        options: ImageGenerateOptions | None = None,
867    ) -> str:
868        """Generate an image from a text prompt.
869
870        Args:
871            prompt: A text description of the image to generate.
872            options: Provider-specific generation options. Use one of:
873                - :class:`GptImageOptions`: ``{'modelName': 'gpt-image-1', 'quality': 'high', 'size': '1024x1024'}``
874                - :class:`FluxOptions`: ``{'modelName': 'flux-pro-1.1', 'width': 1024, 'height': 768}``
875                - :class:`StableDiffusionOptions`: ``{'modelName': 'stable-diffusion-core', 'aspectRatio': '16:9'}``
876
877        Returns:
878            The URL of the generated image.
879        """
880        result = await self._http.post(
881            "squid-api/v1/ai/image/generate",
882            {"prompt": prompt, "options": options or {}},
883        )
884        return result if isinstance(result, str) else str(result)

Generate an image from a text prompt.

Arguments:
  • prompt: A text description of the image to generate.
  • options: Provider-specific generation options. Use one of:
    • GptImageOptions: {'modelName': 'gpt-image-1', 'quality': 'high', 'size': '1024x1024'}
    • FluxOptions: {'modelName': 'flux-pro-1.1', 'width': 1024, 'height': 768}
    • StableDiffusionOptions: {'modelName': 'stable-diffusion-core', 'aspectRatio': '16:9'}
Returns:

The URL of the generated image.

async def remove_background( self, image_data: bytes, filename: str = 'image.png', content_type: str = 'image/png') -> str:
886    async def remove_background(
887        self,
888        image_data: bytes,
889        filename: str = "image.png",
890        content_type: str = "image/png",
891    ) -> str:
892        """Remove the background from an image.
893
894        Args:
895            image_data: The image file content as bytes.
896            filename: The filename (used in the multipart upload).
897            content_type: The MIME type of the image.
898
899        Returns:
900            The URL of the processed image with the background removed.
901        """
902        result = await self._http.post_form(
903            "squid-api/v1/ai/image/removeBackground",
904            data={},
905            files=[("file", (filename, image_data, content_type))],
906        )
907        return result if isinstance(result, str) else str(result)

Remove the background from an image.

Arguments:
  • image_data: The image file content as bytes.
  • filename: The filename (used in the multipart upload).
  • content_type: The MIME type of the image.
Returns:

The URL of the processed image with the background removed.

class IntegrationEmbeddingModelSpec(typing.TypedDict):
439class IntegrationEmbeddingModelSpec(TypedDict):
440    """Specifies an embedding model from a specific integration."""
441
442    integrationId: str
443    """The ID of the integration providing the embedding model."""
444    model: str
445    """The model name as recognized by the provider."""
446    dimensions: int
447    """The number of dimensions in the embedding vector output."""

Specifies an embedding model from a specific integration.

integrationId: str

The ID of the integration providing the embedding model.

model: str

The model name as recognized by the provider.

dimensions: int

The number of dimensions in the embedding vector output.

class IntegrationModelSpec(typing.TypedDict):
31class IntegrationModelSpec(TypedDict):
32    """Specifies a model from a specific integration."""
33
34    integrationId: str
35    model: str

Specifies a model from a specific integration.

integrationId: str
model: str
class KnowledgeBaseClient:
451class KnowledgeBaseClient:
452    """Operations on a single knowledge base.
453
454    Provides methods for managing knowledge base configuration, upserting
455    and searching text/file contexts, and retrieving individual contexts.
456
457    Obtained via :meth:`AiClient.knowledge_base`.
458
459    Example::
460
461        kb = squid.ai().knowledge_base("my-kb")
462        await kb.upsert(description="Product documentation")
463        await kb.upsert_contexts(
464            [
465                {
466                    "contextId": "doc-1",
467                    "type": "text",
468                    "title": "Getting Started",
469                    "text": "Welcome to our product...",
470                }
471            ]
472        )
473        results = await kb.search("How do I get started?")
474    """
475
476    def __init__(self, http: HttpTransport, kb_id: str) -> None:
477        self._http = http
478        self._kb_id = kb_id
479
480    async def get(self) -> dict | None:
481        """Get the knowledge base details.
482
483        Returns:
484            An ``AiKnowledgeBase`` dict with keys: ``id``, ``appId``,
485            ``description``, ``metadataFields``, ``embeddingModel``,
486            ``chatModel``, ``updatedAt``. Returns ``None`` if not found.
487        """
488        return await self._http.get(f"squid-api/v1/ai/knowledge-base/get/{self._kb_id}")
489
490    async def upsert(
491        self,
492        *,
493        description: str | None = None,
494        metadata_fields: list[AiKnowledgeBaseMetadataField] | None = None,
495        embedding_model: str | None = None,
496        chat_model: AiChatModelSelection | None = None,
497        name: str | None = None,
498        vector_db_type: VectorDbType | None = None,
499        graph_rag: AiKnowledgeBaseGraphConfig | None = None,
500    ) -> None:
501        """Create or update the knowledge base.
502
503        Args:
504            description: Description of the knowledge base's content.
505            metadata_fields: Schema for metadata fields used in filtering.
506                Each field: ``{'name': str, 'dataType': str, 'required': bool, 'description'?: str}``.
507            embedding_model: The embedding model name for vectorization.
508                Required when creating a new knowledge base.
509            chat_model: The LLM model for answering questions over this KB.
510            name: Display name for the knowledge base.
511            vector_db_type: The vector store backend. Set at creation (defaulting to the
512                server's default) and immutable thereafter. The knowledge graph requires
513                ``'mongoAtlas'``.
514            graph_rag: Opt-in GraphRAG configuration (``{'enabled': True, ...}``). Only
515                honored on ``'mongoAtlas'`` knowledge bases; mutable, unlike
516                ``vector_db_type``. The value replaces the stored config rather than
517                merging into it. See :class:`AiKnowledgeBaseGraphConfig`.
518        """
519        kb: dict[str, Any] = {"id": self._kb_id}
520        if description is not None:
521            kb["description"] = description
522        if metadata_fields is not None:
523            kb["metadataFields"] = metadata_fields
524        if embedding_model is not None:
525            kb["embeddingModel"] = embedding_model
526        if chat_model is not None:
527            kb["chatModel"] = chat_model
528        if name is not None:
529            kb["name"] = name
530        if vector_db_type is not None:
531            kb["vectorDbType"] = vector_db_type
532        if graph_rag is not None:
533            kb["graphRag"] = graph_rag
534        await self._http.post("squid-api/v1/ai/knowledge-base/upsert", {"knowledgeBase": kb})
535
536    async def delete(self) -> None:
537        """Delete the knowledge base and all its contexts permanently."""
538        await self._http.post("squid-api/v1/ai/knowledge-base/delete", {"id": self._kb_id})
539
540    # --- Contexts ---
541
542    async def get_context(self, context_id: str) -> dict | None:
543        """Get a specific context entry.
544
545        Args:
546            context_id: The unique context identifier.
547
548        Returns:
549            An ``AiKnowledgeBaseContext`` dict with keys: ``id``, ``appId``,
550            ``knowledgeBaseId``, ``createdAt``, ``updatedAt``, ``type``,
551            ``title``, ``text``, ``preview``, ``sizeBytes``, ``metadata``,
552            ``requestConfig``. Returns ``None`` if not found.
553        """
554        return await self._http.get(
555            f"squid-api/v1/ai/knowledge-base/getContext/{self._kb_id}/{context_id}"
556        )
557
558    async def list_contexts(self) -> list[dict]:
559        """List all contexts in the knowledge base.
560
561        Deprecated: fetches every context in one call with no pagination — expensive for large
562        knowledge bases. Use :meth:`list_contexts_page` instead, which supports
563        ``offset``/``limit``/``search``.
564
565        Returns:
566            A list of ``AiKnowledgeBaseContext`` dicts.
567        """
568        result = await self._http.get(f"squid-api/v1/ai/knowledge-base/listContexts/{self._kb_id}")
569        return result.get("contexts", []) if result else []
570
571    async def list_contexts_page(
572        self,
573        *,
574        offset: int | None = None,
575        limit: int | None = None,
576        search: str | None = None,
577    ) -> dict:
578        """List a page of contexts in the knowledge base.
579
580        Args:
581            offset: The number of contexts to skip, for pagination.
582            limit: The maximum number of contexts to return, for pagination.
583            search: Case-insensitive substring search across id/title only.
584
585        Returns:
586            A dict with ``contexts`` (a list of ``AiKnowledgeBaseContext`` dicts for the
587            requested page) and ``totalCount`` (the total number of contexts in the
588            knowledge base, ignoring ``offset``/``limit``).
589        """
590        params = {
591            key: str(value)
592            for key, value in {"offset": offset, "limit": limit, "search": search}.items()
593            if value is not None
594        }
595        result = await self._http.get(
596            f"squid-api/v1/ai/knowledge-base/listContextsPage/{self._kb_id}",
597            params=params or None,
598        )
599        return result if result else {"contexts": [], "totalCount": 0}
600
601    async def upsert_contexts(
602        self,
603        contexts: list[ContextRequest],
604        files: list[tuple[str, bytes, str]] | None = None,
605    ) -> dict:
606        """Add or update contexts in the knowledge base.
607
608        Args:
609            contexts: A list of context request objects. Each must be either:
610                - A :class:`TextContextRequest`: ``{'contextId', 'type': 'text', 'title', 'text', ...}``
611                - A :class:`FileContextRequest`: ``{'contextId', 'type': 'file', ...}``
612            files: For file contexts, provide the actual file data as a list of
613                ``(filename, data_bytes, content_type)`` tuples. Must match the
614                order of file contexts in the ``contexts`` list.
615
616        Returns:
617            A dict with ``failures``: a list of ``UpsertContextStatusError`` dicts
618            for any contexts that failed to upsert.
619
620        Example::
621
622            await kb.upsert_contexts(
623                [
624                    {"contextId": "doc-1", "type": "text", "title": "FAQ", "text": "..."},
625                    {"contextId": "doc-2", "type": "file"},
626                ],
627                files=[
628                    ("manual.pdf", pdf_bytes, "application/pdf"),
629                ],
630            )
631        """
632        form_data = {
633            "knowledgeBaseId": self._kb_id,
634            "contexts": json.dumps(contexts),
635        }
636        file_tuples: list[tuple[str, tuple[str, bytes, str]]] = []
637        if files:
638            for fname, fdata, ftype in files:
639                file_tuples.append(("files", (fname, fdata, ftype)))
640        return await self._http.post_form(
641            "squid-api/v1/ai/knowledge-base/upsertContexts",
642            data=form_data,
643            files=file_tuples,
644        )
645
646    async def delete_contexts(self, context_ids: list[str]) -> None:
647        """Delete contexts by their IDs.
648
649        Args:
650            context_ids: List of context IDs to delete.
651        """
652        await self._http.post(
653            "squid-api/v1/ai/knowledge-base/deleteContexts",
654            {"knowledgeBaseId": self._kb_id, "contextIds": context_ids},
655        )
656
657    # --- Search ---
658
659    async def search(
660        self,
661        prompt: str,
662        options: KnowledgeBaseSearchOptions | None = None,
663    ) -> list[dict]:
664        """Search the knowledge base using semantic search.
665
666        Args:
667            prompt: The search query in natural language.
668            options: Search options. See :class:`KnowledgeBaseSearchOptions`.
669                Supports: ``limit``, ``chunkLimit``, ``rerankProvider``, ``chatModel``,
670                ``searchMode``, ``graphOptions``, ``graphFilter``.
671
672        Returns:
673            A list of ``AiKnowledgeBaseSearchResultChunk`` dicts, each with:
674            ``contextId``, ``data``, ``metadata``, ``score``.
675
676        Example::
677
678            chunks = await kb.search(
679                "How do I reset my password?",
680                options={
681                    "limit": 5,
682                    "chatModel": "gemini-3.7-flash",
683                },
684            )
685            for chunk in chunks:
686                print(f"Score: {chunk['score']}, Data: {chunk['data'][:100]}")
687        """
688        response = await self.search_with_graph_context(prompt, options)
689        return response.get("chunks", [])
690
691    # --- Knowledge graph ---
692
693    async def search_with_graph_context(
694        self,
695        prompt: str,
696        options: KnowledgeBaseSearchOptions | None = None,
697    ) -> dict:
698        """Like :meth:`search`, but return the full search response instead of only the chunks.
699
700        With ``searchMode: 'graph'`` and ``graphOptions: {'includeGraphContext': True}`` the
701        response also carries ``graphContext``, the subgraph the search traversed.
702
703        Args:
704            prompt: The search query in natural language.
705            options: Search options. See :class:`KnowledgeBaseSearchOptions`.
706
707        Returns:
708            An ``AiKnowledgeBaseSearchResponse`` dict: ``chunks`` (list of result chunk dicts)
709            and, when requested via ``includeGraphContext``, ``graphContext``
710            (``{'entities': [...], 'relationships': [...]}``).
711        """
712        search_options: dict[str, Any] = {"prompt": prompt, **(options or {})}
713        result = await self._http.post(
714            "squid-api/v1/ai/knowledge-base/search",
715            {
716                "knowledgeBaseId": self._kb_id,
717                "prompt": prompt,
718                "options": search_options,
719            },
720        )
721        return result or {"chunks": []}
722
723    async def get_graph_status(self) -> dict:
724        """Get the knowledge base's graph build/readiness status.
725
726        Returns:
727            A ``GetKnowledgeBaseGraphStatusResponse`` dict with ``enabled``, ``entityCount``,
728            ``relationshipCount``, ``contextsIndexed``, ``contextsTotal``, and, where available,
729            ``facets``, ``topics``, ``structureStale``, LLM usage fields, and ``buildJob``
730            (``{'status': 'in_progress' | 'completed' | 'failed', ...}``) for the most recent
731            rebuild. Poll it after :meth:`rebuild_graph` until ``buildJob`` leaves
732            ``'in_progress'``.
733        """
734        return await self._http.get(f"squid-api/v1/ai/knowledge-base/getGraphStatus/{self._kb_id}")
735
736    async def rebuild_graph(self, *, mode: Literal["full", "structural"] | None = None) -> None:
737        """Enqueue a graph rebuild/backfill. Requires ``graphRag.enabled``.
738
739        Only one rebuild can run per knowledge base at a time; track progress via
740        :meth:`get_graph_status`.
741
742        Args:
743            mode: ``'structural'`` (the default) keeps the already-extracted entity graph and
744                rebuilds just the concept layer; ``'full'`` wipes the graph and re-extracts every
745                context with an LLM — expensive, and only needed when the extraction itself must
746                be redone (e.g. after changing ``entityTypes`` or ``extractionModel``).
747        """
748        request: dict[str, Any] = {"knowledgeBaseId": self._kb_id}
749        if mode is not None:
750            request["mode"] = mode
751        await self._http.post("squid-api/v1/ai/knowledge-base/rebuildGraph", request)
752
753    async def query_graph(
754        self,
755        op: KnowledgeBaseGraphQueryOp,
756        *,
757        ref: str | None = None,
758        ref_b: str | None = None,
759        context_id: str | None = None,
760        query: str | None = None,
761        depth: int | None = None,
762        hops: int | None = None,
763        recursive: bool | None = None,
764        limit: int | None = None,
765    ) -> dict:
766        """Query the knowledge base's graph (documents, entities, themes, facets).
767
768        Requires ``graphRag.enabled`` on the knowledge base.
769
770        Args:
771            op: The operation to run.
772            ref: Node ref (name or facet nodeId). Required by resolve/describe/subtree/
773                docsUnder/neighborhood/pathBetween.
774            ref_b: Second node ref for ``pathBetween``.
775            context_id: The document's contextId for ``conceptsOf``.
776            query: The free-text question for ``globalSummary``.
777            depth: ``subtree``: maximum depth below the resolved node. Default (and cap) 3.
778            hops: ``neighborhood``: expansion hops from the resolved entity. Default 1, max 2.
779            recursive: ``docsUnder``: when True (the default), include documents under the whole
780                subtree, not just the node itself.
781            limit: ``docsUnder``: maximum documents returned. Default 25, max 100.
782
783        Returns:
784            A ``QueryKnowledgeBaseGraphResponse`` dict; which keys are present depends on ``op``
785            (e.g. ``overview`` for 'overview', ``matches`` for 'resolve', ``node``/``path``/
786            ``related`` for 'describe', ``tree``, ``documents``/``totalDocs``, ``concepts``,
787            ``graph``, ``pathBetween``, ``summaries``).
788        """
789        request: dict[str, Any] = {"knowledgeBaseId": self._kb_id, "op": op}
790        if ref is not None:
791            request["ref"] = ref
792        if ref_b is not None:
793            request["refB"] = ref_b
794        if context_id is not None:
795            request["contextId"] = context_id
796        if query is not None:
797            request["query"] = query
798        if depth is not None:
799            request["depth"] = depth
800        if hops is not None:
801            request["hops"] = hops
802        if recursive is not None:
803            request["recursive"] = recursive
804        if limit is not None:
805            request["limit"] = limit
806        return await self._http.post("squid-api/v1/ai/knowledge-base/queryGraph", request)
807
808    async def explore_graph(
809        self,
810        *,
811        node_limit: int | None = None,
812        topic_id: str | None = None,
813    ) -> dict:
814        """Get a bounded slice of the knowledge base's entity graph for exploration/visualization.
815
816        Returns the highest-degree entities and the relationships among them. Requires
817        ``graphRag.enabled``.
818
819        Args:
820            node_limit: Hard cap on returned nodes. Default 200, max 1000.
821            topic_id: Restricts the subgraph to entities under the given topic node id. Ids come
822                from :meth:`get_graph_status`'s ``topics`` and churn on rebuild.
823
824        Returns:
825            An ``ExploreKnowledgeBaseGraphResponse`` dict: ``nodes``, ``edges``, and, once the
826            concept layer has been built, ``topics``.
827        """
828        request: dict[str, Any] = {"knowledgeBaseId": self._kb_id}
829        if node_limit is not None:
830            request["nodeLimit"] = node_limit
831        if topic_id is not None:
832            request["topicId"] = topic_id
833        return await self._http.post("squid-api/v1/ai/knowledge-base/exploreGraph", request)

Operations on a single knowledge base.

Provides methods for managing knowledge base configuration, upserting and searching text/file contexts, and retrieving individual contexts.

Obtained via AiClient.knowledge_base().

Example::

kb = squid.ai().knowledge_base("my-kb")
await kb.upsert(description="Product documentation")
await kb.upsert_contexts(
    [
        {
            "contextId": "doc-1",
            "type": "text",
            "title": "Getting Started",
            "text": "Welcome to our product...",
        }
    ]
)
results = await kb.search("How do I get started?")
KnowledgeBaseClient(http: squidcloud.http.HttpTransport, kb_id: str)
476    def __init__(self, http: HttpTransport, kb_id: str) -> None:
477        self._http = http
478        self._kb_id = kb_id
async def get(self) -> dict | None:
480    async def get(self) -> dict | None:
481        """Get the knowledge base details.
482
483        Returns:
484            An ``AiKnowledgeBase`` dict with keys: ``id``, ``appId``,
485            ``description``, ``metadataFields``, ``embeddingModel``,
486            ``chatModel``, ``updatedAt``. Returns ``None`` if not found.
487        """
488        return await self._http.get(f"squid-api/v1/ai/knowledge-base/get/{self._kb_id}")

Get the knowledge base details.

Returns:

An AiKnowledgeBase dict with keys: id, appId, description, metadataFields, embeddingModel, chatModel, updatedAt. Returns None if not found.

async def upsert( self, *, description: str | None = None, metadata_fields: list[AiKnowledgeBaseMetadataField] | None = None, embedding_model: str | None = None, chat_model: str | IntegrationModelSpec | None = None, name: str | None = None, vector_db_type: Literal['postgres', 'mongoAtlas'] | None = None, graph_rag: AiKnowledgeBaseGraphConfig | None = None) -> None:
490    async def upsert(
491        self,
492        *,
493        description: str | None = None,
494        metadata_fields: list[AiKnowledgeBaseMetadataField] | None = None,
495        embedding_model: str | None = None,
496        chat_model: AiChatModelSelection | None = None,
497        name: str | None = None,
498        vector_db_type: VectorDbType | None = None,
499        graph_rag: AiKnowledgeBaseGraphConfig | None = None,
500    ) -> None:
501        """Create or update the knowledge base.
502
503        Args:
504            description: Description of the knowledge base's content.
505            metadata_fields: Schema for metadata fields used in filtering.
506                Each field: ``{'name': str, 'dataType': str, 'required': bool, 'description'?: str}``.
507            embedding_model: The embedding model name for vectorization.
508                Required when creating a new knowledge base.
509            chat_model: The LLM model for answering questions over this KB.
510            name: Display name for the knowledge base.
511            vector_db_type: The vector store backend. Set at creation (defaulting to the
512                server's default) and immutable thereafter. The knowledge graph requires
513                ``'mongoAtlas'``.
514            graph_rag: Opt-in GraphRAG configuration (``{'enabled': True, ...}``). Only
515                honored on ``'mongoAtlas'`` knowledge bases; mutable, unlike
516                ``vector_db_type``. The value replaces the stored config rather than
517                merging into it. See :class:`AiKnowledgeBaseGraphConfig`.
518        """
519        kb: dict[str, Any] = {"id": self._kb_id}
520        if description is not None:
521            kb["description"] = description
522        if metadata_fields is not None:
523            kb["metadataFields"] = metadata_fields
524        if embedding_model is not None:
525            kb["embeddingModel"] = embedding_model
526        if chat_model is not None:
527            kb["chatModel"] = chat_model
528        if name is not None:
529            kb["name"] = name
530        if vector_db_type is not None:
531            kb["vectorDbType"] = vector_db_type
532        if graph_rag is not None:
533            kb["graphRag"] = graph_rag
534        await self._http.post("squid-api/v1/ai/knowledge-base/upsert", {"knowledgeBase": kb})

Create or update the knowledge base.

Arguments:
  • description: Description of the knowledge base's content.
  • metadata_fields: Schema for metadata fields used in filtering. Each field: {'name': str, 'dataType': str, 'required': bool, 'description'?: str}.
  • embedding_model: The embedding model name for vectorization. Required when creating a new knowledge base.
  • chat_model: The LLM model for answering questions over this KB.
  • name: Display name for the knowledge base.
  • vector_db_type: The vector store backend. Set at creation (defaulting to the server's default) and immutable thereafter. The knowledge graph requires 'mongoAtlas'.
  • graph_rag: Opt-in GraphRAG configuration ({'enabled': True, ...}). Only honored on 'mongoAtlas' knowledge bases; mutable, unlike vector_db_type. The value replaces the stored config rather than merging into it. See AiKnowledgeBaseGraphConfig.
async def delete(self) -> None:
536    async def delete(self) -> None:
537        """Delete the knowledge base and all its contexts permanently."""
538        await self._http.post("squid-api/v1/ai/knowledge-base/delete", {"id": self._kb_id})

Delete the knowledge base and all its contexts permanently.

async def get_context(self, context_id: str) -> dict | None:
542    async def get_context(self, context_id: str) -> dict | None:
543        """Get a specific context entry.
544
545        Args:
546            context_id: The unique context identifier.
547
548        Returns:
549            An ``AiKnowledgeBaseContext`` dict with keys: ``id``, ``appId``,
550            ``knowledgeBaseId``, ``createdAt``, ``updatedAt``, ``type``,
551            ``title``, ``text``, ``preview``, ``sizeBytes``, ``metadata``,
552            ``requestConfig``. Returns ``None`` if not found.
553        """
554        return await self._http.get(
555            f"squid-api/v1/ai/knowledge-base/getContext/{self._kb_id}/{context_id}"
556        )

Get a specific context entry.

Arguments:
  • context_id: The unique context identifier.
Returns:

An AiKnowledgeBaseContext dict with keys: id, appId, knowledgeBaseId, createdAt, updatedAt, type, title, text, preview, sizeBytes, metadata, requestConfig. Returns None if not found.

async def list_contexts(self) -> list[dict]:
558    async def list_contexts(self) -> list[dict]:
559        """List all contexts in the knowledge base.
560
561        Deprecated: fetches every context in one call with no pagination — expensive for large
562        knowledge bases. Use :meth:`list_contexts_page` instead, which supports
563        ``offset``/``limit``/``search``.
564
565        Returns:
566            A list of ``AiKnowledgeBaseContext`` dicts.
567        """
568        result = await self._http.get(f"squid-api/v1/ai/knowledge-base/listContexts/{self._kb_id}")
569        return result.get("contexts", []) if result else []

List all contexts in the knowledge base.

Deprecated: fetches every context in one call with no pagination — expensive for large knowledge bases. Use list_contexts_page() instead, which supports offset/limit/search.

Returns:

A list of AiKnowledgeBaseContext dicts.

async def list_contexts_page( self, *, offset: int | None = None, limit: int | None = None, search: str | None = None) -> dict:
571    async def list_contexts_page(
572        self,
573        *,
574        offset: int | None = None,
575        limit: int | None = None,
576        search: str | None = None,
577    ) -> dict:
578        """List a page of contexts in the knowledge base.
579
580        Args:
581            offset: The number of contexts to skip, for pagination.
582            limit: The maximum number of contexts to return, for pagination.
583            search: Case-insensitive substring search across id/title only.
584
585        Returns:
586            A dict with ``contexts`` (a list of ``AiKnowledgeBaseContext`` dicts for the
587            requested page) and ``totalCount`` (the total number of contexts in the
588            knowledge base, ignoring ``offset``/``limit``).
589        """
590        params = {
591            key: str(value)
592            for key, value in {"offset": offset, "limit": limit, "search": search}.items()
593            if value is not None
594        }
595        result = await self._http.get(
596            f"squid-api/v1/ai/knowledge-base/listContextsPage/{self._kb_id}",
597            params=params or None,
598        )
599        return result if result else {"contexts": [], "totalCount": 0}

List a page of contexts in the knowledge base.

Arguments:
  • offset: The number of contexts to skip, for pagination.
  • limit: The maximum number of contexts to return, for pagination.
  • search: Case-insensitive substring search across id/title only.
Returns:

A dict with contexts (a list of AiKnowledgeBaseContext dicts for the requested page) and totalCount (the total number of contexts in the knowledge base, ignoring offset/limit).

async def upsert_contexts( self, contexts: list[TextContextRequest | FileContextRequest], files: list[tuple[str, bytes, str]] | None = None) -> dict:
601    async def upsert_contexts(
602        self,
603        contexts: list[ContextRequest],
604        files: list[tuple[str, bytes, str]] | None = None,
605    ) -> dict:
606        """Add or update contexts in the knowledge base.
607
608        Args:
609            contexts: A list of context request objects. Each must be either:
610                - A :class:`TextContextRequest`: ``{'contextId', 'type': 'text', 'title', 'text', ...}``
611                - A :class:`FileContextRequest`: ``{'contextId', 'type': 'file', ...}``
612            files: For file contexts, provide the actual file data as a list of
613                ``(filename, data_bytes, content_type)`` tuples. Must match the
614                order of file contexts in the ``contexts`` list.
615
616        Returns:
617            A dict with ``failures``: a list of ``UpsertContextStatusError`` dicts
618            for any contexts that failed to upsert.
619
620        Example::
621
622            await kb.upsert_contexts(
623                [
624                    {"contextId": "doc-1", "type": "text", "title": "FAQ", "text": "..."},
625                    {"contextId": "doc-2", "type": "file"},
626                ],
627                files=[
628                    ("manual.pdf", pdf_bytes, "application/pdf"),
629                ],
630            )
631        """
632        form_data = {
633            "knowledgeBaseId": self._kb_id,
634            "contexts": json.dumps(contexts),
635        }
636        file_tuples: list[tuple[str, tuple[str, bytes, str]]] = []
637        if files:
638            for fname, fdata, ftype in files:
639                file_tuples.append(("files", (fname, fdata, ftype)))
640        return await self._http.post_form(
641            "squid-api/v1/ai/knowledge-base/upsertContexts",
642            data=form_data,
643            files=file_tuples,
644        )

Add or update contexts in the knowledge base.

Arguments:
  • contexts: A list of context request objects. Each must be either:
  • files: For file contexts, provide the actual file data as a list of (filename, data_bytes, content_type) tuples. Must match the order of file contexts in the contexts list.
Returns:

A dict with failures: a list of UpsertContextStatusError dicts for any contexts that failed to upsert.

Example::

await kb.upsert_contexts(
    [
        {"contextId": "doc-1", "type": "text", "title": "FAQ", "text": "..."},
        {"contextId": "doc-2", "type": "file"},
    ],
    files=[
        ("manual.pdf", pdf_bytes, "application/pdf"),
    ],
)
async def delete_contexts(self, context_ids: list[str]) -> None:
646    async def delete_contexts(self, context_ids: list[str]) -> None:
647        """Delete contexts by their IDs.
648
649        Args:
650            context_ids: List of context IDs to delete.
651        """
652        await self._http.post(
653            "squid-api/v1/ai/knowledge-base/deleteContexts",
654            {"knowledgeBaseId": self._kb_id, "contextIds": context_ids},
655        )

Delete contexts by their IDs.

Arguments:
  • context_ids: List of context IDs to delete.
async def search( self, prompt: str, options: KnowledgeBaseSearchOptions | None = None) -> list[dict]:
659    async def search(
660        self,
661        prompt: str,
662        options: KnowledgeBaseSearchOptions | None = None,
663    ) -> list[dict]:
664        """Search the knowledge base using semantic search.
665
666        Args:
667            prompt: The search query in natural language.
668            options: Search options. See :class:`KnowledgeBaseSearchOptions`.
669                Supports: ``limit``, ``chunkLimit``, ``rerankProvider``, ``chatModel``,
670                ``searchMode``, ``graphOptions``, ``graphFilter``.
671
672        Returns:
673            A list of ``AiKnowledgeBaseSearchResultChunk`` dicts, each with:
674            ``contextId``, ``data``, ``metadata``, ``score``.
675
676        Example::
677
678            chunks = await kb.search(
679                "How do I reset my password?",
680                options={
681                    "limit": 5,
682                    "chatModel": "gemini-3.7-flash",
683                },
684            )
685            for chunk in chunks:
686                print(f"Score: {chunk['score']}, Data: {chunk['data'][:100]}")
687        """
688        response = await self.search_with_graph_context(prompt, options)
689        return response.get("chunks", [])

Search the knowledge base using semantic search.

Arguments:
  • prompt: The search query in natural language.
  • options: Search options. See KnowledgeBaseSearchOptions. Supports: limit, chunkLimit, rerankProvider, chatModel, searchMode, graphOptions, graphFilter.
Returns:

A list of AiKnowledgeBaseSearchResultChunk dicts, each with: contextId, data, metadata, score.

Example::

chunks = await kb.search(
    "How do I reset my password?",
    options={
        "limit": 5,
        "chatModel": "gemini-3.7-flash",
    },
)
for chunk in chunks:
    print(f"Score: {chunk['score']}, Data: {chunk['data'][:100]}")
async def search_with_graph_context( self, prompt: str, options: KnowledgeBaseSearchOptions | None = None) -> dict:
693    async def search_with_graph_context(
694        self,
695        prompt: str,
696        options: KnowledgeBaseSearchOptions | None = None,
697    ) -> dict:
698        """Like :meth:`search`, but return the full search response instead of only the chunks.
699
700        With ``searchMode: 'graph'`` and ``graphOptions: {'includeGraphContext': True}`` the
701        response also carries ``graphContext``, the subgraph the search traversed.
702
703        Args:
704            prompt: The search query in natural language.
705            options: Search options. See :class:`KnowledgeBaseSearchOptions`.
706
707        Returns:
708            An ``AiKnowledgeBaseSearchResponse`` dict: ``chunks`` (list of result chunk dicts)
709            and, when requested via ``includeGraphContext``, ``graphContext``
710            (``{'entities': [...], 'relationships': [...]}``).
711        """
712        search_options: dict[str, Any] = {"prompt": prompt, **(options or {})}
713        result = await self._http.post(
714            "squid-api/v1/ai/knowledge-base/search",
715            {
716                "knowledgeBaseId": self._kb_id,
717                "prompt": prompt,
718                "options": search_options,
719            },
720        )
721        return result or {"chunks": []}

Like search(), but return the full search response instead of only the chunks.

With searchMode: 'graph' and graphOptions: {'includeGraphContext': True} the response also carries graphContext, the subgraph the search traversed.

Arguments:
Returns:

An AiKnowledgeBaseSearchResponse dict: chunks (list of result chunk dicts) and, when requested via includeGraphContext, graphContext ({'entities': [...], 'relationships': [...]}).

async def get_graph_status(self) -> dict:
723    async def get_graph_status(self) -> dict:
724        """Get the knowledge base's graph build/readiness status.
725
726        Returns:
727            A ``GetKnowledgeBaseGraphStatusResponse`` dict with ``enabled``, ``entityCount``,
728            ``relationshipCount``, ``contextsIndexed``, ``contextsTotal``, and, where available,
729            ``facets``, ``topics``, ``structureStale``, LLM usage fields, and ``buildJob``
730            (``{'status': 'in_progress' | 'completed' | 'failed', ...}``) for the most recent
731            rebuild. Poll it after :meth:`rebuild_graph` until ``buildJob`` leaves
732            ``'in_progress'``.
733        """
734        return await self._http.get(f"squid-api/v1/ai/knowledge-base/getGraphStatus/{self._kb_id}")

Get the knowledge base's graph build/readiness status.

Returns:

A GetKnowledgeBaseGraphStatusResponse dict with enabled, entityCount, relationshipCount, contextsIndexed, contextsTotal, and, where available, facets, topics, structureStale, LLM usage fields, and buildJob ({'status': 'in_progress' | 'completed' | 'failed', ...}) for the most recent rebuild. Poll it after rebuild_graph() until buildJob leaves 'in_progress'.

async def rebuild_graph(self, *, mode: Literal['full', 'structural'] | None = None) -> None:
736    async def rebuild_graph(self, *, mode: Literal["full", "structural"] | None = None) -> None:
737        """Enqueue a graph rebuild/backfill. Requires ``graphRag.enabled``.
738
739        Only one rebuild can run per knowledge base at a time; track progress via
740        :meth:`get_graph_status`.
741
742        Args:
743            mode: ``'structural'`` (the default) keeps the already-extracted entity graph and
744                rebuilds just the concept layer; ``'full'`` wipes the graph and re-extracts every
745                context with an LLM — expensive, and only needed when the extraction itself must
746                be redone (e.g. after changing ``entityTypes`` or ``extractionModel``).
747        """
748        request: dict[str, Any] = {"knowledgeBaseId": self._kb_id}
749        if mode is not None:
750            request["mode"] = mode
751        await self._http.post("squid-api/v1/ai/knowledge-base/rebuildGraph", request)

Enqueue a graph rebuild/backfill. Requires graphRag.enabled.

Only one rebuild can run per knowledge base at a time; track progress via get_graph_status().

Arguments:
  • mode: 'structural' (the default) keeps the already-extracted entity graph and rebuilds just the concept layer; 'full' wipes the graph and re-extracts every context with an LLM — expensive, and only needed when the extraction itself must be redone (e.g. after changing entityTypes or extractionModel).
async def query_graph( self, op: Literal['overview', 'resolve', 'describe', 'subtree', 'docsUnder', 'conceptsOf', 'neighborhood', 'pathBetween', 'globalSummary'], *, ref: str | None = None, ref_b: str | None = None, context_id: str | None = None, query: str | None = None, depth: int | None = None, hops: int | None = None, recursive: bool | None = None, limit: int | None = None) -> dict:
753    async def query_graph(
754        self,
755        op: KnowledgeBaseGraphQueryOp,
756        *,
757        ref: str | None = None,
758        ref_b: str | None = None,
759        context_id: str | None = None,
760        query: str | None = None,
761        depth: int | None = None,
762        hops: int | None = None,
763        recursive: bool | None = None,
764        limit: int | None = None,
765    ) -> dict:
766        """Query the knowledge base's graph (documents, entities, themes, facets).
767
768        Requires ``graphRag.enabled`` on the knowledge base.
769
770        Args:
771            op: The operation to run.
772            ref: Node ref (name or facet nodeId). Required by resolve/describe/subtree/
773                docsUnder/neighborhood/pathBetween.
774            ref_b: Second node ref for ``pathBetween``.
775            context_id: The document's contextId for ``conceptsOf``.
776            query: The free-text question for ``globalSummary``.
777            depth: ``subtree``: maximum depth below the resolved node. Default (and cap) 3.
778            hops: ``neighborhood``: expansion hops from the resolved entity. Default 1, max 2.
779            recursive: ``docsUnder``: when True (the default), include documents under the whole
780                subtree, not just the node itself.
781            limit: ``docsUnder``: maximum documents returned. Default 25, max 100.
782
783        Returns:
784            A ``QueryKnowledgeBaseGraphResponse`` dict; which keys are present depends on ``op``
785            (e.g. ``overview`` for 'overview', ``matches`` for 'resolve', ``node``/``path``/
786            ``related`` for 'describe', ``tree``, ``documents``/``totalDocs``, ``concepts``,
787            ``graph``, ``pathBetween``, ``summaries``).
788        """
789        request: dict[str, Any] = {"knowledgeBaseId": self._kb_id, "op": op}
790        if ref is not None:
791            request["ref"] = ref
792        if ref_b is not None:
793            request["refB"] = ref_b
794        if context_id is not None:
795            request["contextId"] = context_id
796        if query is not None:
797            request["query"] = query
798        if depth is not None:
799            request["depth"] = depth
800        if hops is not None:
801            request["hops"] = hops
802        if recursive is not None:
803            request["recursive"] = recursive
804        if limit is not None:
805            request["limit"] = limit
806        return await self._http.post("squid-api/v1/ai/knowledge-base/queryGraph", request)

Query the knowledge base's graph (documents, entities, themes, facets).

Requires graphRag.enabled on the knowledge base.

Arguments:
  • op: The operation to run.
  • ref: Node ref (name or facet nodeId). Required by resolve/describe/subtree/ docsUnder/neighborhood/pathBetween.
  • ref_b: Second node ref for pathBetween.
  • context_id: The document's contextId for conceptsOf.
  • query: The free-text question for globalSummary.
  • depth: subtree: maximum depth below the resolved node. Default (and cap) 3.
  • hops: neighborhood: expansion hops from the resolved entity. Default 1, max 2.
  • recursive: docsUnder: when True (the default), include documents under the whole subtree, not just the node itself.
  • limit: docsUnder: maximum documents returned. Default 25, max 100.
Returns:

A QueryKnowledgeBaseGraphResponse dict; which keys are present depends on op (e.g. overview for 'overview', matches for 'resolve', node/path/ related for 'describe', tree, documents/totalDocs, concepts, graph, pathBetween, summaries).

async def explore_graph( self, *, node_limit: int | None = None, topic_id: str | None = None) -> dict:
808    async def explore_graph(
809        self,
810        *,
811        node_limit: int | None = None,
812        topic_id: str | None = None,
813    ) -> dict:
814        """Get a bounded slice of the knowledge base's entity graph for exploration/visualization.
815
816        Returns the highest-degree entities and the relationships among them. Requires
817        ``graphRag.enabled``.
818
819        Args:
820            node_limit: Hard cap on returned nodes. Default 200, max 1000.
821            topic_id: Restricts the subgraph to entities under the given topic node id. Ids come
822                from :meth:`get_graph_status`'s ``topics`` and churn on rebuild.
823
824        Returns:
825            An ``ExploreKnowledgeBaseGraphResponse`` dict: ``nodes``, ``edges``, and, once the
826            concept layer has been built, ``topics``.
827        """
828        request: dict[str, Any] = {"knowledgeBaseId": self._kb_id}
829        if node_limit is not None:
830            request["nodeLimit"] = node_limit
831        if topic_id is not None:
832            request["topicId"] = topic_id
833        return await self._http.post("squid-api/v1/ai/knowledge-base/exploreGraph", request)

Get a bounded slice of the knowledge base's entity graph for exploration/visualization.

Returns the highest-degree entities and the relationships among them. Requires graphRag.enabled.

Arguments:
  • node_limit: Hard cap on returned nodes. Default 200, max 1000.
  • topic_id: Restricts the subgraph to entities under the given topic node id. Ids come from get_graph_status()'s topics and churn on rebuild.
Returns:

An ExploreKnowledgeBaseGraphResponse dict: nodes, edges, and, once the concept layer has been built, topics.

KnowledgeBaseGraphQueryOp = typing.Literal['overview', 'resolve', 'describe', 'subtree', 'docsUnder', 'conceptsOf', 'neighborhood', 'pathBetween', 'globalSummary']
class KnowledgeBaseSearchOptions(typing.TypedDict):
647class KnowledgeBaseSearchOptions(TypedDict, total=False):
648    """Options for knowledge base search."""
649
650    prompt: str
651    """The search prompt."""
652    limit: int
653    """Max number of results to return."""
654    chunkLimit: int
655    """How many chunks to search over (default 100)."""
656    rerankProvider: AiRerankProvider
657    """Reranker provider (default 'cohere')."""
658    chatModel: AiChatModelSelection
659    """Model to use for answering."""
660    searchMode: Literal["vector", "hybrid", "keyword", "graph"]
661    """Retrieval mode: 'hybrid' (BM25+dense fusion where supported; default on non-graph KBs),
662    'vector' (dense only), 'keyword' (pure lexical — every whitespace-separated term must appear
663    as a literal, case-insensitive substring), or 'graph' (GraphRAG — seeds entities via vector
664    search, expands relationships via graph traversal, maps entities back to their chunks, fused
665    with a hybrid search; requires a ``vectorDbType: 'mongoAtlas'`` KB with ``graphRag.enabled``
666    and is the default there)."""
667    graphOptions: AiKnowledgeBaseGraphSearchOptions
668    """Tuning for ``searchMode: 'graph'``. Ignored for other search modes."""
669    graphFilter: AiKnowledgeBaseGraphFilter
670    """Scopes the search to the documents under one concept of the KB's graph. Requires
671    ``graphRag.enabled``."""

Options for knowledge base search.

prompt: str

The search prompt.

limit: int

Max number of results to return.

chunkLimit: int

How many chunks to search over (default 100).

rerankProvider: Literal['cohere']

Reranker provider (default 'cohere').

chatModel: str | IntegrationModelSpec

Model to use for answering.

searchMode: Literal['vector', 'hybrid', 'keyword', 'graph']

Retrieval mode: 'hybrid' (BM25+dense fusion where supported; default on non-graph KBs), 'vector' (dense only), 'keyword' (pure lexical — every whitespace-separated term must appear as a literal, case-insensitive substring), or 'graph' (GraphRAG — seeds entities via vector search, expands relationships via graph traversal, maps entities back to their chunks, fused with a hybrid search; requires a vectorDbType: 'mongoAtlas' KB with graphRag.enabled and is the default there).

Tuning for searchMode: 'graph'. Ignored for other search modes.

Scopes the search to the documents under one concept of the KB's graph. Requires graphRag.enabled.

class MatchmakingClient:
 21class MatchmakingClient:
 22    """AI-powered matchmaking: match makers, entities, matching."""
 23
 24    def __init__(self, http: HttpTransport) -> None:
 25        self._http = http
 26
 27    # --- Match makers ---
 28
 29    async def create_match_maker(
 30        self,
 31        match_maker_id: str,
 32        description: str,
 33        categories: list[MmCategory],
 34    ) -> dict:
 35        """Create a new match maker."""
 36        return await self._http.post(
 37            "squid-api/v1/ai/matchmaking/createMatchMaker",
 38            {"id": match_maker_id, "description": description, "categories": categories},
 39        )
 40
 41    async def get_match_maker(self, match_maker_id: str) -> dict | None:
 42        """Get a match maker by ID."""
 43        result = await self._http.get(f"squid-api/v1/ai/matchmaking/getMatchMaker/{match_maker_id}")
 44        return result.get("matchMaker") if result else None
 45
 46    async def list_match_makers(self) -> list[dict]:
 47        """List all match makers."""
 48        result = await self._http.get("squid-api/v1/ai/matchmaking/listMatchMakers")
 49        return result.get("matchMakers", []) if result else []
 50
 51    async def delete_match_maker(self, match_maker_id: str) -> None:
 52        """Delete a match maker."""
 53        await self._http.post(
 54            "squid-api/v1/ai/matchmaking/deleteMatchMaker",
 55            {"matchMakerId": match_maker_id},
 56        )
 57
 58    # --- Entities ---
 59
 60    async def insert_entities(self, match_maker_id: str, entities: list[MmEntity]) -> None:
 61        """Insert entities into a match maker."""
 62        await self._http.post(
 63            "squid-api/v1/ai/matchmaking/insertEntities",
 64            {"matchMakerId": match_maker_id, "entities": entities},
 65        )
 66
 67    async def delete_entity(self, match_maker_id: str, entity_id: str) -> None:
 68        """Delete an entity."""
 69        await self._http.post(
 70            "squid-api/v1/ai/matchmaking/deleteEntity",
 71            {"matchMakerId": match_maker_id, "entityId": entity_id},
 72        )
 73
 74    async def get_entity(self, match_maker_id: str, entity_id: str) -> dict | None:
 75        """Get a specific entity."""
 76        result = await self._http.get(
 77            f"squid-api/v1/ai/matchmaking/getEntity/{match_maker_id}/{entity_id}"
 78        )
 79        return result.get("entity") if result else None
 80
 81    async def list_entities(
 82        self,
 83        match_maker_id: str,
 84        category_id: str,
 85        options: MmListEntitiesOptions | None = None,
 86    ) -> list[dict]:
 87        """List entities in a category."""
 88        result = await self._http.post(
 89            "squid-api/v1/ai/matchmaking/listEntities",
 90            {
 91                "matchMakerId": match_maker_id,
 92                "categoryId": category_id,
 93                "options": options or {},
 94            },
 95        )
 96        return result.get("entities", []) if result else []
 97
 98    # --- Matching ---
 99
100    async def find_matches(
101        self,
102        match_maker_id: str,
103        entity_id: str,
104        options: MmFindMatchesOptions | None = None,
105    ) -> list[dict]:
106        """Find matches for an existing entity.
107
108        Returns list of MmEntityMatch dicts with:
109        id, content, categoryId, metadata, score, reasoning.
110        """
111        result = await self._http.post(
112            "squid-api/v1/ai/matchmaking/findMatches",
113            {
114                "matchMakerId": match_maker_id,
115                "entityId": entity_id,
116                "options": options or {},
117            },
118        )
119        return result.get("matches", []) if result else []
120
121    async def find_matches_for_entity(
122        self,
123        match_maker_id: str,
124        entity: MmEntity,
125        options: MmFindMatchesOptions | None = None,
126    ) -> list[dict]:
127        """Find matches for a new entity (not yet inserted)."""
128        result = await self._http.post(
129            "squid-api/v1/ai/matchmaking/findMatchesForEntity",
130            {
131                "matchMakerId": match_maker_id,
132                "entity": entity,
133                "options": options or {},
134            },
135        )
136        return result.get("matches", []) if result else []

AI-powered matchmaking: match makers, entities, matching.

MatchmakingClient(http: squidcloud.http.HttpTransport)
24    def __init__(self, http: HttpTransport) -> None:
25        self._http = http
async def create_match_maker( self, match_maker_id: str, description: str, categories: list[MmCategory]) -> dict:
29    async def create_match_maker(
30        self,
31        match_maker_id: str,
32        description: str,
33        categories: list[MmCategory],
34    ) -> dict:
35        """Create a new match maker."""
36        return await self._http.post(
37            "squid-api/v1/ai/matchmaking/createMatchMaker",
38            {"id": match_maker_id, "description": description, "categories": categories},
39        )

Create a new match maker.

async def get_match_maker(self, match_maker_id: str) -> dict | None:
41    async def get_match_maker(self, match_maker_id: str) -> dict | None:
42        """Get a match maker by ID."""
43        result = await self._http.get(f"squid-api/v1/ai/matchmaking/getMatchMaker/{match_maker_id}")
44        return result.get("matchMaker") if result else None

Get a match maker by ID.

async def list_match_makers(self) -> list[dict]:
46    async def list_match_makers(self) -> list[dict]:
47        """List all match makers."""
48        result = await self._http.get("squid-api/v1/ai/matchmaking/listMatchMakers")
49        return result.get("matchMakers", []) if result else []

List all match makers.

async def delete_match_maker(self, match_maker_id: str) -> None:
51    async def delete_match_maker(self, match_maker_id: str) -> None:
52        """Delete a match maker."""
53        await self._http.post(
54            "squid-api/v1/ai/matchmaking/deleteMatchMaker",
55            {"matchMakerId": match_maker_id},
56        )

Delete a match maker.

async def insert_entities( self, match_maker_id: str, entities: list[MmEntity]) -> None:
60    async def insert_entities(self, match_maker_id: str, entities: list[MmEntity]) -> None:
61        """Insert entities into a match maker."""
62        await self._http.post(
63            "squid-api/v1/ai/matchmaking/insertEntities",
64            {"matchMakerId": match_maker_id, "entities": entities},
65        )

Insert entities into a match maker.

async def delete_entity(self, match_maker_id: str, entity_id: str) -> None:
67    async def delete_entity(self, match_maker_id: str, entity_id: str) -> None:
68        """Delete an entity."""
69        await self._http.post(
70            "squid-api/v1/ai/matchmaking/deleteEntity",
71            {"matchMakerId": match_maker_id, "entityId": entity_id},
72        )

Delete an entity.

async def get_entity(self, match_maker_id: str, entity_id: str) -> dict | None:
74    async def get_entity(self, match_maker_id: str, entity_id: str) -> dict | None:
75        """Get a specific entity."""
76        result = await self._http.get(
77            f"squid-api/v1/ai/matchmaking/getEntity/{match_maker_id}/{entity_id}"
78        )
79        return result.get("entity") if result else None

Get a specific entity.

async def list_entities( self, match_maker_id: str, category_id: str, options: MmListEntitiesOptions | None = None) -> list[dict]:
81    async def list_entities(
82        self,
83        match_maker_id: str,
84        category_id: str,
85        options: MmListEntitiesOptions | None = None,
86    ) -> list[dict]:
87        """List entities in a category."""
88        result = await self._http.post(
89            "squid-api/v1/ai/matchmaking/listEntities",
90            {
91                "matchMakerId": match_maker_id,
92                "categoryId": category_id,
93                "options": options or {},
94            },
95        )
96        return result.get("entities", []) if result else []

List entities in a category.

async def find_matches( self, match_maker_id: str, entity_id: str, options: MmFindMatchesOptions | None = None) -> list[dict]:
100    async def find_matches(
101        self,
102        match_maker_id: str,
103        entity_id: str,
104        options: MmFindMatchesOptions | None = None,
105    ) -> list[dict]:
106        """Find matches for an existing entity.
107
108        Returns list of MmEntityMatch dicts with:
109        id, content, categoryId, metadata, score, reasoning.
110        """
111        result = await self._http.post(
112            "squid-api/v1/ai/matchmaking/findMatches",
113            {
114                "matchMakerId": match_maker_id,
115                "entityId": entity_id,
116                "options": options or {},
117            },
118        )
119        return result.get("matches", []) if result else []

Find matches for an existing entity.

Returns list of MmEntityMatch dicts with: id, content, categoryId, metadata, score, reasoning.

async def find_matches_for_entity( self, match_maker_id: str, entity: MmEntity, options: MmFindMatchesOptions | None = None) -> list[dict]:
121    async def find_matches_for_entity(
122        self,
123        match_maker_id: str,
124        entity: MmEntity,
125        options: MmFindMatchesOptions | None = None,
126    ) -> list[dict]:
127        """Find matches for a new entity (not yet inserted)."""
128        result = await self._http.post(
129            "squid-api/v1/ai/matchmaking/findMatchesForEntity",
130            {
131                "matchMakerId": match_maker_id,
132                "entity": entity,
133                "options": options or {},
134            },
135        )
136        return result.get("matches", []) if result else []

Find matches for a new entity (not yet inserted).

class MmCategory(typing.TypedDict):
777class MmCategory(TypedDict):
778    """Matchmaking category."""
779
780    id: str
781    description: str

Matchmaking category.

id: str
description: str
class MmEntity(typing.TypedDict):
784class MmEntity(TypedDict, total=False):
785    """Matchmaking entity."""
786
787    id: str
788    content: str
789    categoryId: str
790    metadata: dict[str, Any]

Matchmaking entity.

id: str
content: str
categoryId: str
metadata: dict[str, typing.Any]
class MmFindMatchesOptions(typing.TypedDict):
793class MmFindMatchesOptions(TypedDict, total=False):
794    """Options for finding matches."""
795
796    metadataFilter: dict[str, Any]
797    """AiContextMetadataFilter conditions."""
798    limit: int
799    """Max matches to return (default 100, max 100)."""
800    matchToCategoryId: str
801    """Category to match against."""

Options for finding matches.

metadataFilter: dict[str, typing.Any]

AiContextMetadataFilter conditions.

limit: int

Max matches to return (default 100, max 100).

matchToCategoryId: str

Category to match against.

class MmListEntitiesOptions(typing.TypedDict):
804class MmListEntitiesOptions(TypedDict, total=False):
805    """Options for listing entities."""
806
807    metadataFilter: dict[str, Any]
808    limit: int

Options for listing entities.

metadataFilter: dict[str, typing.Any]
limit: int
class ModelIdSpec(typing.TypedDict):
45class ModelIdSpec(TypedDict, total=False):
46    """An AI chat model available to the app.
47
48    Returned by :meth:`AiClient.list_chat_models`.
49    """
50
51    modelId: AiChatModelName
52    """The model ID used for API calls. Required."""
53    integrationId: str
54    """The integration ID if this model comes from an integration (OpenAI-compatible,
55    Bedrock). Absent for Squid-provided models."""
56    displayName: str
57    """Human-readable display name for the model (e.g. 'GPT-4o')."""
58    description: str
59    """Short human-readable description of the model. Absent for custom integration models."""
60    replacedBy: AiChatModelName
61    """Set only for deprecated models: the active model that calls to this model are
62    routed to. Absent for active models."""
63    source: AiModelSource
64    """Where the model comes from: 'vendor' (Squid-provided), 'connector' (provided by an
65    integration configured on the app), or 'custom' (user-added model from the app's bundle)."""

An AI chat model available to the app.

Returned by AiClient.list_chat_models().

modelId: str

The model ID used for API calls. Required.

integrationId: str

The integration ID if this model comes from an integration (OpenAI-compatible, Bedrock). Absent for Squid-provided models.

displayName: str

Human-readable display name for the model (e.g. 'GPT-4o').

description: str

Short human-readable description of the model. Absent for custom integration models.

replacedBy: str

Set only for deprecated models: the active model that calls to this model are routed to. Absent for active models.

source: Literal['vendor', 'connector', 'custom']

Where the model comes from: 'vendor' (Squid-provided), 'connector' (provided by an integration configured on the app), or 'custom' (user-added model from the app's bundle).

class Squid:
 24class Squid:
 25    """Squid Cloud Python client.
 26
 27    The main entry point for interacting with the Squid Cloud platform.
 28    Provides access to AI agents, knowledge bases, web utilities,
 29    matchmaking, document extraction, backend functions, and webhooks.
 30
 31    Usage::
 32
 33        squid = Squid(
 34            app_id="my-app",
 35            api_key="sk-...",
 36            region="us-east-1.aws",
 37            environment_id="dev",
 38        )
 39
 40        # AI agent
 41        response = await squid.ai().agent("my-agent").ask("Hello!")
 42
 43        # Execute backend function
 44        result = await squid.execute_function("MyService:greet", "World")
 45
 46        # Web search
 47        results = await squid.web().ai_search("latest news")
 48
 49        # Cleanup
 50        await squid.close()
 51
 52    Can also be used as an async context manager::
 53
 54        async with Squid(app_id="my-app", api_key="sk-...", region="us-east-1.aws") as squid:
 55            result = await squid.ai().agent("my-agent").ask("Hello!")
 56    """
 57
 58    def __init__(
 59        self,
 60        app_id: str,
 61        region: str,
 62        api_key: str | None = None,
 63        environment_id: str | None = None,
 64        squid_developer_id: str | None = None,
 65    ) -> None:
 66        """Initialize the Squid client.
 67
 68        Args:
 69            app_id: The Squid application ID.
 70            region: The deployment region (e.g., 'us-east-1.aws', 'local').
 71            api_key: API key for authentication. Required for most operations.
 72            environment_id: Environment identifier (e.g., 'dev', 'prod').
 73                Appended to app_id as '{app_id}-{environment_id}'.
 74            squid_developer_id: Developer identifier for local development.
 75                Appended to app_id as '{app_id}-{environment_id}-{developer_id}'.
 76        """
 77        self._app_id = app_id
 78        self._region = region
 79        self._environment_id = environment_id
 80        self._squid_developer_id = squid_developer_id
 81
 82        full_app_id = app_id
 83        if environment_id:
 84            full_app_id = f"{app_id}-{environment_id}"
 85        if squid_developer_id:
 86            full_app_id = f"{full_app_id}-{squid_developer_id}"
 87
 88        self._full_app_id = full_app_id
 89        self._http = HttpTransport(
 90            app_id=full_app_id,
 91            region=region,
 92            api_key=api_key,
 93        )
 94
 95    @property
 96    def app_id(self) -> str:
 97        """The application ID (without environment/developer suffix)."""
 98        return self._app_id
 99
100    @property
101    def region(self) -> str:
102        """The deployment region."""
103        return self._region
104
105    @property
106    def client_id(self) -> str:
107        """The unique client instance ID (UUID generated per Squid instance)."""
108        return self._http.client_id
109
110    # --- Sub-clients ---
111
112    def ai(self) -> AiClient:
113        """Access AI operations.
114
115        Provides access to AI agents, knowledge bases, image generation,
116        and audio transcription/synthesis.
117
118        Returns:
119            An :class:`AiClient` instance.
120
121        Example::
122
123            agent = squid.ai().agent("my-agent")
124            response = await agent.ask("What is the weather?")
125
126            kb = squid.ai().knowledge_base("my-kb")
127            results = await kb.search("query")
128        """
129        return AiClient(self._http)
130
131    def web(self) -> WebClient:
132        """Access web utilities.
133
134        Provides AI-powered web search, URL content extraction,
135        and short URL management.
136
137        Returns:
138            A :class:`WebClient` instance.
139
140        Example::
141
142            content = await squid.web().get_url_content("https://example.com")
143            results = await squid.web().ai_search("latest AI news")
144        """
145        return WebClient(self._http)
146
147    def matchmaking(self) -> MatchmakingClient:
148        """Access AI-powered matchmaking.
149
150        Provides match maker management, entity CRUD,
151        and AI-powered entity matching.
152
153        Returns:
154            A :class:`MatchmakingClient` instance.
155
156        Example::
157
158            mm = squid.matchmaking()
159            await mm.create_match_maker("jobs", "Job matching", categories=[...])
160            matches = await mm.find_matches("jobs", "entity-1")
161        """
162        return MatchmakingClient(self._http)
163
164    def extraction(self) -> ExtractionClient:
165        """Access document extraction and PDF creation.
166
167        Provides PDF generation from HTML or URLs, and structured data
168        extraction from documents (PDF, DOCX, images, etc.).
169
170        Returns:
171            An :class:`ExtractionClient` instance.
172
173        Example::
174
175            pdf = await squid.extraction().create_pdf_from_html("<h1>Hello</h1>")
176            data = await squid.extraction().extract_data_from_document_url(
177                "https://example.com/doc.pdf"
178            )
179        """
180        return ExtractionClient(self._http)
181
182    # --- Execute backend function ---
183
184    async def execute_function(
185        self,
186        function_name: str,
187        *params: Any,
188    ) -> Any:
189        """Execute a backend function by name.
190
191        Calls a function defined in a Squid backend service using the
192        ``@executable()`` decorator.
193
194        Args:
195            function_name: The service function name in the format
196                ``"ClassName:methodName"`` (e.g., ``"MyService:greet"``).
197            *params: Positional arguments to pass to the function.
198                Must be JSON-serializable.
199
200        Returns:
201            The function's return value, deserialized from JSON.
202
203        Raises:
204            SquidHttpError: If the function is not found or throws an error.
205
206        Example::
207
208            result = await squid.execute_function("MyService:greet", "World")
209            # result == "Hello, World!"
210
211            data = await squid.execute_function("MyService:getData", 42, True)
212        """
213        result = await self._http.post(
214            f"backend-function/execute?{function_name}",
215            {
216                "functionName": function_name,
217                "paramsArrayStr": json.dumps(list(params)),
218            },
219        )
220        if isinstance(result, dict):
221            payload = result.get("payload")
222            if isinstance(payload, str):
223                return json.loads(payload)
224            return payload
225        return result
226
227    # --- Execute webhook ---
228
229    async def execute_webhook(
230        self,
231        webhook_id: str,
232        *,
233        body: Any = None,
234        headers: dict[str, str] | None = None,
235        method: str = "POST",
236    ) -> Any:
237        """Execute a webhook.
238
239        Calls a webhook endpoint defined in a Squid backend service
240        using the ``@webhook()`` decorator.
241
242        Args:
243            webhook_id: The webhook ID as defined in the ``@webhook("id")`` decorator.
244            body: The request body to send. Must be JSON-serializable.
245            headers: Extra HTTP headers to include in the request.
246            method: The HTTP method to use (default ``"POST"``).
247
248        Returns:
249            The webhook's response body, deserialized from JSON.
250
251        Raises:
252            SquidHttpError: If the webhook is not found or returns an error.
253
254        Example::
255
256            result = await squid.execute_webhook("my-hook", body={"key": "value"})
257        """
258        return await self._http.post(
259            f"webhooks/{webhook_id}",
260            body,
261            extra_headers=headers,
262        )
263
264    def get_webhook_url(self, webhook_id: str) -> str:
265        """Get the full URL for a webhook endpoint.
266
267        Useful for providing the webhook URL to external services that
268        need to send HTTP requests to your Squid backend.
269
270        Args:
271            webhook_id: The webhook ID.
272
273        Returns:
274            The full URL string (e.g.,
275            ``"https://myapp.us-east-1.aws.squid.cloud/webhooks/my-hook"``).
276
277        Example::
278
279            url = squid.get_webhook_url("stripe-events")
280            # url == "https://myapp-dev.us-east-1.aws.squid.cloud/webhooks/stripe-events"
281        """
282        return build_url(self._region, self._full_app_id, f"webhooks/{webhook_id}")
283
284    # --- AI Query ---
285
286    async def execute_ai_query(
287        self,
288        integration_id: str,
289        prompt: str,
290        *,
291        options: AiQueryOptions | None = None,
292        response_format: dict[str, Any] | None = None,
293    ) -> dict:
294        """Execute an AI-powered database query.
295
296        Uses AI to generate and execute database queries based on a
297        natural language prompt.
298
299        Args:
300            integration_id: The database integration ID to query against.
301            prompt: A natural language description of the data you want.
302            options: Optional :class:`AiQueryOptions` controlling collection
303                selection, query generation (including ``allowClarification``),
304                result analysis (including ``enableCodeInterpreter``), memory,
305                AI validation, per-stage model overrides via ``aiOptions``,
306                and custom instructions.
307            response_format: Optional structured output format, e.g.,
308                ``{"type": "json_schema", "schema": {...}}``.
309
310        Returns:
311            An ``AiQueryResponse`` dict containing:
312                - ``answer`` (str): The AI-generated answer.
313                - ``explanation`` (str): How the answer was derived.
314                - ``executedQueries`` (list): The actual queries that were run.
315                - ``success`` (bool): Whether the query succeeded.
316                - ``usedCodeInterpreter`` (bool): Whether the code
317                  interpreter was used to analyze results.
318                - ``clarificationQuestion`` (str): If the AI needs more info.
319
320        Example::
321
322            result = await squid.execute_ai_query(
323                "my-database",
324                "How many users signed up last week?",
325                options={
326                    "selectCollectionsOptions": {"collectionsToUse": ["users"]},
327                    "analyzeResultsOptions": {"enableCodeInterpreter": True},
328                },
329            )
330            print(result["answer"])
331        """
332        return await execute_ai_query(
333            self._http,
334            integration_id,
335            prompt,
336            options=options,
337            response_format=response_format,
338        )
339
340    # --- Lifecycle ---
341
342    async def close(self) -> None:
343        """Close the HTTP client and release resources.
344
345        Should be called when the Squid client is no longer needed.
346        Alternatively, use the client as an async context manager.
347        """
348        await self._http.close()
349
350    async def __aenter__(self) -> Squid:
351        """Enter async context manager."""
352        return self
353
354    async def __aexit__(self, *args: Any) -> None:
355        """Exit async context manager and close resources."""
356        await self.close()

Squid Cloud Python client.

The main entry point for interacting with the Squid Cloud platform. Provides access to AI agents, knowledge bases, web utilities, matchmaking, document extraction, backend functions, and webhooks.

Usage::

squid = Squid(
    app_id="my-app",
    api_key="sk-...",
    region="us-east-1.aws",
    environment_id="dev",
)

# AI agent
response = await squid.ai().agent("my-agent").ask("Hello!")

# Execute backend function
result = await squid.execute_function("MyService:greet", "World")

# Web search
results = await squid.web().ai_search("latest news")

# Cleanup
await squid.close()

Can also be used as an async context manager::

async with Squid(app_id="my-app", api_key="sk-...", region="us-east-1.aws") as squid:
    result = await squid.ai().agent("my-agent").ask("Hello!")
Squid( app_id: str, region: str, api_key: str | None = None, environment_id: str | None = None, squid_developer_id: str | None = None)
58    def __init__(
59        self,
60        app_id: str,
61        region: str,
62        api_key: str | None = None,
63        environment_id: str | None = None,
64        squid_developer_id: str | None = None,
65    ) -> None:
66        """Initialize the Squid client.
67
68        Args:
69            app_id: The Squid application ID.
70            region: The deployment region (e.g., 'us-east-1.aws', 'local').
71            api_key: API key for authentication. Required for most operations.
72            environment_id: Environment identifier (e.g., 'dev', 'prod').
73                Appended to app_id as '{app_id}-{environment_id}'.
74            squid_developer_id: Developer identifier for local development.
75                Appended to app_id as '{app_id}-{environment_id}-{developer_id}'.
76        """
77        self._app_id = app_id
78        self._region = region
79        self._environment_id = environment_id
80        self._squid_developer_id = squid_developer_id
81
82        full_app_id = app_id
83        if environment_id:
84            full_app_id = f"{app_id}-{environment_id}"
85        if squid_developer_id:
86            full_app_id = f"{full_app_id}-{squid_developer_id}"
87
88        self._full_app_id = full_app_id
89        self._http = HttpTransport(
90            app_id=full_app_id,
91            region=region,
92            api_key=api_key,
93        )

Initialize the Squid client.

Arguments:
  • app_id: The Squid application ID.
  • region: The deployment region (e.g., 'us-east-1.aws', 'local').
  • api_key: API key for authentication. Required for most operations.
  • environment_id: Environment identifier (e.g., 'dev', 'prod'). Appended to app_id as '{app_id}-{environment_id}'.
  • squid_developer_id: Developer identifier for local development. Appended to app_id as '{app_id}-{environment_id}-{developer_id}'.
app_id: str
95    @property
96    def app_id(self) -> str:
97        """The application ID (without environment/developer suffix)."""
98        return self._app_id

The application ID (without environment/developer suffix).

region: str
100    @property
101    def region(self) -> str:
102        """The deployment region."""
103        return self._region

The deployment region.

client_id: str
105    @property
106    def client_id(self) -> str:
107        """The unique client instance ID (UUID generated per Squid instance)."""
108        return self._http.client_id

The unique client instance ID (UUID generated per Squid instance).

def ai(self) -> AiClient:
112    def ai(self) -> AiClient:
113        """Access AI operations.
114
115        Provides access to AI agents, knowledge bases, image generation,
116        and audio transcription/synthesis.
117
118        Returns:
119            An :class:`AiClient` instance.
120
121        Example::
122
123            agent = squid.ai().agent("my-agent")
124            response = await agent.ask("What is the weather?")
125
126            kb = squid.ai().knowledge_base("my-kb")
127            results = await kb.search("query")
128        """
129        return AiClient(self._http)

Access AI operations.

Provides access to AI agents, knowledge bases, image generation, and audio transcription/synthesis.

Returns:

An AiClient instance.

Example::

agent = squid.ai().agent("my-agent")
response = await agent.ask("What is the weather?")

kb = squid.ai().knowledge_base("my-kb")
results = await kb.search("query")
def web(self) -> WebClient:
131    def web(self) -> WebClient:
132        """Access web utilities.
133
134        Provides AI-powered web search, URL content extraction,
135        and short URL management.
136
137        Returns:
138            A :class:`WebClient` instance.
139
140        Example::
141
142            content = await squid.web().get_url_content("https://example.com")
143            results = await squid.web().ai_search("latest AI news")
144        """
145        return WebClient(self._http)

Access web utilities.

Provides AI-powered web search, URL content extraction, and short URL management.

Returns:

A WebClient instance.

Example::

content = await squid.web().get_url_content("https://example.com")
results = await squid.web().ai_search("latest AI news")
def matchmaking(self) -> MatchmakingClient:
147    def matchmaking(self) -> MatchmakingClient:
148        """Access AI-powered matchmaking.
149
150        Provides match maker management, entity CRUD,
151        and AI-powered entity matching.
152
153        Returns:
154            A :class:`MatchmakingClient` instance.
155
156        Example::
157
158            mm = squid.matchmaking()
159            await mm.create_match_maker("jobs", "Job matching", categories=[...])
160            matches = await mm.find_matches("jobs", "entity-1")
161        """
162        return MatchmakingClient(self._http)

Access AI-powered matchmaking.

Provides match maker management, entity CRUD, and AI-powered entity matching.

Returns:

A MatchmakingClient instance.

Example::

mm = squid.matchmaking()
await mm.create_match_maker("jobs", "Job matching", categories=[...])
matches = await mm.find_matches("jobs", "entity-1")
def extraction(self) -> ExtractionClient:
164    def extraction(self) -> ExtractionClient:
165        """Access document extraction and PDF creation.
166
167        Provides PDF generation from HTML or URLs, and structured data
168        extraction from documents (PDF, DOCX, images, etc.).
169
170        Returns:
171            An :class:`ExtractionClient` instance.
172
173        Example::
174
175            pdf = await squid.extraction().create_pdf_from_html("<h1>Hello</h1>")
176            data = await squid.extraction().extract_data_from_document_url(
177                "https://example.com/doc.pdf"
178            )
179        """
180        return ExtractionClient(self._http)

Access document extraction and PDF creation.

Provides PDF generation from HTML or URLs, and structured data extraction from documents (PDF, DOCX, images, etc.).

Returns:

An ExtractionClient instance.

Example::

pdf = await squid.extraction().create_pdf_from_html("<h1>Hello</h1>")
data = await squid.extraction().extract_data_from_document_url(
    "https://example.com/doc.pdf"
)
async def execute_function(self, function_name: str, *params: Any) -> Any:
184    async def execute_function(
185        self,
186        function_name: str,
187        *params: Any,
188    ) -> Any:
189        """Execute a backend function by name.
190
191        Calls a function defined in a Squid backend service using the
192        ``@executable()`` decorator.
193
194        Args:
195            function_name: The service function name in the format
196                ``"ClassName:methodName"`` (e.g., ``"MyService:greet"``).
197            *params: Positional arguments to pass to the function.
198                Must be JSON-serializable.
199
200        Returns:
201            The function's return value, deserialized from JSON.
202
203        Raises:
204            SquidHttpError: If the function is not found or throws an error.
205
206        Example::
207
208            result = await squid.execute_function("MyService:greet", "World")
209            # result == "Hello, World!"
210
211            data = await squid.execute_function("MyService:getData", 42, True)
212        """
213        result = await self._http.post(
214            f"backend-function/execute?{function_name}",
215            {
216                "functionName": function_name,
217                "paramsArrayStr": json.dumps(list(params)),
218            },
219        )
220        if isinstance(result, dict):
221            payload = result.get("payload")
222            if isinstance(payload, str):
223                return json.loads(payload)
224            return payload
225        return result

Execute a backend function by name.

Calls a function defined in a Squid backend service using the @executable() decorator.

Arguments:
  • function_name: The service function name in the format "ClassName:methodName" (e.g., "MyService:greet").
  • *params: Positional arguments to pass to the function. Must be JSON-serializable.
Returns:

The function's return value, deserialized from JSON.

Raises:
  • SquidHttpError: If the function is not found or throws an error.

Example::

result = await squid.execute_function("MyService:greet", "World")
# result == "Hello, World!"

data = await squid.execute_function("MyService:getData", 42, True)
async def execute_webhook( self, webhook_id: str, *, body: Any = None, headers: dict[str, str] | None = None, method: str = 'POST') -> Any:
229    async def execute_webhook(
230        self,
231        webhook_id: str,
232        *,
233        body: Any = None,
234        headers: dict[str, str] | None = None,
235        method: str = "POST",
236    ) -> Any:
237        """Execute a webhook.
238
239        Calls a webhook endpoint defined in a Squid backend service
240        using the ``@webhook()`` decorator.
241
242        Args:
243            webhook_id: The webhook ID as defined in the ``@webhook("id")`` decorator.
244            body: The request body to send. Must be JSON-serializable.
245            headers: Extra HTTP headers to include in the request.
246            method: The HTTP method to use (default ``"POST"``).
247
248        Returns:
249            The webhook's response body, deserialized from JSON.
250
251        Raises:
252            SquidHttpError: If the webhook is not found or returns an error.
253
254        Example::
255
256            result = await squid.execute_webhook("my-hook", body={"key": "value"})
257        """
258        return await self._http.post(
259            f"webhooks/{webhook_id}",
260            body,
261            extra_headers=headers,
262        )

Execute a webhook.

Calls a webhook endpoint defined in a Squid backend service using the @webhook() decorator.

Arguments:
  • webhook_id: The webhook ID as defined in the @webhook("id") decorator.
  • body: The request body to send. Must be JSON-serializable.
  • headers: Extra HTTP headers to include in the request.
  • method: The HTTP method to use (default "POST").
Returns:

The webhook's response body, deserialized from JSON.

Raises:
  • SquidHttpError: If the webhook is not found or returns an error.

Example::

result = await squid.execute_webhook("my-hook", body={"key": "value"})
def get_webhook_url(self, webhook_id: str) -> str:
264    def get_webhook_url(self, webhook_id: str) -> str:
265        """Get the full URL for a webhook endpoint.
266
267        Useful for providing the webhook URL to external services that
268        need to send HTTP requests to your Squid backend.
269
270        Args:
271            webhook_id: The webhook ID.
272
273        Returns:
274            The full URL string (e.g.,
275            ``"https://myapp.us-east-1.aws.squid.cloud/webhooks/my-hook"``).
276
277        Example::
278
279            url = squid.get_webhook_url("stripe-events")
280            # url == "https://myapp-dev.us-east-1.aws.squid.cloud/webhooks/stripe-events"
281        """
282        return build_url(self._region, self._full_app_id, f"webhooks/{webhook_id}")

Get the full URL for a webhook endpoint.

Useful for providing the webhook URL to external services that need to send HTTP requests to your Squid backend.

Arguments:
  • webhook_id: The webhook ID.
Returns:

The full URL string (e.g., "https://myapp.us-east-1.aws.squid.cloud/webhooks/my-hook").

Example::

url = squid.get_webhook_url("stripe-events")
# url == "https://myapp-dev.us-east-1.aws.squid.cloud/webhooks/stripe-events"
async def execute_ai_query( self, integration_id: str, prompt: str, *, options: AiQueryOptions | None = None, response_format: dict[str, Any] | None = None) -> dict:
286    async def execute_ai_query(
287        self,
288        integration_id: str,
289        prompt: str,
290        *,
291        options: AiQueryOptions | None = None,
292        response_format: dict[str, Any] | None = None,
293    ) -> dict:
294        """Execute an AI-powered database query.
295
296        Uses AI to generate and execute database queries based on a
297        natural language prompt.
298
299        Args:
300            integration_id: The database integration ID to query against.
301            prompt: A natural language description of the data you want.
302            options: Optional :class:`AiQueryOptions` controlling collection
303                selection, query generation (including ``allowClarification``),
304                result analysis (including ``enableCodeInterpreter``), memory,
305                AI validation, per-stage model overrides via ``aiOptions``,
306                and custom instructions.
307            response_format: Optional structured output format, e.g.,
308                ``{"type": "json_schema", "schema": {...}}``.
309
310        Returns:
311            An ``AiQueryResponse`` dict containing:
312                - ``answer`` (str): The AI-generated answer.
313                - ``explanation`` (str): How the answer was derived.
314                - ``executedQueries`` (list): The actual queries that were run.
315                - ``success`` (bool): Whether the query succeeded.
316                - ``usedCodeInterpreter`` (bool): Whether the code
317                  interpreter was used to analyze results.
318                - ``clarificationQuestion`` (str): If the AI needs more info.
319
320        Example::
321
322            result = await squid.execute_ai_query(
323                "my-database",
324                "How many users signed up last week?",
325                options={
326                    "selectCollectionsOptions": {"collectionsToUse": ["users"]},
327                    "analyzeResultsOptions": {"enableCodeInterpreter": True},
328                },
329            )
330            print(result["answer"])
331        """
332        return await execute_ai_query(
333            self._http,
334            integration_id,
335            prompt,
336            options=options,
337            response_format=response_format,
338        )

Execute an AI-powered database query.

Uses AI to generate and execute database queries based on a natural language prompt.

Arguments:
  • integration_id: The database integration ID to query against.
  • prompt: A natural language description of the data you want.
  • options: Optional AiQueryOptions controlling collection selection, query generation (including allowClarification), result analysis (including enableCodeInterpreter), memory, AI validation, per-stage model overrides via aiOptions, and custom instructions.
  • response_format: Optional structured output format, e.g., {"type": "json_schema", "schema": {...}}.
Returns:

An AiQueryResponse dict containing: - answer (str): The AI-generated answer. - explanation (str): How the answer was derived. - executedQueries (list): The actual queries that were run. - success (bool): Whether the query succeeded. - usedCodeInterpreter (bool): Whether the code interpreter was used to analyze results. - clarificationQuestion (str): If the AI needs more info.

Example::

result = await squid.execute_ai_query(
    "my-database",
    "How many users signed up last week?",
    options={
        "selectCollectionsOptions": {"collectionsToUse": ["users"]},
        "analyzeResultsOptions": {"enableCodeInterpreter": True},
    },
)
print(result["answer"])
async def close(self) -> None:
342    async def close(self) -> None:
343        """Close the HTTP client and release resources.
344
345        Should be called when the Squid client is no longer needed.
346        Alternatively, use the client as an async context manager.
347        """
348        await self._http.close()

Close the HTTP client and release resources.

Should be called when the Squid client is no longer needed. Alternatively, use the client as an async context manager.

class SquidHttpError(builtins.Exception):
81class SquidHttpError(Exception):
82    """Raised when the Squid API returns an HTTP error response (status >= 400).
83
84    Attributes:
85        status_code: The HTTP status code.
86        url: The URL that was requested.
87        body: The parsed response body, if available.
88    """
89
90    def __init__(self, status_code: int, message: str, url: str, body: Any = None):
91        self.status_code = status_code
92        self.url = url
93        self.body = body
94        super().__init__(f"HTTP {status_code}: {message} (url={url})")

Raised when the Squid API returns an HTTP error response (status >= 400).

Attributes:
  • status_code: The HTTP status code.
  • url: The URL that was requested.
  • body: The parsed response body, if available.
SquidHttpError(status_code: int, message: str, url: str, body: Any = None)
90    def __init__(self, status_code: int, message: str, url: str, body: Any = None):
91        self.status_code = status_code
92        self.url = url
93        self.body = body
94        super().__init__(f"HTTP {status_code}: {message} (url={url})")
status_code
url
body
class StableDiffusionOptions(typing.TypedDict):
760class StableDiffusionOptions(TypedDict, total=False):
761    """Options for Stable Diffusion Core image generation."""
762
763    modelName: Literal["stable-diffusion-core"]
764    aspectRatio: Literal["16:9", "1:1", "21:9", "2:3", "3:2", "4:5", "5:4", "9:16", "9:21"]
765    negativePrompt: str
766    seed: int
767    stylePreset: str
768    outputFormat: str

Options for Stable Diffusion Core image generation.

modelName: Literal['stable-diffusion-core']
aspectRatio: Literal['16:9', '1:1', '21:9', '2:3', '3:2', '4:5', '5:4', '9:16', '9:21']
negativePrompt: str
seed: int
stylePreset: str
outputFormat: str
class TextContextRequest(typing.TypedDict):
567class TextContextRequest(TypedDict, total=False):
568    """Request to upsert a text context."""
569
570    contextId: str
571    type: Literal["text"]
572    title: str
573    text: str
574    metadata: dict[str, Any]
575    options: AiContextTextOptions

Request to upsert a text context.

contextId: str
type: Literal['text']
title: str
text: str
metadata: dict[str, typing.Any]
class UpsertAgentOptions(typing.TypedDict):
380class UpsertAgentOptions(TypedDict, total=False):
381    """Options for creating/updating an agent."""
382
383    description: str
384    """Description of the agent's purpose."""
385    isPublic: bool
386    """Whether the agent is publicly accessible."""
387    auditLog: bool
388    """Enable audit logging."""
389    auditLogFullContext: bool
390    """Record the full agent context (system instructions and retrieved knowledge-base content) in the audit log."""
391    apiKey: str
392    """API key for this agent."""
393    mcpServer: AiAgentMcpServerConfig
394    """Optional configuration for exposing the agent as an MCP server."""
395    options: AiChatOptions
396    """Default chat options."""

Options for creating/updating an agent.

description: str

Description of the agent's purpose.

isPublic: bool

Whether the agent is publicly accessible.

auditLog: bool

Enable audit logging.

auditLogFullContext: bool

Record the full agent context (system instructions and retrieved knowledge-base content) in the audit log.

apiKey: str

API key for this agent.

Optional configuration for exposing the agent as an MCP server.

options: AiChatOptions

Default chat options.

VectorDbType = typing.Literal['postgres', 'mongoAtlas']
class WebAiSearchResponse(typing.TypedDict):
878class WebAiSearchResponse(TypedDict):
879    """Response from AI web search."""
880
881    markdownText: str
882    citedUrls: list[dict[str, str]]
883    """Pages the answer cites. A terse answer cites nothing even when the search ran."""
884
885    consultedUrls: list[str]
886    """Pages the search opened, whether or not the answer cites them."""

Response from AI web search.

markdownText: str
citedUrls: list[dict[str, str]]

Pages the answer cites. A terse answer cites nothing even when the search ran.

consultedUrls: list[str]

Pages the search opened, whether or not the answer cites them.

class WebClient:
16class WebClient:
17    """Web utilities: AI search, URL content, short URLs."""
18
19    def __init__(self, http: HttpTransport) -> None:
20        self._http = http
21
22    async def ai_search(
23        self, query: str, allowed_domains: list[str] | None = None
24    ) -> WebAiSearchResponse:
25        """Perform an AI-powered web search.
26
27        When allowed_domains is provided, the search is restricted to those domains
28        (subdomains included) and every URL in the response -- cited or consulted --
29        belongs to one of them. Squid enforces this over the consulted pages;
30        citations arrive already restricted.
31
32        Returns WebAiSearchResponse with 'markdownText', 'citedUrls' and 'consultedUrls'.
33        """
34        body: dict[str, object] = {"query": query}
35        if allowed_domains is not None:
36            body["allowedDomains"] = allowed_domains
37        return await self._http.post("squid-api/v1/web/aiSearch", body)
38
39    async def get_url_content(self, url: str) -> str:
40        """Fetch and extract content from a URL as markdown."""
41        result = await self._http.post("squid-api/v1/web/getUrlContent", {"url": url})
42        if isinstance(result, dict):
43            return result.get("markdownText", "")
44        return str(result) if result else ""
45
46    async def create_short_url(
47        self,
48        url: str,
49        *,
50        seconds_to_live: int | None = None,
51        file_extension: str | None = None,
52    ) -> WebShortUrlResponse:
53        """Create a short URL.
54
55        Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'.
56        """
57        body: dict = {"url": url}
58        if seconds_to_live is not None:
59            body["secondsToLive"] = seconds_to_live
60        if file_extension is not None:
61            body["fileExtension"] = file_extension
62        return await self._http.post("squid-api/v1/web/createShortUrl", body)
63
64    async def create_short_urls(
65        self,
66        urls: list[str],
67        *,
68        seconds_to_live: int | None = None,
69        file_extension: str | None = None,
70    ) -> WebShortUrlBulkResponse:
71        """Create multiple short URLs in bulk.
72
73        Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'.
74        """
75        body: dict = {"urls": urls}
76        if seconds_to_live is not None:
77            body["secondsToLive"] = seconds_to_live
78        if file_extension is not None:
79            body["fileExtension"] = file_extension
80        return await self._http.post("squid-api/v1/web/createShortUrls", body)
81
82    async def delete_short_url(self, url_id: str) -> None:
83        """Delete a short URL."""
84        await self._http.post("squid-api/v1/web/deleteShortUrl", {"id": url_id})
85
86    async def delete_short_urls(self, url_ids: list[str]) -> None:
87        """Delete multiple short URLs."""
88        await self._http.post("squid-api/v1/web/deleteShortUrls", {"ids": url_ids})

Web utilities: AI search, URL content, short URLs.

WebClient(http: squidcloud.http.HttpTransport)
19    def __init__(self, http: HttpTransport) -> None:
20        self._http = http
async def get_url_content(self, url: str) -> str:
39    async def get_url_content(self, url: str) -> str:
40        """Fetch and extract content from a URL as markdown."""
41        result = await self._http.post("squid-api/v1/web/getUrlContent", {"url": url})
42        if isinstance(result, dict):
43            return result.get("markdownText", "")
44        return str(result) if result else ""

Fetch and extract content from a URL as markdown.

async def create_short_url( self, url: str, *, seconds_to_live: int | None = None, file_extension: str | None = None) -> WebShortUrlResponse:
46    async def create_short_url(
47        self,
48        url: str,
49        *,
50        seconds_to_live: int | None = None,
51        file_extension: str | None = None,
52    ) -> WebShortUrlResponse:
53        """Create a short URL.
54
55        Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'.
56        """
57        body: dict = {"url": url}
58        if seconds_to_live is not None:
59            body["secondsToLive"] = seconds_to_live
60        if file_extension is not None:
61            body["fileExtension"] = file_extension
62        return await self._http.post("squid-api/v1/web/createShortUrl", body)

Create a short URL.

Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'.

async def create_short_urls( self, urls: list[str], *, seconds_to_live: int | None = None, file_extension: str | None = None) -> WebShortUrlBulkResponse:
64    async def create_short_urls(
65        self,
66        urls: list[str],
67        *,
68        seconds_to_live: int | None = None,
69        file_extension: str | None = None,
70    ) -> WebShortUrlBulkResponse:
71        """Create multiple short URLs in bulk.
72
73        Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'.
74        """
75        body: dict = {"urls": urls}
76        if seconds_to_live is not None:
77            body["secondsToLive"] = seconds_to_live
78        if file_extension is not None:
79            body["fileExtension"] = file_extension
80        return await self._http.post("squid-api/v1/web/createShortUrls", body)

Create multiple short URLs in bulk.

Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'.

async def delete_short_url(self, url_id: str) -> None:
82    async def delete_short_url(self, url_id: str) -> None:
83        """Delete a short URL."""
84        await self._http.post("squid-api/v1/web/deleteShortUrl", {"id": url_id})

Delete a short URL.

async def delete_short_urls(self, url_ids: list[str]) -> None:
86    async def delete_short_urls(self, url_ids: list[str]) -> None:
87        """Delete multiple short URLs."""
88        await self._http.post("squid-api/v1/web/deleteShortUrls", {"ids": url_ids})

Delete multiple short URLs.

class WebShortUrlBulkResponse(typing.TypedDict):
870class WebShortUrlBulkResponse(TypedDict):
871    """Response from creating bulk short URLs."""
872
873    ids: list[str]
874    shortUrls: list[str]
875    expiry: str

Response from creating bulk short URLs.

ids: list[str]
shortUrls: list[str]
expiry: str
class WebShortUrlResponse(typing.TypedDict):
862class WebShortUrlResponse(TypedDict):
863    """Response from creating a short URL."""
864
865    id: str
866    shortUrl: str
867    expiry: str

Response from creating a short URL.

id: str
shortUrl: str
expiry: str