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-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-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-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-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-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-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-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-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-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):
395class AiAgent(TypedDict, total=False):
396    """A definition of an AI agent with its properties and default chat options.
397
398    Returned by :meth:`AiClient.list_agents`.
399    """
400
401    id: str
402    """The unique identifier of the AI agent. Required."""
403    createdAt: str
404    """ISO 8601 timestamp of when the agent was created. Required."""
405    updatedAt: str
406    """ISO 8601 timestamp of when the agent was last updated. Required."""
407    description: str
408    """An optional description of the agent's purpose or capabilities."""
409    isPublic: bool
410    """Whether the agent is publicly accessible; defaults to False."""
411    auditLog: bool
412    """Whether audit logging is enabled for the agent's activities; defaults to False."""
413    auditLogFullContext: bool
414    """Whether the full agent context (system instructions and retrieved knowledge-base content) is recorded in the audit log; requires auditLog; defaults to False."""
415    options: AiChatOptions
416    """The agent's default chat options, overridable by the user during use. Required."""
417    apiKey: str
418    """Optional API key used specifically for operations on this agent."""
419    mcpServer: AiAgentMcpServerConfig
420    """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):
361class AiAgentMcpServerConfig(TypedDict, total=False):
362    """Configuration for exposing an AI agent as an MCP server at ``/mcp/<agentId>``."""
363
364    enabled: bool
365    """Whether the agent is exposed as an MCP server. Required."""
366    description: str
367    """Description of the MCP server, served as the ``instructions`` field of the MCP initialize result."""
368    toolDescription: str
369    """Description of the MCP ``ask`` tool, exposed in the tools manifest."""
370    oauthIntegrationId: str
371    """ID of an auth integration used to OAuth-protect the MCP server."""
372    requireApiKey: bool
373    """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    smoothTyping: bool
223    """Smooth typing effect for UI display (default true)."""
224    disableContext: bool
225    """Disable the whole context for this request."""
226    enablePromptRewriteForRag: bool
227    """Rewrite prompt for RAG (default false)."""
228    agentContext: dict[str, Any]
229    """Global context passed to agent and all AI functions."""
230    connectedAgents: list[AiConnectedAgentMetadata]
231    """Connected agents that can be called."""
232    connectedIntegrations: list[AiConnectedIntegrationMetadata]
233    """Connected integrations."""
234    connectedKnowledgeBases: list[AiConnectedKnowledgeBaseMetadata]
235    """Connected knowledge bases."""
236    guardrails: GuardrailsOptions
237    """Guardrail options."""
238    pii: AiPiiOptions
239    """PII screening. Read from the stored agent only; ignored when passed with a request."""
240    contextMetadataFilterForKnowledgeBase: dict[str, Any]
241    """Metadata filters per knowledge base ID."""
242    voiceOptions: AiAudioCreateSpeechOptions
243    """Options for voice response."""
244    quotas: AiChatPromptQuotas
245    """Budget for nested AI calls."""
246    executionPlanOptions: AiAgentExecutionPlanOptions
247    """Execution plan options."""
248    fileUrls: list[AiFileUrl]
249    """File URLs to include in context."""
250    fileIds: list[str]
251    """File IDs from AI provider's Files API."""
252    reasoningEffort: AiReasoningEffort
253    """Reasoning effort level."""
254    verbosity: AiVerbosityLevel
255    """Response verbosity level."""
256    useCodeInterpreter: Literal["none", "llm"]
257    """Enable LLM's built-in code interpreter."""
258    rerankProvider: AiRerankProvider
259    """Reranker provider for context (default 'cohere')."""
260    includeMetadata: bool
261    """Include metadata in context (deprecated)."""
262    timeoutMs: int
263    """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.

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):
574class AiContextFileOptions(TypedDict, total=False):
575    """Options for file context processing."""
576
577    chunkOverlap: int
578    ragType: str

Options for file context processing.

chunkOverlap: int
ragType: str
class AiContextTextOptions(typing.TypedDict):
554class AiContextTextOptions(TypedDict, total=False):
555    """Options for text context processing."""
556
557    chunkOverlap: int
558    """Amount of chunk overlap in characters."""
559    ragType: str
560    """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):
692class AiFunctionAttributes(TypedDict, total=False):
693    """Additional optional readonly metadata for an AI function."""
694
695    integrationType: list[str]
696    """Types of integration this function is used for. Functions with a defined
697    '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):
700class AiFunctionMetadata(TypedDict, total=False):
701    """Metadata describing an AI function available in the application.
702
703    Returned by :meth:`AiClient.list_functions`.
704    """
705
706    serviceFunction: str
707    """The fully qualified name of the function ('ServiceName:functionName'). Required."""
708    description: str
709    """Description of what the function does."""
710    promptId: str
711    """Opaque ID of a registered prompt that supplies this function's description;
712    resolved server-side."""
713    params: list[AiFunctionParam]
714    """Parameters that the function accepts. Required."""
715    attributes: AiFunctionAttributes
716    """Additional attributes for the function."""
717    categories: list[str]
718    """Categories this function belongs to."""
719    internal: bool
720    """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):
677class AiFunctionParam(TypedDict, total=False):
678    """Defines the structure of a parameter for an AI function."""
679
680    name: str
681    """Name of the parameter. Required."""
682    description: str
683    """Description of the parameter's purpose. Required."""
684    type: AiFunctionParamType
685    """Data type of the parameter. Required."""
686    required: bool
687    """Indicates if the parameter is mandatory. Required."""
688    enum: list[str]
689    """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):
525class AiKnowledgeBase(TypedDict, total=False):
526    """An AI knowledge base that can be attached to an AI agent.
527
528    Returned by :meth:`AiClient.list_knowledge_bases`.
529    """
530
531    id: str
532    """The unique identifier of the knowledge base. Required."""
533    appId: str
534    """The app ID that the knowledge base belongs to. Required."""
535    description: str
536    """The user's description of the knowledge base. Required."""
537    metadataFields: list[AiKnowledgeBaseMetadataField]
538    """Predefined metadata fields that can be used for filtering. Required."""
539    embeddingModel: AiEmbeddingsModelSelection
540    """The embedding model used by this knowledge base. Required."""
541    chatModel: AiChatModelSelection
542    """The model used when asking questions of this knowledge base. Required."""
543    vectorDbType: VectorDbType
544    """The vector store backend the knowledge base reads/writes from. Set at creation
545    and immutable thereafter. Absent on older records."""
546    graphRag: AiKnowledgeBaseGraphConfig
547    """Opt-in GraphRAG configuration. Only honored for ``vectorDbType: 'mongoAtlas'``
548    knowledge bases; enables per-chunk entity/relationship extraction at ingest and
549    ``searchMode: 'graph'`` at query time."""
550    updatedAt: str
551    """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):
478class AiKnowledgeBaseGraphConceptsConfig(TypedDict, total=False):
479    """Configuration of the graph's concept layer (facet taxonomies)."""
480
481    facets: Union[list[str], Literal["auto"]]
482    """Which metadata fields become value facets. ``'auto'`` (the default) profiles the KB's
483    context metadata and selects the categorical fields; an explicit list overrides
484    auto-selection; an empty list disables value facets."""
485    pathFacets: list[AiKnowledgeBaseGraphPathFacetConfig]
486    """Explicit path facets, e.g. ``[{'field': 'folderPath', 'type': 'path'}]``. A path facet
487    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):
502class AiKnowledgeBaseGraphConfig(_AiKnowledgeBaseGraphConfigRequired, total=False):
503    """Per-knowledge-base GraphRAG configuration.
504
505    Opt-in and mutable (unlike ``embeddingModel``/``vectorDbType``); only honored for
506    ``vectorDbType: 'mongoAtlas'`` knowledge bases. Enabling it on a knowledge base that
507    already has content backfills the graph automatically once the KB goes quiet.
508
509    On upsert the supplied value replaces the stored config rather than merging into it,
510    so include every key that should remain set.
511    """
512
513    extractionModel: AiChatModelSelection
514    """Chat model used for per-chunk entity/relationship extraction. Defaults to the server's
515    graph model."""
516    entityTypes: list[str]
517    """Optional domain taxonomy hint (entity types) injected into the extraction prompt."""
518    autoBuildDebounceMs: int
519    """Quiet window (milliseconds) after the last graph activity before the sweep auto-builds
520    the structure. Must be a positive integer. Defaults to the server's window (5 minutes)."""
521    concepts: AiKnowledgeBaseGraphConceptsConfig
522    """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):
618class AiKnowledgeBaseGraphFilter(TypedDict):
619    """Graph scope for a knowledge-base search: restricts results to the documents under one
620    concept of the KB's graph. Composes with every ``searchMode``. Requires ``graphRag.enabled``."""
621
622    underConcept: str
623    """The concept to scope to: a facet nodeId (``facet_…`` — exact) or a concept name,
624    resolved server-side (exact, then alias, then similarity). An unresolvable ref fails with
625    ``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):
469class AiKnowledgeBaseGraphPathFacetConfig(
470    _AiKnowledgeBaseGraphPathFacetConfigRequired, total=False
471):
472    """A path facet: a deterministic tree built by splitting a hierarchical path field."""
473
474    separator: str
475    """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):
604class AiKnowledgeBaseGraphSearchOptions(TypedDict, total=False):
605    """Tuning for ``searchMode: 'graph'`` (GraphRAG) retrieval. Ignored for other search modes."""
606
607    seedLimit: int
608    """Entities seeded via vector search before graph expansion. Default 8, max 25."""
609    maxHops: int
610    """Number of hops to expand from each seed (traversal depth + 1). Default 2, max 3."""
611    includeGraphContext: bool
612    """When True, the server attaches the traversed subgraph to the search response as
613    ``graphContext``. Default False. Read it via
614    :meth:`~squidcloud.ai.KnowledgeBaseClient.search_with_graph_context`;
615    :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):
426class AiKnowledgeBaseMetadataField(TypedDict, total=False):
427    """Metadata field definition for a knowledge base."""
428
429    name: str
430    dataType: str
431    required: bool
432    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):
310class AiQueryAnalyzeResultsOptions(TypedDict, total=False):
311    """Options for the result-analysis stage of AI query."""
312
313    disabled: bool
314    """When true, skip analysis and return raw results only."""
315    enableCodeInterpreter: bool
316    """Enable code interpreter mode (default false)."""
317    aiOptions: AiChatOptions
318    """Customize AI agent behavior used by the stage."""
319    agentId: AiAgentId
320    """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):
296class AiQueryGenerateQueryOptions(TypedDict, total=False):
297    """Options for the query-generation stage of AI query."""
298
299    aiOptions: AiChatOptions
300    """Customize AI agent behavior used by the stage."""
301    maxErrorCorrections: int
302    """Number of retries due to errors in a generated AI query (default 2)."""
303    agentId: AiAgentId
304    """If set, use this agent to generate the query."""
305    allowClarification: bool
306    """When true, allow the AI to ask a clarifying question instead of
307    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):
332class AiQueryOptions(TypedDict, total=False):
333    """Options for configuring AI query execution.
334
335    Mirrors ``AiQueryOptions`` from the TypeScript SDK. All fields optional.
336    """
337
338    instructions: str
339    """Custom instructions applied to all stages unless overridden per-stage."""
340    enableRawResults: bool
341    """Enable raw results output."""
342    selectCollectionsOptions: AiQuerySelectCollectionsOptions
343    """Collection-selection stage options."""
344    generateQueryOptions: AiQueryGenerateQueryOptions
345    """Query-generation stage options."""
346    analyzeResultsOptions: AiQueryAnalyzeResultsOptions
347    """Result-analysis stage options."""
348    sessionContext: AiSessionContext
349    """Session information (``agentId`` may be omitted)."""
350    memoryOptions: AiAgentMemoryOptions
351    """Memory/session configuration."""
352    generateQueriesOnly: bool
353    """If true, return generated queries without executing or analyzing them."""
354    validateWithAiOptions: AiQueryValidateWithAiOptions
355    """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):
285class AiQuerySelectCollectionsOptions(TypedDict, total=False):
286    """Options for the collection-selection stage of AI query."""
287
288    collectionsToUse: list[str]
289    """Restrict query to these collections. Defaults to all collections."""
290    runMode: AiQueryCollectionsSelectionRunMode
291    """Stage behavior: 'default', 'force', or 'disable'."""
292    aiOptions: AiChatOptions
293    """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):
323class AiQueryValidateWithAiOptions(TypedDict, total=False):
324    """Options for AI-based validation of generated queries."""
325
326    enabled: bool
327    """Whether AI validation is enabled."""
328    aiOptions: AiChatOptions
329    """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):
272class AiSessionContext(TypedDict, total=False):
273    """Session context for AI query execution.
274
275    Mirrors the TypeScript ``AiSessionContext`` type. All fields optional
276    here because the query endpoint accepts a partial context (``agentId``
277    may be omitted).
278    """
279
280    clientId: str
281    agentId: str
282    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):
829class CreatePdfDimensionsOptions(TypedDict):
830    """PDF output options by custom dimensions."""
831
832    type: Literal["dimensions"]
833    width: int
834    """Width in pixels."""
835    height: int
836    """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):
810class CreatePdfFormatOptions(TypedDict):
811    """PDF output options by format."""
812
813    type: Literal["format"]
814    format: Literal[
815        "letter",
816        "legal",
817        "tabloid",
818        "ledger",
819        "a0",
820        "a1",
821        "a2",
822        "a3",
823        "a4",
824        "a5",
825        "a6",
826    ]

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):
842class ExtractDataFromDocumentOptions(TypedDict, total=False):
843    """Options for document data extraction."""
844
845    extractImages: bool
846    """Whether to extract embedded images. Defaults to True."""
847    imageMinSizePixels: int
848    """Minimum image size to extract."""
849    pageIndexes: list[int]
850    """Specific pages to extract (0-based)."""
851    preferredExtractionMethod: str
852    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):
581class FileContextRequest(TypedDict, total=False):
582    """Request to upsert a file context."""
583
584    contextId: str
585    type: Literal["file"]
586    metadata: dict[str, Any]
587    extractImages: bool
588    """Whether to extract and describe images in the file. Defaults to True.
589
590    This is the opposite of the text context default, which is False: a file's charts and
591    scanned pages carry content its text layer does not, while images referenced from pasted
592    markdown/HTML are usually layout chrome.
593    """
594    imageMinSizePixels: int
595    extractionModel: AiChatModelSelection
596    options: AiContextFileOptions
597    preferredExtractionMethod: str
598    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):
742class FluxOptions(TypedDict, total=False):
743    """Options for Flux image generation."""
744
745    modelName: Literal["flux-pro-1.1", "flux-kontext-pro"]
746    width: int
747    """Must be multiple of 32, min 256, max 1440."""
748    height: int
749    """Must be multiple of 32, min 256, max 1440."""
750    prompt_upsampling: bool
751    seed: int
752    safety_tolerance: int
753    """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):
726class GptImageOptions(TypedDict, total=False):
727    """Options for OpenAI gpt-image-* family image generation."""
728
729    modelName: Literal[
730        "gpt-image-1",
731        "gpt-image-1-mini",
732        "gpt-image-1.5",
733        "gpt-image-2",
734        "gpt-image-2-2026-04-21",
735        "chatgpt-image-latest",
736    ]
737    quality: Literal["auto", "high", "medium", "low"]
738    size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"]
739    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):
435class IntegrationEmbeddingModelSpec(TypedDict):
436    """Specifies an embedding model from a specific integration."""
437
438    integrationId: str
439    """The ID of the integration providing the embedding model."""
440    model: str
441    """The model name as recognized by the provider."""
442    dimensions: int
443    """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-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-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-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):
643class KnowledgeBaseSearchOptions(TypedDict, total=False):
644    """Options for knowledge base search."""
645
646    prompt: str
647    """The search prompt."""
648    limit: int
649    """Max number of results to return."""
650    chunkLimit: int
651    """How many chunks to search over (default 100)."""
652    rerankProvider: AiRerankProvider
653    """Reranker provider (default 'cohere')."""
654    chatModel: AiChatModelSelection
655    """Model to use for answering."""
656    searchMode: Literal["vector", "hybrid", "keyword", "graph"]
657    """Retrieval mode: 'hybrid' (BM25+dense fusion where supported; default on non-graph KBs),
658    'vector' (dense only), 'keyword' (pure lexical — every whitespace-separated term must appear
659    as a literal, case-insensitive substring), or 'graph' (GraphRAG — seeds entities via vector
660    search, expands relationships via graph traversal, maps entities back to their chunks, fused
661    with a hybrid search; requires a ``vectorDbType: 'mongoAtlas'`` KB with ``graphRag.enabled``
662    and is the default there)."""
663    graphOptions: AiKnowledgeBaseGraphSearchOptions
664    """Tuning for ``searchMode: 'graph'``. Ignored for other search modes."""
665    graphFilter: AiKnowledgeBaseGraphFilter
666    """Scopes the search to the documents under one concept of the KB's graph. Requires
667    ``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):
773class MmCategory(TypedDict):
774    """Matchmaking category."""
775
776    id: str
777    description: str

Matchmaking category.

id: str
description: str
class MmEntity(typing.TypedDict):
780class MmEntity(TypedDict, total=False):
781    """Matchmaking entity."""
782
783    id: str
784    content: str
785    categoryId: str
786    metadata: dict[str, Any]

Matchmaking entity.

id: str
content: str
categoryId: str
metadata: dict[str, typing.Any]
class MmFindMatchesOptions(typing.TypedDict):
789class MmFindMatchesOptions(TypedDict, total=False):
790    """Options for finding matches."""
791
792    metadataFilter: dict[str, Any]
793    """AiContextMetadataFilter conditions."""
794    limit: int
795    """Max matches to return (default 100, max 100)."""
796    matchToCategoryId: str
797    """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):
800class MmListEntitiesOptions(TypedDict, total=False):
801    """Options for listing entities."""
802
803    metadataFilter: dict[str, Any]
804    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):
83class SquidHttpError(Exception):
84    """Raised when the Squid API returns an HTTP error response (status >= 400).
85
86    Attributes:
87        status_code: The HTTP status code.
88        url: The URL that was requested.
89        body: The parsed response body, if available.
90    """
91
92    def __init__(self, status_code: int, message: str, url: str, body: Any = None):
93        self.status_code = status_code
94        self.url = url
95        self.body = body
96        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)
92    def __init__(self, status_code: int, message: str, url: str, body: Any = None):
93        self.status_code = status_code
94        self.url = url
95        self.body = body
96        super().__init__(f"HTTP {status_code}: {message} (url={url})")
status_code
url
body
class StableDiffusionOptions(typing.TypedDict):
756class StableDiffusionOptions(TypedDict, total=False):
757    """Options for Stable Diffusion Core image generation."""
758
759    modelName: Literal["stable-diffusion-core"]
760    aspectRatio: Literal["16:9", "1:1", "21:9", "2:3", "3:2", "4:5", "5:4", "9:16", "9:21"]
761    negativePrompt: str
762    seed: int
763    stylePreset: str
764    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):
563class TextContextRequest(TypedDict, total=False):
564    """Request to upsert a text context."""
565
566    contextId: str
567    type: Literal["text"]
568    title: str
569    text: str
570    metadata: dict[str, Any]
571    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):
376class UpsertAgentOptions(TypedDict, total=False):
377    """Options for creating/updating an agent."""
378
379    description: str
380    """Description of the agent's purpose."""
381    isPublic: bool
382    """Whether the agent is publicly accessible."""
383    auditLog: bool
384    """Enable audit logging."""
385    auditLogFullContext: bool
386    """Record the full agent context (system instructions and retrieved knowledge-base content) in the audit log."""
387    apiKey: str
388    """API key for this agent."""
389    mcpServer: AiAgentMcpServerConfig
390    """Optional configuration for exposing the agent as an MCP server."""
391    options: AiChatOptions
392    """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):
874class WebAiSearchResponse(TypedDict):
875    """Response from AI web search."""
876
877    markdownText: str
878    citedUrls: list[dict[str, str]]

Response from AI web search.

markdownText: str
citedUrls: list[dict[str, str]]
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 cited URL belongs to one of them.
29
30        Returns WebAiSearchResponse with 'markdownText' and 'citedUrls'.
31        """
32        body: dict[str, object] = {"query": query}
33        if allowed_domains is not None:
34            body["allowedDomains"] = allowed_domains
35        return await self._http.post("squid-api/v1/web/aiSearch", body)
36
37    async def get_url_content(self, url: str) -> str:
38        """Fetch and extract content from a URL as markdown."""
39        result = await self._http.post("squid-api/v1/web/getUrlContent", {"url": url})
40        if isinstance(result, dict):
41            return result.get("markdownText", "")
42        return str(result) if result else ""
43
44    async def create_short_url(
45        self,
46        url: str,
47        *,
48        seconds_to_live: int | None = None,
49        file_extension: str | None = None,
50    ) -> WebShortUrlResponse:
51        """Create a short URL.
52
53        Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'.
54        """
55        body: dict = {"url": url}
56        if seconds_to_live is not None:
57            body["secondsToLive"] = seconds_to_live
58        if file_extension is not None:
59            body["fileExtension"] = file_extension
60        return await self._http.post("squid-api/v1/web/createShortUrl", body)
61
62    async def create_short_urls(
63        self,
64        urls: list[str],
65        *,
66        seconds_to_live: int | None = None,
67        file_extension: str | None = None,
68    ) -> WebShortUrlBulkResponse:
69        """Create multiple short URLs in bulk.
70
71        Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'.
72        """
73        body: dict = {"urls": urls}
74        if seconds_to_live is not None:
75            body["secondsToLive"] = seconds_to_live
76        if file_extension is not None:
77            body["fileExtension"] = file_extension
78        return await self._http.post("squid-api/v1/web/createShortUrls", body)
79
80    async def delete_short_url(self, url_id: str) -> None:
81        """Delete a short URL."""
82        await self._http.post("squid-api/v1/web/deleteShortUrl", {"id": url_id})
83
84    async def delete_short_urls(self, url_ids: list[str]) -> None:
85        """Delete multiple short URLs."""
86        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:
37    async def get_url_content(self, url: str) -> str:
38        """Fetch and extract content from a URL as markdown."""
39        result = await self._http.post("squid-api/v1/web/getUrlContent", {"url": url})
40        if isinstance(result, dict):
41            return result.get("markdownText", "")
42        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:
44    async def create_short_url(
45        self,
46        url: str,
47        *,
48        seconds_to_live: int | None = None,
49        file_extension: str | None = None,
50    ) -> WebShortUrlResponse:
51        """Create a short URL.
52
53        Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'.
54        """
55        body: dict = {"url": url}
56        if seconds_to_live is not None:
57            body["secondsToLive"] = seconds_to_live
58        if file_extension is not None:
59            body["fileExtension"] = file_extension
60        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:
62    async def create_short_urls(
63        self,
64        urls: list[str],
65        *,
66        seconds_to_live: int | None = None,
67        file_extension: str | None = None,
68    ) -> WebShortUrlBulkResponse:
69        """Create multiple short URLs in bulk.
70
71        Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'.
72        """
73        body: dict = {"urls": urls}
74        if seconds_to_live is not None:
75            body["secondsToLive"] = seconds_to_live
76        if file_extension is not None:
77            body["fileExtension"] = file_extension
78        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:
80    async def delete_short_url(self, url_id: str) -> None:
81        """Delete a short URL."""
82        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:
84    async def delete_short_urls(self, url_ids: list[str]) -> None:
85        """Delete multiple short URLs."""
86        await self._http.post("squid-api/v1/web/deleteShortUrls", {"ids": url_ids})

Delete multiple short URLs.

class WebShortUrlBulkResponse(typing.TypedDict):
866class WebShortUrlBulkResponse(TypedDict):
867    """Response from creating bulk short URLs."""
868
869    ids: list[str]
870    shortUrls: list[str]
871    expiry: str

Response from creating bulk short URLs.

ids: list[str]
shortUrls: list[str]
expiry: str
class WebShortUrlResponse(typing.TypedDict):
858class WebShortUrlResponse(TypedDict):
859    """Response from creating a short URL."""
860
861    id: str
862    shortUrl: str
863    expiry: str

Response from creating a short URL.

id: str
shortUrl: str
expiry: str