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 AiAskModelSelection, 42 AiAskOptions, 43 AiAudioCreateSpeechOptions, 44 AiChatModelSelection, 45 AiChatOptions, 46 AiChatPromptQuotas, 47 AiConnectedAgentMetadata, 48 AiConnectedIntegrationMetadata, 49 AiConnectedKnowledgeBaseMetadata, 50 AiContextFileOptions, 51 AiContextTextOptions, 52 AiEmbeddingsModelSelection, 53 AiFileUrl, 54 AiFunctionAttributes, 55 AiFunctionMetadata, 56 AiFunctionParam, 57 AiKnowledgeBase, 58 AiKnowledgeBaseGraphConceptsConfig, 59 AiKnowledgeBaseGraphConfig, 60 AiKnowledgeBaseGraphFilter, 61 AiKnowledgeBaseGraphPathFacetConfig, 62 AiKnowledgeBaseGraphSearchOptions, 63 AiKnowledgeBaseMetadataField, 64 AiModelRoutingOptions, 65 AiModelRoutingResult, 66 AiPiiOptions, 67 AiQueryAnalyzeResultsOptions, 68 AiQueryCollectionsSelectionRunMode, 69 AiQueryGenerateQueryOptions, 70 AiQueryOptions, 71 AiQuerySelectCollectionsOptions, 72 AiQueryValidateWithAiOptions, 73 AiSessionContext, 74 AiStructuredOutputFormat, 75 ContextRequest, 76 CreatePdfDimensionsOptions, 77 CreatePdfFormatOptions, 78 CreatePdfOutputOptions, 79 EmbeddingModelIdSpec, 80 ExtractDataFromDocumentOptions, 81 FileContextRequest, 82 FluxOptions, 83 GptImageOptions, 84 GuardrailsOptions, 85 ImageGenerateOptions, 86 IntegrationEmbeddingModelSpec, 87 IntegrationModelSpec, 88 KnowledgeBaseGraphQueryOp, 89 KnowledgeBaseSearchOptions, 90 MmCategory, 91 MmEntity, 92 MmFindMatchesOptions, 93 MmListEntitiesOptions, 94 ModelIdSpec, 95 StableDiffusionOptions, 96 TextContextRequest, 97 UpsertAgentOptions, 98 VectorDbType, 99 WebAiSearchResponse, 100 WebShortUrlBulkResponse, 101 WebShortUrlResponse, 102) 103from squidcloud.web import WebClient 104 105__all__ = [ 106 "AgentClient", 107 "AiAgent", 108 "AiAgentExecutionPlanOptions", 109 "AiAgentMcpServerConfig", 110 "AiAgentMemoryOptions", 111 "AiAgentResponseFormat", 112 "AiAskModelSelection", 113 "AiAskOptions", 114 "AiAudioCreateSpeechOptions", 115 "AiChatModelSelection", 116 # AI Chat 117 "AiChatOptions", 118 "AiChatPromptQuotas", 119 "AiClient", 120 "AiConnectedAgentMetadata", 121 "AiConnectedIntegrationMetadata", 122 "AiConnectedKnowledgeBaseMetadata", 123 "AiContextFileOptions", 124 "AiContextTextOptions", 125 "AiEmbeddingsModelSelection", 126 "AiFileUrl", 127 "AiFunctionAttributes", 128 "AiFunctionMetadata", 129 "AiFunctionParam", 130 # Knowledge Base 131 "AiKnowledgeBase", 132 "AiKnowledgeBaseGraphConceptsConfig", 133 "AiKnowledgeBaseGraphConfig", 134 "AiKnowledgeBaseGraphFilter", 135 "AiKnowledgeBaseGraphPathFacetConfig", 136 "AiKnowledgeBaseGraphSearchOptions", 137 "AiKnowledgeBaseMetadataField", 138 "AiModelRoutingOptions", 139 "AiModelRoutingResult", 140 "AiPiiOptions", 141 # AI Query 142 "AiQueryAnalyzeResultsOptions", 143 "AiQueryCollectionsSelectionRunMode", 144 "AiQueryGenerateQueryOptions", 145 "AiQueryOptions", 146 "AiQuerySelectCollectionsOptions", 147 "AiQueryValidateWithAiOptions", 148 "AiSessionContext", 149 "AiStructuredOutputFormat", 150 "AudioClient", 151 "ContextRequest", 152 "CreatePdfDimensionsOptions", 153 "CreatePdfFormatOptions", 154 # Extraction 155 "CreatePdfOutputOptions", 156 "EmbeddingModelIdSpec", 157 "ExtractDataFromDocumentOptions", 158 "ExtractionClient", 159 "FileContextRequest", 160 "FluxOptions", 161 "GptImageOptions", 162 "GuardrailsOptions", 163 # Image 164 "ImageClient", 165 "ImageGenerateOptions", 166 "IntegrationEmbeddingModelSpec", 167 "IntegrationModelSpec", 168 "KnowledgeBaseClient", 169 "KnowledgeBaseGraphQueryOp", 170 "KnowledgeBaseSearchOptions", 171 # Matchmaking 172 "MatchmakingClient", 173 "MmCategory", 174 "MmEntity", 175 "MmFindMatchesOptions", 176 "MmListEntitiesOptions", 177 "ModelIdSpec", 178 "Squid", 179 "SquidHttpError", 180 "StableDiffusionOptions", 181 "TextContextRequest", 182 "UpsertAgentOptions", 183 "VectorDbType", 184 # Web 185 "WebAiSearchResponse", 186 "WebClient", 187 "WebShortUrlBulkResponse", 188 "WebShortUrlResponse", 189]
169class AgentClient: 170 """Operations on a single AI agent. 171 172 Provides methods for chatting with an agent, managing its configuration, 173 updating guardrails, and working with revisions. 174 175 Obtained via :meth:`AiClient.agent`. 176 177 Example:: 178 179 agent = squid.ai().agent("my-agent") 180 response = await agent.ask("What is the weather?", options={"temperature": 0.7}) 181 await agent.update_instructions("Always respond in haiku format.") 182 """ 183 184 def __init__(self, http: HttpTransport, agent_id: str) -> None: 185 self._http = http 186 self._agent_id = agent_id 187 188 # --- Chat --- 189 190 async def ask( 191 self, 192 prompt: str, 193 options: AiChatOptions | AiAskOptions | None = None, 194 ) -> str: 195 """Ask the agent a question and get a text response. 196 197 Args: 198 prompt: The user's question or instruction. 199 options: Chat options controlling model, temperature, memory, 200 functions, guardrails, and more. See :class:`AiChatOptions`. With 201 :class:`AiAskOptions`, ``model`` may be an :class:`AiModelRoutingOptions` 202 to let a routing model pick the answering model; 203 :meth:`ask_with_annotations` also reports which one it chose. 204 205 Returns: 206 The agent's response as a string. 207 208 Raises: 209 SquidHttpError: If the agent is not found or the request fails. 210 211 Example:: 212 213 response = await agent.ask( 214 "Summarize this document", 215 options={ 216 "model": "gemini-3.8-flash", 217 "temperature": 0.3, 218 "memoryOptions": {"memoryId": "session-1", "memoryMode": "read-write"}, 219 }, 220 ) 221 """ 222 result = await self._http.post( 223 "squid-api/v1/ai/agent/ask", 224 {"agentId": self._agent_id, "prompt": prompt, "options": options or {}}, 225 ) 226 return result.get("responseString", "") if result else "" 227 228 async def ask_with_annotations( 229 self, 230 prompt: str, 231 options: AiChatOptions | AiAskOptions | None = None, 232 ) -> dict: 233 """Ask the agent and get a response with annotations. 234 235 Annotations include file references, citations, and other metadata 236 the agent may attach to its response. 237 238 Args: 239 prompt: The user's question or instruction. 240 options: Chat options. See :class:`AiChatOptions` and :class:`AiAskOptions`. 241 242 Returns: 243 A dict with: 244 - ``responseString`` (str): The text response. 245 - ``annotations`` (dict): Annotation metadata keyed by ID. 246 - ``routing`` (:class:`AiModelRoutingResult`): Present when ``model`` 247 was an :class:`AiModelRoutingOptions`: the chosen model and the 248 routing call's usage. 249 250 Example:: 251 252 result = await agent.ask_with_annotations("Find relevant docs") 253 print(result["responseString"]) 254 for ann_id, ann in result.get("annotations", {}).items(): 255 print(f" Annotation: {ann}") 256 """ 257 return await self._http.post( 258 "squid-api/v1/ai/agent/askWithAnnotations", 259 {"agentId": self._agent_id, "prompt": prompt, "options": options or {}}, 260 ) 261 262 # --- Management --- 263 264 async def get(self) -> dict | None: 265 """Get the agent's configuration. 266 267 Returns: 268 An ``AiAgent`` dict with keys: ``id``, ``createdAt``, ``updatedAt``, 269 ``description``, ``isPublic``, ``auditLog``, ``auditLogFullContext``, 270 ``options``, ``apiKey``. 271 Returns ``None`` if the agent does not exist. 272 """ 273 return await self._http.get(f"squid-api/v1/ai/agent/get/{self._agent_id}") 274 275 async def upsert( 276 self, 277 *, 278 description: str | None = None, 279 is_public: bool | None = None, 280 audit_log: bool | None = None, 281 audit_log_full_context: bool | None = None, 282 api_key: str | None = None, 283 mcp_server: AiAgentMcpServerConfig | None = None, 284 options: AiChatOptions | None = None, 285 ) -> None: 286 """Create or update the agent. 287 288 If the agent does not exist, it is created. If it exists, the provided 289 fields are updated (fields set to ``None`` are left unchanged). 290 291 Args: 292 description: A description of the agent's purpose or capabilities. 293 is_public: Whether the agent is publicly accessible (default ``False``). 294 audit_log: Enable audit logging for the agent's activities. 295 audit_log_full_context: Record the full agent context (system 296 instructions and retrieved knowledge-base content) in the audit 297 log; requires ``audit_log``. 298 api_key: Optional API key used specifically for this agent. 299 mcp_server: Configuration for exposing the agent as an MCP server 300 at ``/mcp/<agentId>``. See :class:`AiAgentMcpServerConfig`. 301 options: Default chat options applied to every request unless 302 overridden per-call. See :class:`AiChatOptions`. 303 304 Example:: 305 306 await agent.upsert( 307 description="Customer support agent", 308 options={"model": "gemini-3.8-flash", "temperature": 0.5}, 309 ) 310 """ 311 body: dict[str, Any] = {"id": self._agent_id} 312 if description is not None: 313 body["description"] = description 314 if is_public is not None: 315 body["isPublic"] = is_public 316 if audit_log is not None: 317 body["auditLog"] = audit_log 318 if audit_log_full_context is not None: 319 body["auditLogFullContext"] = audit_log_full_context 320 if api_key is not None: 321 body["apiKey"] = api_key 322 if mcp_server is not None: 323 body["mcpServer"] = mcp_server 324 if options is not None: 325 body["options"] = options 326 await self._http.post("squid-api/v1/ai/agent/upsert", body) 327 328 async def delete(self) -> None: 329 """Delete the agent permanently.""" 330 await self._http.post("squid-api/v1/ai/agent/delete", {"agentId": self._agent_id}) 331 332 async def update_instructions(self, instructions: str) -> None: 333 """Update the agent's system instructions. 334 335 Args: 336 instructions: The new system prompt / instructions text. 337 """ 338 await self._http.post( 339 "squid-api/v1/ai/agent/updateInstructions", 340 {"agentId": self._agent_id, "instructions": instructions}, 341 ) 342 343 async def update_model(self, model: AiChatModelSelection) -> None: 344 """Update the agent's default LLM model. 345 346 Args: 347 model: A model name string (e.g., ``'gemini-3.8-flash'``) or an 348 ``IntegrationModelSpec`` dict (``{'integrationId': str, 'model': str}``). 349 """ 350 await self._http.post( 351 "squid-api/v1/ai/agent/updateModel", 352 {"agentId": self._agent_id, "model": model}, 353 ) 354 355 async def update_connected_agents( 356 self, connected_agents: list[AiConnectedAgentMetadata] 357 ) -> None: 358 """Update the list of connected agents. 359 360 Connected agents can be called by this agent during conversations. 361 362 Args: 363 connected_agents: List of ``{'agentId': str, 'description': str}`` dicts. 364 """ 365 await self._http.post( 366 "squid-api/v1/ai/agent/updateConnectedAgents", 367 {"agentId": self._agent_id, "connectedAgents": connected_agents}, 368 ) 369 370 async def update_guardrails(self, guardrails: GuardrailsOptions) -> None: 371 """Update the agent's guardrail settings. 372 373 Args: 374 guardrails: A :class:`GuardrailsOptions` dict with optional keys: 375 ``custom``, ``disablePii``, ``professionalTone``, 376 ``offTopicAnswers``, ``disableProfanity``. 377 378 Example:: 379 380 await agent.update_guardrails( 381 { 382 "professionalTone": True, 383 "disableProfanity": True, 384 } 385 ) 386 """ 387 await self._http.post( 388 "squid-api/v1/ai/agent/updateGuardrails", 389 {"agentId": self._agent_id, "guardrails": guardrails}, 390 ) 391 392 async def update_custom_guardrails(self, custom_guardrail: str) -> None: 393 """Update the custom guardrail instruction text. 394 395 Args: 396 custom_guardrail: Free-form guardrail instruction string. 397 """ 398 await self._http.post( 399 "squid-api/v1/ai/agent/updateCustomGuardrails", 400 {"agentId": self._agent_id, "customGuardrail": custom_guardrail}, 401 ) 402 403 async def delete_custom_guardrails(self) -> None: 404 """Delete the custom guardrail, reverting to defaults.""" 405 await self._http.post( 406 "squid-api/v1/ai/agent/deleteCustomGuardrails", 407 {"agentId": self._agent_id}, 408 ) 409 410 async def update_pii(self, pii: AiPiiOptions) -> None: 411 """Update the agent's PII screening, merging with its existing settings. 412 413 With ``onDetect`` set to ``"reject"`` the agent refuses any prompt carrying 414 PII before it reaches the model, so the prompt is never answered and never 415 stored. This is the inverse of ``GuardrailsOptions.disablePii``, which asks 416 the agent's own model not to emit PII in its answer. 417 418 Args: 419 pii: An :class:`AiPiiOptions` dict with optional keys: ``onDetect``, 420 ``entities``, ``customRules``, ``classifierModel``, ``allowList``. 421 422 Example:: 423 424 await agent.update_pii( 425 { 426 "onDetect": "reject", 427 "customRules": ["internal case numbers like CASE-12345"], 428 } 429 ) 430 """ 431 agent = await self.get() 432 existing = (agent or {}).get("options", {}).get("pii", {}) 433 merged = {"onDetect": "off", **existing, **pii} 434 await self._http.post( 435 "squid-api/v1/ai/agent/setAgentOptionInPath", 436 {"agentId": self._agent_id, "path": "pii", "value": merged}, 437 ) 438 439 # --- Revisions --- 440 441 async def list_revisions(self) -> list[dict]: 442 """List all revisions of this agent. 443 444 Returns: 445 A list of ``AiAgentRevision`` dicts, each containing: 446 ``agentId``, ``revisionNumber``, ``action``, ``createdAt``, 447 ``agentSnapshot``. 448 """ 449 result = await self._http.get(f"squid-api/v1/ai/agent/revisions/{self._agent_id}") 450 return result.get("revisions", []) if result else [] 451 452 async def restore_revision(self, revision_number: int) -> None: 453 """Restore the agent to a previous revision. 454 455 Args: 456 revision_number: The revision number to restore. 457 """ 458 await self._http.post( 459 "squid-api/v1/ai/agent/restoreRevision", 460 {"agentId": self._agent_id, "revisionNumber": revision_number}, 461 ) 462 463 async def delete_revision(self, revision_number: int) -> None: 464 """Delete a specific revision. 465 466 Args: 467 revision_number: The revision number to delete. 468 """ 469 await self._http.post( 470 "squid-api/v1/ai/agent/deleteRevision", 471 {"agentId": self._agent_id, "revisionNumber": revision_number}, 472 )
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.")
190 async def ask( 191 self, 192 prompt: str, 193 options: AiChatOptions | AiAskOptions | None = None, 194 ) -> str: 195 """Ask the agent a question and get a text response. 196 197 Args: 198 prompt: The user's question or instruction. 199 options: Chat options controlling model, temperature, memory, 200 functions, guardrails, and more. See :class:`AiChatOptions`. With 201 :class:`AiAskOptions`, ``model`` may be an :class:`AiModelRoutingOptions` 202 to let a routing model pick the answering model; 203 :meth:`ask_with_annotations` also reports which one it chose. 204 205 Returns: 206 The agent's response as a string. 207 208 Raises: 209 SquidHttpError: If the agent is not found or the request fails. 210 211 Example:: 212 213 response = await agent.ask( 214 "Summarize this document", 215 options={ 216 "model": "gemini-3.8-flash", 217 "temperature": 0.3, 218 "memoryOptions": {"memoryId": "session-1", "memoryMode": "read-write"}, 219 }, 220 ) 221 """ 222 result = await self._http.post( 223 "squid-api/v1/ai/agent/ask", 224 {"agentId": self._agent_id, "prompt": prompt, "options": options or {}}, 225 ) 226 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. WithAiAskOptions,modelmay be anAiModelRoutingOptionsto let a routing model pick the answering model;ask_with_annotations()also reports which one it chose.
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.8-flash",
"temperature": 0.3,
"memoryOptions": {"memoryId": "session-1", "memoryMode": "read-write"},
},
)
228 async def ask_with_annotations( 229 self, 230 prompt: str, 231 options: AiChatOptions | AiAskOptions | None = None, 232 ) -> dict: 233 """Ask the agent and get a response with annotations. 234 235 Annotations include file references, citations, and other metadata 236 the agent may attach to its response. 237 238 Args: 239 prompt: The user's question or instruction. 240 options: Chat options. See :class:`AiChatOptions` and :class:`AiAskOptions`. 241 242 Returns: 243 A dict with: 244 - ``responseString`` (str): The text response. 245 - ``annotations`` (dict): Annotation metadata keyed by ID. 246 - ``routing`` (:class:`AiModelRoutingResult`): Present when ``model`` 247 was an :class:`AiModelRoutingOptions`: the chosen model and the 248 routing call's usage. 249 250 Example:: 251 252 result = await agent.ask_with_annotations("Find relevant docs") 253 print(result["responseString"]) 254 for ann_id, ann in result.get("annotations", {}).items(): 255 print(f" Annotation: {ann}") 256 """ 257 return await self._http.post( 258 "squid-api/v1/ai/agent/askWithAnnotations", 259 {"agentId": self._agent_id, "prompt": prompt, "options": options or {}}, 260 )
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
AiChatOptionsandAiAskOptions.
Returns:
A dict with: -
responseString(str): The text response. -annotations(dict): Annotation metadata keyed by ID. -routing(AiModelRoutingResult): Present whenmodelwas anAiModelRoutingOptions: the chosen model and the routing call's usage.
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}")
264 async def get(self) -> dict | None: 265 """Get the agent's configuration. 266 267 Returns: 268 An ``AiAgent`` dict with keys: ``id``, ``createdAt``, ``updatedAt``, 269 ``description``, ``isPublic``, ``auditLog``, ``auditLogFullContext``, 270 ``options``, ``apiKey``. 271 Returns ``None`` if the agent does not exist. 272 """ 273 return await self._http.get(f"squid-api/v1/ai/agent/get/{self._agent_id}")
Get the agent's configuration.
Returns:
An
AiAgentdict with keys:id,createdAt,updatedAt,description,isPublic,auditLog,auditLogFullContext,options,apiKey. ReturnsNoneif the agent does not exist.
275 async def upsert( 276 self, 277 *, 278 description: str | None = None, 279 is_public: bool | None = None, 280 audit_log: bool | None = None, 281 audit_log_full_context: bool | None = None, 282 api_key: str | None = None, 283 mcp_server: AiAgentMcpServerConfig | None = None, 284 options: AiChatOptions | None = None, 285 ) -> None: 286 """Create or update the agent. 287 288 If the agent does not exist, it is created. If it exists, the provided 289 fields are updated (fields set to ``None`` are left unchanged). 290 291 Args: 292 description: A description of the agent's purpose or capabilities. 293 is_public: Whether the agent is publicly accessible (default ``False``). 294 audit_log: Enable audit logging for the agent's activities. 295 audit_log_full_context: Record the full agent context (system 296 instructions and retrieved knowledge-base content) in the audit 297 log; requires ``audit_log``. 298 api_key: Optional API key used specifically for this agent. 299 mcp_server: Configuration for exposing the agent as an MCP server 300 at ``/mcp/<agentId>``. See :class:`AiAgentMcpServerConfig`. 301 options: Default chat options applied to every request unless 302 overridden per-call. See :class:`AiChatOptions`. 303 304 Example:: 305 306 await agent.upsert( 307 description="Customer support agent", 308 options={"model": "gemini-3.8-flash", "temperature": 0.5}, 309 ) 310 """ 311 body: dict[str, Any] = {"id": self._agent_id} 312 if description is not None: 313 body["description"] = description 314 if is_public is not None: 315 body["isPublic"] = is_public 316 if audit_log is not None: 317 body["auditLog"] = audit_log 318 if audit_log_full_context is not None: 319 body["auditLogFullContext"] = audit_log_full_context 320 if api_key is not None: 321 body["apiKey"] = api_key 322 if mcp_server is not None: 323 body["mcpServer"] = mcp_server 324 if options is not None: 325 body["options"] = options 326 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>. SeeAiAgentMcpServerConfig. - 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.8-flash", "temperature": 0.5},
)
328 async def delete(self) -> None: 329 """Delete the agent permanently.""" 330 await self._http.post("squid-api/v1/ai/agent/delete", {"agentId": self._agent_id})
Delete the agent permanently.
332 async def update_instructions(self, instructions: str) -> None: 333 """Update the agent's system instructions. 334 335 Args: 336 instructions: The new system prompt / instructions text. 337 """ 338 await self._http.post( 339 "squid-api/v1/ai/agent/updateInstructions", 340 {"agentId": self._agent_id, "instructions": instructions}, 341 )
Update the agent's system instructions.
Arguments:
- instructions: The new system prompt / instructions text.
343 async def update_model(self, model: AiChatModelSelection) -> None: 344 """Update the agent's default LLM model. 345 346 Args: 347 model: A model name string (e.g., ``'gemini-3.8-flash'``) or an 348 ``IntegrationModelSpec`` dict (``{'integrationId': str, 'model': str}``). 349 """ 350 await self._http.post( 351 "squid-api/v1/ai/agent/updateModel", 352 {"agentId": self._agent_id, "model": model}, 353 )
Update the agent's default LLM model.
Arguments:
- model: A model name string (e.g.,
'gemini-3.8-flash') or anIntegrationModelSpecdict ({'integrationId': str, 'model': str}).
355 async def update_connected_agents( 356 self, connected_agents: list[AiConnectedAgentMetadata] 357 ) -> None: 358 """Update the list of connected agents. 359 360 Connected agents can be called by this agent during conversations. 361 362 Args: 363 connected_agents: List of ``{'agentId': str, 'description': str}`` dicts. 364 """ 365 await self._http.post( 366 "squid-api/v1/ai/agent/updateConnectedAgents", 367 {"agentId": self._agent_id, "connectedAgents": connected_agents}, 368 )
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.
370 async def update_guardrails(self, guardrails: GuardrailsOptions) -> None: 371 """Update the agent's guardrail settings. 372 373 Args: 374 guardrails: A :class:`GuardrailsOptions` dict with optional keys: 375 ``custom``, ``disablePii``, ``professionalTone``, 376 ``offTopicAnswers``, ``disableProfanity``. 377 378 Example:: 379 380 await agent.update_guardrails( 381 { 382 "professionalTone": True, 383 "disableProfanity": True, 384 } 385 ) 386 """ 387 await self._http.post( 388 "squid-api/v1/ai/agent/updateGuardrails", 389 {"agentId": self._agent_id, "guardrails": guardrails}, 390 )
Update the agent's guardrail settings.
Arguments:
- guardrails: A
GuardrailsOptionsdict with optional keys:custom,disablePii,professionalTone,offTopicAnswers,disableProfanity.
Example::
await agent.update_guardrails(
{
"professionalTone": True,
"disableProfanity": True,
}
)
392 async def update_custom_guardrails(self, custom_guardrail: str) -> None: 393 """Update the custom guardrail instruction text. 394 395 Args: 396 custom_guardrail: Free-form guardrail instruction string. 397 """ 398 await self._http.post( 399 "squid-api/v1/ai/agent/updateCustomGuardrails", 400 {"agentId": self._agent_id, "customGuardrail": custom_guardrail}, 401 )
Update the custom guardrail instruction text.
Arguments:
- custom_guardrail: Free-form guardrail instruction string.
403 async def delete_custom_guardrails(self) -> None: 404 """Delete the custom guardrail, reverting to defaults.""" 405 await self._http.post( 406 "squid-api/v1/ai/agent/deleteCustomGuardrails", 407 {"agentId": self._agent_id}, 408 )
Delete the custom guardrail, reverting to defaults.
410 async def update_pii(self, pii: AiPiiOptions) -> None: 411 """Update the agent's PII screening, merging with its existing settings. 412 413 With ``onDetect`` set to ``"reject"`` the agent refuses any prompt carrying 414 PII before it reaches the model, so the prompt is never answered and never 415 stored. This is the inverse of ``GuardrailsOptions.disablePii``, which asks 416 the agent's own model not to emit PII in its answer. 417 418 Args: 419 pii: An :class:`AiPiiOptions` dict with optional keys: ``onDetect``, 420 ``entities``, ``customRules``, ``classifierModel``, ``allowList``. 421 422 Example:: 423 424 await agent.update_pii( 425 { 426 "onDetect": "reject", 427 "customRules": ["internal case numbers like CASE-12345"], 428 } 429 ) 430 """ 431 agent = await self.get() 432 existing = (agent or {}).get("options", {}).get("pii", {}) 433 merged = {"onDetect": "off", **existing, **pii} 434 await self._http.post( 435 "squid-api/v1/ai/agent/setAgentOptionInPath", 436 {"agentId": self._agent_id, "path": "pii", "value": merged}, 437 )
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
AiPiiOptionsdict with optional keys:onDetect,entities,customRules,classifierModel,allowList.
Example::
await agent.update_pii(
{
"onDetect": "reject",
"customRules": ["internal case numbers like CASE-12345"],
}
)
441 async def list_revisions(self) -> list[dict]: 442 """List all revisions of this agent. 443 444 Returns: 445 A list of ``AiAgentRevision`` dicts, each containing: 446 ``agentId``, ``revisionNumber``, ``action``, ``createdAt``, 447 ``agentSnapshot``. 448 """ 449 result = await self._http.get(f"squid-api/v1/ai/agent/revisions/{self._agent_id}") 450 return result.get("revisions", []) if result else []
List all revisions of this agent.
Returns:
A list of
AiAgentRevisiondicts, each containing:agentId,revisionNumber,action,createdAt,agentSnapshot.
452 async def restore_revision(self, revision_number: int) -> None: 453 """Restore the agent to a previous revision. 454 455 Args: 456 revision_number: The revision number to restore. 457 """ 458 await self._http.post( 459 "squid-api/v1/ai/agent/restoreRevision", 460 {"agentId": self._agent_id, "revisionNumber": revision_number}, 461 )
Restore the agent to a previous revision.
Arguments:
- revision_number: The revision number to restore.
463 async def delete_revision(self, revision_number: int) -> None: 464 """Delete a specific revision. 465 466 Args: 467 revision_number: The revision number to delete. 468 """ 469 await self._http.post( 470 "squid-api/v1/ai/agent/deleteRevision", 471 {"agentId": self._agent_id, "revisionNumber": revision_number}, 472 )
Delete a specific revision.
Arguments:
- revision_number: The revision number to delete.
474class AiAgent(TypedDict, total=False): 475 """A definition of an AI agent with its properties and default chat options. 476 477 Returned by :meth:`AiClient.list_agents`. 478 """ 479 480 id: str 481 """The unique identifier of the AI agent. Required.""" 482 createdAt: str 483 """ISO 8601 timestamp of when the agent was created. Required.""" 484 updatedAt: str 485 """ISO 8601 timestamp of when the agent was last updated. Required.""" 486 description: str 487 """An optional description of the agent's purpose or capabilities.""" 488 isPublic: bool 489 """Whether the agent is publicly accessible; defaults to False.""" 490 auditLog: bool 491 """Whether audit logging is enabled for the agent's activities; defaults to False.""" 492 auditLogFullContext: bool 493 """Whether the full agent context (system instructions and retrieved knowledge-base content) is recorded in the audit log; requires auditLog; defaults to False.""" 494 options: AiChatOptions 495 """The agent's default chat options, overridable by the user during use. Required.""" 496 apiKey: str 497 """Optional API key used specifically for operations on this agent.""" 498 mcpServer: AiAgentMcpServerConfig 499 """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().
Whether the full agent context (system instructions and retrieved knowledge-base content) is recorded in the audit log; requires auditLog; defaults to False.
The agent's default chat options, overridable by the user during use. Required.
166class AiAgentExecutionPlanOptions(TypedDict, total=False): 167 """Options for AI agent execution plan.""" 168 169 enabled: bool
Options for AI agent execution plan.
440class AiAgentMcpServerConfig(TypedDict, total=False): 441 """Configuration for exposing an AI agent as an MCP server at ``/mcp/<agentId>``.""" 442 443 enabled: bool 444 """Whether the agent is exposed as an MCP server. Required.""" 445 description: str 446 """Description of the MCP server, served as the ``instructions`` field of the MCP initialize result.""" 447 toolDescription: str 448 """Description of the MCP ``ask`` tool, exposed in the tools manifest.""" 449 oauthIntegrationId: str 450 """ID of an auth integration used to OAuth-protect the MCP server.""" 451 requireApiKey: bool 452 """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>.
92class AiAgentMemoryOptions(TypedDict, total=False): 93 """Memory/session configuration for agent chat.""" 94 95 memoryId: str 96 """Unique memory ID. Reuse to continue a conversation.""" 97 memoryMode: AiMemoryMode 98 """How memory is used: 'read-write', 'read-only', 'write-only', 'disabled'."""
Memory/session configuration for agent chat.
334class AiAskOptions(_AiChatOptionsBase, total=False): 335 """Options of :meth:`AgentClient.ask` and :meth:`AgentClient.ask_with_annotations`. 336 337 The same fields as :class:`AiChatOptions`, except that ``model`` may also be an 338 :class:`AiModelRoutingOptions` routing choice. 339 """ 340 341 model: AiAskModelSelection 342 """LLM model to use: a name, an IntegrationModelSpec, or an AiModelRoutingOptions."""
Options of AgentClient.ask() and AgentClient.ask_with_annotations().
The same fields as AiChatOptions, except that model may also be an
AiModelRoutingOptions routing choice.
LLM model to use: a name, an IntegrationModelSpec, or an AiModelRoutingOptions.
206class AiAudioCreateSpeechOptions(TypedDict, total=False): 207 """Options for text-to-speech.""" 208 209 modelName: str 210 """'tts-1' or 'tts-1-hd'.""" 211 voice: str 212 """'alloy'|'ash'|'ballad'|'coral'|'echo'|'fable'|'onyx'|'nova'|'sage'|'shimmer'|'verse'.""" 213 responseFormat: str 214 """Audio output format.""" 215 instructions: str 216 """Extra instructions for speech generation.""" 217 speed: float 218 """Speech speed."""
Options for text-to-speech.
323class AiChatOptions(_AiChatOptionsBase, total=False): 324 """Full chat options for AI agent chat operations and agent profiles. 325 326 Mirrors BaseAiChatOptions from the TypeScript SDK. 327 All fields are optional. 328 """ 329 330 model: AiChatModelSelection 331 """LLM model to use. String name or IntegrationModelSpec."""
Full chat options for AI agent chat operations and agent profiles.
Mirrors BaseAiChatOptions from the TypeScript SDK. All fields are optional.
160class AiChatPromptQuotas(TypedDict, total=False): 161 """Budget for nested/recursive AI chat calls.""" 162 163 maxNestedCalls: int
Budget for nested/recursive AI chat calls.
39class AiClient: 40 """Entry point for AI operations: agents, knowledge base, audio, image. 41 42 Obtained via :meth:`Squid.ai()`. 43 44 Example:: 45 46 ai = squid.ai() 47 agent = ai.agent("my-agent") 48 kb = ai.knowledge_base("my-kb") 49 image_url = await ai.image().generate("a cat in space") 50 """ 51 52 def __init__(self, http: HttpTransport) -> None: 53 self._http = http 54 55 def agent(self, agent_id: str) -> AgentClient: 56 """Get a client for a specific AI agent. 57 58 Args: 59 agent_id: The unique agent identifier. 60 61 Returns: 62 An :class:`AgentClient` bound to the given agent ID. 63 """ 64 return AgentClient(self._http, agent_id) 65 66 def knowledge_base(self, knowledge_base_id: str) -> KnowledgeBaseClient: 67 """Get a client for a specific knowledge base. 68 69 Args: 70 knowledge_base_id: The unique knowledge base identifier. 71 72 Returns: 73 A :class:`KnowledgeBaseClient` bound to the given knowledge base ID. 74 """ 75 return KnowledgeBaseClient(self._http, knowledge_base_id) 76 77 def image(self) -> ImageClient: 78 """Get a client for image generation and processing. 79 80 Returns: 81 An :class:`ImageClient` instance. 82 """ 83 return ImageClient(self._http) 84 85 def audio(self) -> AudioClient: 86 """Get a client for audio transcription and speech synthesis. 87 88 Returns: 89 An :class:`AudioClient` instance. 90 """ 91 return AudioClient(self._http) 92 93 async def list_agents(self) -> list[AiAgent]: 94 """List all AI agents defined for the application. 95 96 Returns: 97 A list of ``AiAgent`` dicts. Empty list if no agents are defined. 98 """ 99 result = await self._http.get("squid-api/v1/ai/agent/listAgents") 100 return result.get("agents", []) if result else [] 101 102 async def list_knowledge_bases(self) -> list[AiKnowledgeBase]: 103 """List all AI knowledge bases defined for the application. 104 105 Returns: 106 A list of ``AiKnowledgeBase`` dicts. Empty list if no knowledge 107 bases are defined. 108 """ 109 result = await self._http.get("squid-api/v1/ai/knowledge-base/listKnowledgeBases") 110 return result.get("knowledgeBases", []) if result else [] 111 112 async def list_chat_models(self, include_deprecated: bool = False) -> list[ModelIdSpec]: 113 """List all AI chat models available to the application. 114 115 Includes both Squid-provided vendor models and any custom integration 116 models configured for the app. 117 118 Args: 119 include_deprecated: When True, deprecated vendor models are 120 included and marked with ``replacedBy``. Defaults to False. 121 122 Returns: 123 A list of ``ModelIdSpec`` dicts, each with ``modelId``, an optional 124 ``integrationId``, and a human-readable ``displayName``. Vendor 125 models also carry a ``description``, and deprecated vendor models a 126 ``replacedBy`` with the active model their calls are routed to. 127 """ 128 params = {"includeDeprecated": "true"} if include_deprecated else None 129 result = await self._http.get("squid-api/v1/ai/settings/listChatModels", params=params) 130 return result.get("models", []) if result else [] 131 132 async def list_embedding_models( 133 self, include_deprecated: bool = False 134 ) -> list[EmbeddingModelIdSpec]: 135 """List the embedding models a new knowledge base can be created on. 136 137 Includes Squid-provided vendor models and the app's custom integration 138 models. Exactly one entry carries ``isDefault``. 139 140 Args: 141 include_deprecated: When True, deprecated vendor models are 142 included and marked with ``replacedBy``. Defaults to False. 143 144 Returns: 145 A list of ``EmbeddingModelIdSpec`` dicts, each with ``modelId``, 146 ``displayName`` and ``source``, plus ``integrationId`` and 147 ``dimensions`` for integration models. 148 """ 149 params = {"includeDeprecated": "true"} if include_deprecated else None 150 result = await self._http.get("squid-api/v1/ai/settings/listEmbeddingModels", params=params) 151 return result.get("models", []) if result else [] 152 153 async def list_functions(self) -> list[AiFunctionMetadata]: 154 """List all AI functions registered for the application's deployed bundle. 155 156 Returns: 157 A list of ``AiFunctionMetadata`` dicts. Empty list if no functions 158 are registered. 159 """ 160 result = await self._http.get("squid-api/v1/ai/function/listFunctions") 161 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")
55 def agent(self, agent_id: str) -> AgentClient: 56 """Get a client for a specific AI agent. 57 58 Args: 59 agent_id: The unique agent identifier. 60 61 Returns: 62 An :class:`AgentClient` bound to the given agent ID. 63 """ 64 return AgentClient(self._http, agent_id)
Get a client for a specific AI agent.
Arguments:
- agent_id: The unique agent identifier.
Returns:
An
AgentClientbound to the given agent ID.
66 def knowledge_base(self, knowledge_base_id: str) -> KnowledgeBaseClient: 67 """Get a client for a specific knowledge base. 68 69 Args: 70 knowledge_base_id: The unique knowledge base identifier. 71 72 Returns: 73 A :class:`KnowledgeBaseClient` bound to the given knowledge base ID. 74 """ 75 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
KnowledgeBaseClientbound to the given knowledge base ID.
93 async def list_agents(self) -> list[AiAgent]: 94 """List all AI agents defined for the application. 95 96 Returns: 97 A list of ``AiAgent`` dicts. Empty list if no agents are defined. 98 """ 99 result = await self._http.get("squid-api/v1/ai/agent/listAgents") 100 return result.get("agents", []) if result else []
List all AI agents defined for the application.
Returns:
A list of
AiAgentdicts. Empty list if no agents are defined.
102 async def list_knowledge_bases(self) -> list[AiKnowledgeBase]: 103 """List all AI knowledge bases defined for the application. 104 105 Returns: 106 A list of ``AiKnowledgeBase`` dicts. Empty list if no knowledge 107 bases are defined. 108 """ 109 result = await self._http.get("squid-api/v1/ai/knowledge-base/listKnowledgeBases") 110 return result.get("knowledgeBases", []) if result else []
List all AI knowledge bases defined for the application.
Returns:
A list of
AiKnowledgeBasedicts. Empty list if no knowledge bases are defined.
112 async def list_chat_models(self, include_deprecated: bool = False) -> list[ModelIdSpec]: 113 """List all AI chat models available to the application. 114 115 Includes both Squid-provided vendor models and any custom integration 116 models configured for the app. 117 118 Args: 119 include_deprecated: When True, deprecated vendor models are 120 included and marked with ``replacedBy``. Defaults to False. 121 122 Returns: 123 A list of ``ModelIdSpec`` dicts, each with ``modelId``, an optional 124 ``integrationId``, and a human-readable ``displayName``. Vendor 125 models also carry a ``description``, and deprecated vendor models a 126 ``replacedBy`` with the active model their calls are routed to. 127 """ 128 params = {"includeDeprecated": "true"} if include_deprecated else None 129 result = await self._http.get("squid-api/v1/ai/settings/listChatModels", params=params) 130 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
ModelIdSpecdicts, each withmodelId, an optionalintegrationId, and a human-readabledisplayName. Vendor models also carry adescription, and deprecated vendor models areplacedBywith the active model their calls are routed to.
132 async def list_embedding_models( 133 self, include_deprecated: bool = False 134 ) -> list[EmbeddingModelIdSpec]: 135 """List the embedding models a new knowledge base can be created on. 136 137 Includes Squid-provided vendor models and the app's custom integration 138 models. Exactly one entry carries ``isDefault``. 139 140 Args: 141 include_deprecated: When True, deprecated vendor models are 142 included and marked with ``replacedBy``. Defaults to False. 143 144 Returns: 145 A list of ``EmbeddingModelIdSpec`` dicts, each with ``modelId``, 146 ``displayName`` and ``source``, plus ``integrationId`` and 147 ``dimensions`` for integration models. 148 """ 149 params = {"includeDeprecated": "true"} if include_deprecated else None 150 result = await self._http.get("squid-api/v1/ai/settings/listEmbeddingModels", params=params) 151 return result.get("models", []) if result else []
List the embedding models a new knowledge base can be created on.
Includes Squid-provided vendor models and the app's custom integration
models. Exactly one entry carries isDefault.
Arguments:
- include_deprecated: When True, deprecated vendor models are
included and marked with
replacedBy. Defaults to False.
Returns:
A list of
EmbeddingModelIdSpecdicts, each withmodelId,displayNameandsource, plusintegrationIdanddimensionsfor integration models.
153 async def list_functions(self) -> list[AiFunctionMetadata]: 154 """List all AI functions registered for the application's deployed bundle. 155 156 Returns: 157 A list of ``AiFunctionMetadata`` dicts. Empty list if no functions 158 are registered. 159 """ 160 result = await self._http.get("squid-api/v1/ai/function/listFunctions") 161 return result.get("functions", []) if result else []
List all AI functions registered for the application's deployed bundle.
Returns:
A list of
AiFunctionMetadatadicts. Empty list if no functions are registered.
101class AiConnectedAgentMetadata(TypedDict): 102 """Metadata for a connected agent.""" 103 104 agentId: str 105 description: str
Metadata for a connected agent.
108class AiConnectedIntegrationMetadata(TypedDict, total=False): 109 """Metadata for a connected integration. 110 111 ``integrationId`` and ``integrationType`` are required by the platform API; 112 the remaining fields are optional. 113 """ 114 115 integrationId: str 116 """The ID of the connected integration. Required.""" 117 integrationType: str 118 """The integration type, e.g. 'hubspot', 'slack', 'api'. Required.""" 119 description: str 120 """Optional description used as the AI function description for the parent agent.""" 121 instructions: str 122 """Optional instructions for the connected integration agent, overriding the default.""" 123 functionsToUse: list[str] 124 """AI function IDs the agent may use. Omit for all functions; [] for none.""" 125 options: dict[str, Any] 126 """Additional integration options interpreted by Squid Core or connector AI functions.""" 127 connectedAsMcp: bool 128 """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.
Optional instructions for the connected integration agent, overriding the default.
131class AiConnectedKnowledgeBaseMetadata(TypedDict, total=False): 132 """Metadata for a connected knowledge base.""" 133 134 knowledgeBaseId: str 135 description: str 136 includeMetadata: bool
Metadata for a connected knowledge base.
683class AiContextFileOptions(TypedDict, total=False): 684 """Options for file context processing.""" 685 686 chunkOverlap: int 687 ragType: str
Options for file context processing.
647class AiContextTextOptions(TypedDict, total=False): 648 """Options for text context processing.""" 649 650 chunkOverlap: int 651 """Amount of chunk overlap in characters.""" 652 ragType: str 653 """The type of RAG to use."""
Options for text context processing.
139class AiFileUrl(TypedDict, total=False): 140 """File URL to include in chat context.""" 141 142 id: str 143 type: str 144 purpose: str 145 url: str 146 description: str 147 fileName: str
File URL to include in chat context.
812class AiFunctionAttributes(TypedDict, total=False): 813 """Additional optional readonly metadata for an AI function.""" 814 815 integrationType: list[str] 816 """Types of integration this function is used for. Functions with a defined 817 'integrationType' require 'integrationId' to be passed as part of the function context."""
Additional optional readonly metadata for an AI function.
820class AiFunctionMetadata(TypedDict, total=False): 821 """Metadata describing an AI function available in the application. 822 823 Returned by :meth:`AiClient.list_functions`. 824 """ 825 826 serviceFunction: str 827 """The fully qualified name of the function ('ServiceName:functionName'). Required.""" 828 description: str 829 """Description of what the function does.""" 830 promptId: str 831 """Opaque ID of a registered prompt that supplies this function's description; 832 resolved server-side.""" 833 params: list[AiFunctionParam] 834 """Parameters that the function accepts. Required.""" 835 attributes: AiFunctionAttributes 836 """Additional attributes for the function.""" 837 categories: list[str] 838 """Categories this function belongs to.""" 839 internal: bool 840 """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().
The fully qualified name of the function ('ServiceName:functionName'). Required.
795class AiFunctionParam(TypedDict, total=False): 796 """Defines the structure of a parameter for an AI function.""" 797 798 name: str 799 """Name of the parameter. Required.""" 800 description: str 801 """Description of the parameter's purpose. Required.""" 802 type: AiFunctionParamType 803 """Data type of the parameter. Required.""" 804 required: bool 805 """Indicates if the parameter is mandatory. Required.""" 806 enum: list[str] 807 """List of possible values for the parameter, if applicable.""" 808 schema: dict[str, Any] 809 """JSON Schema of an ``object`` parameter's value, which Squid validates every call against."""
Defines the structure of a parameter for an AI function.
618class AiKnowledgeBase(TypedDict, total=False): 619 """An AI knowledge base that can be attached to an AI agent. 620 621 Returned by :meth:`AiClient.list_knowledge_bases`. 622 """ 623 624 id: str 625 """The unique identifier of the knowledge base. Required.""" 626 appId: str 627 """The app ID that the knowledge base belongs to. Required.""" 628 description: str 629 """The user's description of the knowledge base. Required.""" 630 metadataFields: list[AiKnowledgeBaseMetadataField] 631 """Predefined metadata fields that can be used for filtering. Required.""" 632 embeddingModel: AiEmbeddingsModelSelection 633 """The embedding model used by this knowledge base. Required.""" 634 chatModel: AiChatModelSelection 635 """The model used when asking questions of this knowledge base. Required.""" 636 vectorDbType: VectorDbType 637 """The vector store backend the knowledge base reads/writes from. Set at creation 638 and immutable thereafter. Absent on older records.""" 639 graphRag: AiKnowledgeBaseGraphConfig 640 """Opt-in GraphRAG configuration. Only honored for ``vectorDbType: 'mongoAtlas'`` 641 knowledge bases; enables per-chunk entity/relationship extraction at ingest and 642 ``searchMode: 'graph'`` at query time.""" 643 updatedAt: str 644 """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().
Predefined metadata fields that can be used for filtering. Required.
The embedding model used by this knowledge base. Required.
The model used when asking questions of this knowledge base. Required.
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.
557class AiKnowledgeBaseGraphConceptsConfig(TypedDict, total=False): 558 """Configuration of the graph's concept layer (facet taxonomies).""" 559 560 facets: Union[list[str], Literal["auto"]] 561 """Which metadata fields become value facets. ``'auto'`` (the default) profiles the KB's 562 context metadata and selects the categorical fields; an explicit list overrides 563 auto-selection; an empty list disables value facets.""" 564 pathFacets: list[AiKnowledgeBaseGraphPathFacetConfig] 565 """Explicit path facets, e.g. ``[{'field': 'folderPath', 'type': 'path'}]``. A path facet 566 always builds when its field has values, independent of ``facets``."""
Configuration of the graph's concept layer (facet taxonomies).
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.
581class AiKnowledgeBaseGraphConfig(_AiKnowledgeBaseGraphConfigRequired, total=False): 582 """Per-knowledge-base GraphRAG configuration. 583 584 Opt-in and mutable (unlike ``embeddingModel``/``vectorDbType``); only honored for 585 ``vectorDbType: 'mongoAtlas'`` knowledge bases. Enabling it on a knowledge base that 586 already has content backfills the graph automatically once the KB goes quiet. 587 588 On upsert the supplied value replaces the stored config rather than merging into it, 589 so include every key that should remain set. 590 """ 591 592 extractionModel: AiChatModelSelection 593 """Chat model used for per-chunk entity/relationship extraction. Defaults to the server's 594 graph model.""" 595 entityTypes: list[str] 596 """Optional domain taxonomy hint (entity types) injected into the extraction prompt.""" 597 autoBuildDebounceMs: int 598 """Quiet window (milliseconds) after the last graph activity before the sweep auto-builds 599 the structure. Must be a positive integer. Defaults to the server's window (5 minutes).""" 600 autoBuildPaused: bool 601 """When true, the sweep starts no automatic build, entity resolution included: activity keeps 602 arming the build, and the first quiet window after the flag is cleared runs it. ``rebuild_graph`` 603 stays available. To hold only the structural build, use ``structuralBuildSchedule``. Defaults to 604 false.""" 605 structuralBuildSchedule: str 606 """When the sweep may start an automatic structural build: ``'debounced'`` (one quiet window 607 after activity), ``'off'`` (manual ``rebuild_graph`` only) or a 5-field cron expression. 608 Entity resolution keeps running either way. Omitted means the server's default.""" 609 structuralBuildTimeZone: str 610 """IANA time zone of a cron ``structuralBuildSchedule``. Omitted means the server's default (UTC).""" 611 structuralBuildCatchUpMs: int 612 """How long after a cron slot its structural build may still start (milliseconds); past it, the 613 build waits for the next slot. Omitted means the server's default (3 hours).""" 614 concepts: AiKnowledgeBaseGraphConceptsConfig 615 """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.
Chat model used for per-chunk entity/relationship extraction. Defaults to the server's graph model.
Optional domain taxonomy hint (entity types) injected into the extraction prompt.
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).
When true, the sweep starts no automatic build, entity resolution included: activity keeps
arming the build, and the first quiet window after the flag is cleared runs it. rebuild_graph
stays available. To hold only the structural build, use structuralBuildSchedule. Defaults to
false.
When the sweep may start an automatic structural build: 'debounced' (one quiet window
after activity), 'off' (manual rebuild_graph only) or a 5-field cron expression.
Entity resolution keeps running either way. Omitted means the server's default.
IANA time zone of a cron structuralBuildSchedule. Omitted means the server's default (UTC).
How long after a cron slot its structural build may still start (milliseconds); past it, the build waits for the next slot. Omitted means the server's default (3 hours).
Concept-layer (facet taxonomy) configuration. Omitted means facets: 'auto'.
732class AiKnowledgeBaseGraphFilter(TypedDict): 733 """Graph scope for a knowledge-base search: restricts results to the documents under one 734 concept of the KB's graph. Composes with every ``searchMode``. Requires ``graphRag.enabled``.""" 735 736 underConcept: str 737 """The concept to scope to: a facet nodeId (``facet_…`` — exact) or a concept name, 738 resolved server-side (exact, then alias, then similarity). An unresolvable ref fails with 739 ``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.
548class AiKnowledgeBaseGraphPathFacetConfig( 549 _AiKnowledgeBaseGraphPathFacetConfigRequired, total=False 550): 551 """A path facet: a deterministic tree built by splitting a hierarchical path field.""" 552 553 separator: str 554 """Path segment separator. Defaults to ``'/'``."""
A path facet: a deterministic tree built by splitting a hierarchical path field.
718class AiKnowledgeBaseGraphSearchOptions(TypedDict, total=False): 719 """Tuning for ``searchMode: 'graph'`` (GraphRAG) retrieval. Ignored for other search modes.""" 720 721 seedLimit: int 722 """Entities seeded via vector search before graph expansion. Default 8, max 25.""" 723 maxHops: int 724 """Number of hops to expand from each seed (traversal depth + 1). Default 2, max 3.""" 725 includeGraphContext: bool 726 """When True, the server attaches the traversed subgraph to the search response as 727 ``graphContext``. Default False. Read it via 728 :meth:`~squidcloud.ai.KnowledgeBaseClient.search_with_graph_context`; 729 :meth:`~squidcloud.ai.KnowledgeBaseClient.search` returns only the chunks."""
Tuning for searchMode: 'graph' (GraphRAG) retrieval. Ignored for other search modes.
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.
505class AiKnowledgeBaseMetadataField(TypedDict, total=False): 506 """Metadata field definition for a knowledge base.""" 507 508 name: str 509 dataType: str 510 required: bool 511 description: str
Metadata field definition for a knowledge base.
221class AiModelRoutingOptions(TypedDict): 222 """Lets a routing model pick which of several vendor models answers an ``ask``. 223 224 The routing model reads the question, the agent's instructions and a card per candidate 225 and names one of them. Only single questions are routed. 226 """ 227 228 models: list[AiChatModelName] 229 """At least two distinct vendor model names to choose from.""" 230 routingModel: AiChatModelName 231 """The vendor model that makes the choice."""
Lets a routing model pick which of several vendor models answers an ask.
The routing model reads the question, the agent's instructions and a card per candidate and names one of them. Only single questions are routed.
238class AiModelRoutingResult(TypedDict, total=False): 239 """Which model the routing model chose for an ``ask`` and what the routing call cost.""" 240 241 model: AiChatModelName 242 """The chosen candidate. A ``backupModel`` may still have served the answer.""" 243 routingModel: AiChatModelName 244 """The model that made the choice.""" 245 inputTokens: int 246 """Input tokens of the routing call.""" 247 outputTokens: int 248 """Output tokens of the routing call.""" 249 costUsd: float 250 """Cost of the routing call in USD, when known."""
Which model the routing model chose for an ask and what the routing call cost.
187class AiPiiOptions(TypedDict, total=False): 188 """Refuses prompts carrying PII before they reach the agent's model. 189 190 The inverse of GuardrailsOptions.disablePii, which asks the agent's own model 191 not to emit PII in its answer. 192 """ 193 194 onDetect: str 195 """'reject' refuses a prompt carrying PII; 'off' (default) disables screening.""" 196 entities: list[str] 197 """Entity kinds to screen for: 'email', 'phoneNumber', 'creditCard', 'ssn', 'iban', 'passport'.""" 198 customRules: list[str] 199 """App-specific PII described in plain language, screened by classifierModel.""" 200 classifierModel: AiChatModelSelection 201 """Model screening customRules. Defaults to 'gpt-6-luna'.""" 202 allowList: list[str] 203 """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.
389class AiQueryAnalyzeResultsOptions(TypedDict, total=False): 390 """Options for the result-analysis stage of AI query.""" 391 392 disabled: bool 393 """When true, skip analysis and return raw results only.""" 394 enableCodeInterpreter: bool 395 """Enable code interpreter mode (default false).""" 396 aiOptions: AiChatOptions 397 """Customize AI agent behavior used by the stage.""" 398 agentId: AiAgentId 399 """If set, use this agent to analyze results and produce the final answer."""
Options for the result-analysis stage of AI query.
375class AiQueryGenerateQueryOptions(TypedDict, total=False): 376 """Options for the query-generation stage of AI query.""" 377 378 aiOptions: AiChatOptions 379 """Customize AI agent behavior used by the stage.""" 380 maxErrorCorrections: int 381 """Number of retries due to errors in a generated AI query (default 2).""" 382 agentId: AiAgentId 383 """If set, use this agent to generate the query.""" 384 allowClarification: bool 385 """When true, allow the AI to ask a clarifying question instead of 386 generating a query for ambiguous prompts (default false)."""
Options for the query-generation stage of AI query.
411class AiQueryOptions(TypedDict, total=False): 412 """Options for configuring AI query execution. 413 414 Mirrors ``AiQueryOptions`` from the TypeScript SDK. All fields optional. 415 """ 416 417 instructions: str 418 """Custom instructions applied to all stages unless overridden per-stage.""" 419 enableRawResults: bool 420 """Enable raw results output.""" 421 selectCollectionsOptions: AiQuerySelectCollectionsOptions 422 """Collection-selection stage options.""" 423 generateQueryOptions: AiQueryGenerateQueryOptions 424 """Query-generation stage options.""" 425 analyzeResultsOptions: AiQueryAnalyzeResultsOptions 426 """Result-analysis stage options.""" 427 sessionContext: AiSessionContext 428 """Session information (``agentId`` may be omitted).""" 429 memoryOptions: AiAgentMemoryOptions 430 """Memory/session configuration.""" 431 generateQueriesOnly: bool 432 """If true, return generated queries without executing or analyzing them.""" 433 validateWithAiOptions: AiQueryValidateWithAiOptions 434 """Optional AI validation of generated queries."""
Options for configuring AI query execution.
Mirrors AiQueryOptions from the TypeScript SDK. All fields optional.
364class AiQuerySelectCollectionsOptions(TypedDict, total=False): 365 """Options for the collection-selection stage of AI query.""" 366 367 collectionsToUse: list[str] 368 """Restrict query to these collections. Defaults to all collections.""" 369 runMode: AiQueryCollectionsSelectionRunMode 370 """Stage behavior: 'default', 'force', or 'disable'.""" 371 aiOptions: AiChatOptions 372 """Customize AI agent behavior used by the stage."""
Options for the collection-selection stage of AI query.
402class AiQueryValidateWithAiOptions(TypedDict, total=False): 403 """Options for AI-based validation of generated queries.""" 404 405 enabled: bool 406 """Whether AI validation is enabled.""" 407 aiOptions: AiChatOptions 408 """Defaults to the same model used for query generation."""
Options for AI-based validation of generated queries.
351class AiSessionContext(TypedDict, total=False): 352 """Session context for AI query execution. 353 354 Mirrors the TypeScript ``AiSessionContext`` type. All fields optional 355 here because the query endpoint accepts a partial context (``agentId`` 356 may be omitted). 357 """ 358 359 clientId: str 360 agentId: str 361 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).
150class AiStructuredOutputFormat(TypedDict): 151 """Structured output format for JSON responses.""" 152 153 type: Literal["json_schema"] 154 schema: dict[str, Any]
Structured output format for JSON responses.
1065class AudioClient: 1066 """Audio transcription and speech synthesis. 1067 1068 Obtained via :meth:`AiClient.audio`. 1069 1070 Example:: 1071 1072 text = await squid.ai().audio().transcribe(audio_bytes) 1073 speech = await squid.ai().audio().create_speech("Hello!", options={"voice": "nova"}) 1074 """ 1075 1076 def __init__(self, http: HttpTransport) -> None: 1077 self._http = http 1078 1079 async def transcribe( 1080 self, 1081 audio_data: bytes, 1082 filename: str = "audio.wav", 1083 content_type: str = "audio/wav", 1084 *, 1085 options: dict[str, Any] | None = None, 1086 ) -> str: 1087 """Transcribe audio to text. 1088 1089 Args: 1090 audio_data: The audio file content as bytes. 1091 filename: The filename (used in the multipart upload). 1092 content_type: The MIME type of the audio file. 1093 options: Provider-specific transcription options. 1094 1095 Returns: 1096 The transcribed text. 1097 """ 1098 form_data: dict[str, str] = { 1099 "optionsJson": json.dumps(options or {}), 1100 } 1101 result = await self._http.post_form( 1102 "squid-api/v1/ai/audio/transcribe", 1103 data=form_data, 1104 files=[("file", (filename, audio_data, content_type))], 1105 ) 1106 return result if isinstance(result, str) else str(result) 1107 1108 async def create_speech( 1109 self, 1110 text: str, 1111 options: AiAudioCreateSpeechOptions, 1112 ) -> bytes: 1113 """Generate speech audio from text. 1114 1115 Args: 1116 text: The text to convert to speech. 1117 options: Speech generation options. See :class:`AiAudioCreateSpeechOptions`. 1118 Required keys: ``modelName`` (e.g., ``'tts-1'``), ``voice`` 1119 (e.g., ``'nova'``, ``'alloy'``). 1120 1121 Returns: 1122 Raw audio file bytes (e.g., MP3 format by default). 1123 1124 Example:: 1125 1126 audio_data = ( 1127 await squid.ai() 1128 .audio() 1129 .create_speech( 1130 "Hello!", 1131 options={ 1132 "modelName": "tts-1", 1133 "voice": "nova", 1134 }, 1135 ) 1136 ) 1137 with open("speech.mp3", "wb") as f: 1138 f.write(audio_data) 1139 """ 1140 return await self._http.post( 1141 "squid-api/v1/ai/audio/createSpeech", 1142 {"input": text, "options": options}, 1143 )
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"})
1079 async def transcribe( 1080 self, 1081 audio_data: bytes, 1082 filename: str = "audio.wav", 1083 content_type: str = "audio/wav", 1084 *, 1085 options: dict[str, Any] | None = None, 1086 ) -> str: 1087 """Transcribe audio to text. 1088 1089 Args: 1090 audio_data: The audio file content as bytes. 1091 filename: The filename (used in the multipart upload). 1092 content_type: The MIME type of the audio file. 1093 options: Provider-specific transcription options. 1094 1095 Returns: 1096 The transcribed text. 1097 """ 1098 form_data: dict[str, str] = { 1099 "optionsJson": json.dumps(options or {}), 1100 } 1101 result = await self._http.post_form( 1102 "squid-api/v1/ai/audio/transcribe", 1103 data=form_data, 1104 files=[("file", (filename, audio_data, content_type))], 1105 ) 1106 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.
1108 async def create_speech( 1109 self, 1110 text: str, 1111 options: AiAudioCreateSpeechOptions, 1112 ) -> bytes: 1113 """Generate speech audio from text. 1114 1115 Args: 1116 text: The text to convert to speech. 1117 options: Speech generation options. See :class:`AiAudioCreateSpeechOptions`. 1118 Required keys: ``modelName`` (e.g., ``'tts-1'``), ``voice`` 1119 (e.g., ``'nova'``, ``'alloy'``). 1120 1121 Returns: 1122 Raw audio file bytes (e.g., MP3 format by default). 1123 1124 Example:: 1125 1126 audio_data = ( 1127 await squid.ai() 1128 .audio() 1129 .create_speech( 1130 "Hello!", 1131 options={ 1132 "modelName": "tts-1", 1133 "voice": "nova", 1134 }, 1135 ) 1136 ) 1137 with open("speech.mp3", "wb") as f: 1138 f.write(audio_data) 1139 """ 1140 return await self._http.post( 1141 "squid-api/v1/ai/audio/createSpeech", 1142 {"input": text, "options": options}, 1143 )
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)
949class CreatePdfDimensionsOptions(TypedDict): 950 """PDF output options by custom dimensions.""" 951 952 type: Literal["dimensions"] 953 width: int 954 """Width in pixels.""" 955 height: int 956 """Height in pixels."""
PDF output options by custom dimensions.
930class CreatePdfFormatOptions(TypedDict): 931 """PDF output options by format.""" 932 933 type: Literal["format"] 934 format: Literal[ 935 "letter", 936 "legal", 937 "tabloid", 938 "ledger", 939 "a0", 940 "a1", 941 "a2", 942 "a3", 943 "a4", 944 "a5", 945 "a6", 946 ]
PDF output options by format.
68class EmbeddingModelIdSpec(TypedDict, total=False): 69 """An embedding model a new knowledge base can be created on. 70 71 Returned by :meth:`AiClient.list_embedding_models`. 72 """ 73 74 modelId: str 75 """The embedding model ID used for API calls. Required.""" 76 integrationId: str 77 """The integration ID if this model comes from an integration. Absent for Squid-provided models.""" 78 dimensions: int 79 """The embedding dimensions, present for integration-based models.""" 80 displayName: str 81 """Human-readable display name for the model. Required.""" 82 source: AiModelSource 83 """Where the model comes from: 'vendor' (Squid-provided) or 'connector' (an integration 84 configured on the app). Required.""" 85 replacedBy: str 86 """Set only on a deprecated vendor model, listed on request: the model a new knowledge base 87 asking for this one is created on. Absent for active models.""" 88 isDefault: bool 89 """True on exactly one entry of a non-empty list: the model to create on with no preference."""
An embedding model a new knowledge base can be created on.
Returned by AiClient.list_embedding_models().
The integration ID if this model comes from an integration. Absent for Squid-provided models.
Where the model comes from: 'vendor' (Squid-provided) or 'connector' (an integration configured on the app). Required.
962class ExtractDataFromDocumentOptions(TypedDict, total=False): 963 """Options for document data extraction.""" 964 965 extractImages: bool 966 """Whether to extract embedded images. Defaults to True.""" 967 imageMinSizePixels: int 968 """Minimum image size to extract.""" 969 pageIndexes: list[int] 970 """Specific pages to extract (0-based).""" 971 preferredExtractionMethod: str 972 discardOriginalFile: bool
Options for document data extraction.
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.
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'.
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'.
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'.
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'.
690class FileContextRequest(TypedDict, total=False): 691 """Request to upsert a file context.""" 692 693 contextId: str 694 type: Literal["file"] 695 metadata: dict[str, Any] 696 extractImages: bool 697 """Whether to extract and describe images in the file. Defaults to True. 698 699 This is the opposite of the text context default, which is False: a file's charts and 700 scanned pages carry content its text layer does not, while images referenced from pasted 701 markdown/HTML are usually layout chrome. 702 """ 703 imageMinSizePixels: int 704 imageExtractionModel: AiChatModelSelection 705 options: AiContextFileOptions 706 preferredExtractionMethod: str 707 discardOriginalFile: bool 708 scopes: list[str] 709 """Access scopes granting read access to this context. Only meaningful on a knowledge base 710 with ``accessControl.mode: 'enforced'``. Omitted on a re-ingest keeps existing scopes; an 711 empty list makes the context visible to every caller. 712 """
Request to upsert a file context.
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.
862class FluxOptions(TypedDict, total=False): 863 """Options for Flux image generation.""" 864 865 modelName: Literal["flux-pro-1.1", "flux-kontext-pro"] 866 width: int 867 """Must be multiple of 32, min 256, max 1440.""" 868 height: int 869 """Must be multiple of 32, min 256, max 1440.""" 870 prompt_upsampling: bool 871 seed: int 872 safety_tolerance: int 873 """1 (strict) to 5 (permissive)."""
Options for Flux image generation.
846class GptImageOptions(TypedDict, total=False): 847 """Options for OpenAI gpt-image-* family image generation.""" 848 849 modelName: Literal[ 850 "gpt-image-1", 851 "gpt-image-1-mini", 852 "gpt-image-1.5", 853 "gpt-image-2", 854 "gpt-image-2-2026-04-21", 855 "chatgpt-image-latest", 856 ] 857 quality: Literal["auto", "high", "medium", "low"] 858 size: Literal["1024x1024", "1024x1536", "1536x1024", "auto"] 859 numberOfImagesToGenerate: int
Options for OpenAI gpt-image-* family image generation.
172class GuardrailsOptions(TypedDict, total=False): 173 """Guardrail options for agent responses.""" 174 175 custom: str 176 """A custom guardrail instruction.""" 177 disablePii: bool 178 """Disables personally identifiable information if true.""" 179 professionalTone: bool 180 """Enforces a professional tone if true.""" 181 offTopicAnswers: bool 182 """Prevents off-topic answers if true.""" 183 disableProfanity: bool 184 """Disables profanity if true."""
Guardrail options for agent responses.
991class ImageClient: 992 """Image generation and processing. 993 994 Supports DALL-E, Stable Diffusion Core, and Flux models. 995 996 Obtained via :meth:`AiClient.image`. 997 998 Example:: 999 1000 image_url = ( 1001 await squid.ai() 1002 .image() 1003 .generate( 1004 "a cat astronaut on the moon", 1005 options={"modelName": "gpt-image-1", "quality": "high"}, 1006 ) 1007 ) 1008 """ 1009 1010 def __init__(self, http: HttpTransport) -> None: 1011 self._http = http 1012 1013 async def generate( 1014 self, 1015 prompt: str, 1016 options: ImageGenerateOptions | None = None, 1017 ) -> str: 1018 """Generate an image from a text prompt. 1019 1020 Args: 1021 prompt: A text description of the image to generate. 1022 options: Provider-specific generation options. Use one of: 1023 - :class:`GptImageOptions`: ``{'modelName': 'gpt-image-1', 'quality': 'high', 'size': '1024x1024'}`` 1024 - :class:`FluxOptions`: ``{'modelName': 'flux-pro-1.1', 'width': 1024, 'height': 768}`` 1025 - :class:`StableDiffusionOptions`: ``{'modelName': 'stable-diffusion-core', 'aspectRatio': '16:9'}`` 1026 1027 Returns: 1028 The URL of the generated image. 1029 """ 1030 result = await self._http.post( 1031 "squid-api/v1/ai/image/generate", 1032 {"prompt": prompt, "options": options or {}}, 1033 ) 1034 return result if isinstance(result, str) else str(result) 1035 1036 async def remove_background( 1037 self, 1038 image_data: bytes, 1039 filename: str = "image.png", 1040 content_type: str = "image/png", 1041 ) -> str: 1042 """Remove the background from an image. 1043 1044 Args: 1045 image_data: The image file content as bytes. 1046 filename: The filename (used in the multipart upload). 1047 content_type: The MIME type of the image. 1048 1049 Returns: 1050 The URL of the processed image with the background removed. 1051 """ 1052 result = await self._http.post_form( 1053 "squid-api/v1/ai/image/removeBackground", 1054 data={}, 1055 files=[("file", (filename, image_data, content_type))], 1056 ) 1057 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"},
)
)
1013 async def generate( 1014 self, 1015 prompt: str, 1016 options: ImageGenerateOptions | None = None, 1017 ) -> str: 1018 """Generate an image from a text prompt. 1019 1020 Args: 1021 prompt: A text description of the image to generate. 1022 options: Provider-specific generation options. Use one of: 1023 - :class:`GptImageOptions`: ``{'modelName': 'gpt-image-1', 'quality': 'high', 'size': '1024x1024'}`` 1024 - :class:`FluxOptions`: ``{'modelName': 'flux-pro-1.1', 'width': 1024, 'height': 768}`` 1025 - :class:`StableDiffusionOptions`: ``{'modelName': 'stable-diffusion-core', 'aspectRatio': '16:9'}`` 1026 1027 Returns: 1028 The URL of the generated image. 1029 """ 1030 result = await self._http.post( 1031 "squid-api/v1/ai/image/generate", 1032 {"prompt": prompt, "options": options or {}}, 1033 ) 1034 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.
1036 async def remove_background( 1037 self, 1038 image_data: bytes, 1039 filename: str = "image.png", 1040 content_type: str = "image/png", 1041 ) -> str: 1042 """Remove the background from an image. 1043 1044 Args: 1045 image_data: The image file content as bytes. 1046 filename: The filename (used in the multipart upload). 1047 content_type: The MIME type of the image. 1048 1049 Returns: 1050 The URL of the processed image with the background removed. 1051 """ 1052 result = await self._http.post_form( 1053 "squid-api/v1/ai/image/removeBackground", 1054 data={}, 1055 files=[("file", (filename, image_data, content_type))], 1056 ) 1057 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.
514class IntegrationEmbeddingModelSpec(TypedDict): 515 """Specifies an embedding model from a specific integration.""" 516 517 integrationId: str 518 """The ID of the integration providing the embedding model.""" 519 model: str 520 """The model name as recognized by the provider.""" 521 dimensions: int 522 """The number of dimensions in the embedding vector output."""
Specifies an embedding model from a specific integration.
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.
480class KnowledgeBaseClient: 481 """Operations on a single knowledge base. 482 483 Provides methods for managing knowledge base configuration, upserting 484 and searching text/file contexts, and retrieving individual contexts. 485 486 Obtained via :meth:`AiClient.knowledge_base`. 487 488 Example:: 489 490 kb = squid.ai().knowledge_base("my-kb") 491 await kb.upsert(description="Product documentation") 492 await kb.upsert_contexts( 493 [ 494 { 495 "contextId": "doc-1", 496 "type": "text", 497 "title": "Getting Started", 498 "text": "Welcome to our product...", 499 } 500 ] 501 ) 502 results = await kb.search("How do I get started?") 503 """ 504 505 def __init__(self, http: HttpTransport, kb_id: str) -> None: 506 self._http = http 507 self._kb_id = kb_id 508 509 async def get(self) -> dict | None: 510 """Get the knowledge base details. 511 512 Returns: 513 An ``AiKnowledgeBase`` dict with keys: ``id``, ``appId``, 514 ``description``, ``metadataFields``, ``embeddingModel``, 515 ``chatModel``, ``updatedAt``. Returns ``None`` if not found. 516 """ 517 return await self._http.get(f"squid-api/v1/ai/knowledge-base/get/{self._kb_id}") 518 519 async def upsert( 520 self, 521 *, 522 description: str | None = None, 523 metadata_fields: list[AiKnowledgeBaseMetadataField] | None = None, 524 embedding_model: str | None = None, 525 chat_model: AiChatModelSelection | None = None, 526 name: str | None = None, 527 vector_db_type: VectorDbType | None = None, 528 graph_rag: AiKnowledgeBaseGraphConfig | None = None, 529 ) -> None: 530 """Create or update the knowledge base. 531 532 Args: 533 description: Description of the knowledge base's content. 534 metadata_fields: Schema for metadata fields used in filtering. 535 Each field: ``{'name': str, 'dataType': str, 'required': bool, 'description'?: str}``. 536 embedding_model: The embedding model name for vectorization. 537 Required when creating a new knowledge base. 538 chat_model: The LLM model for answering questions over this KB. 539 name: Display name for the knowledge base. 540 vector_db_type: The vector store backend. Set at creation (defaulting to the 541 server's default) and immutable thereafter. The knowledge graph requires 542 ``'mongoAtlas'``. 543 graph_rag: Opt-in GraphRAG configuration (``{'enabled': True, ...}``). Only 544 honored on ``'mongoAtlas'`` knowledge bases; mutable, unlike 545 ``vector_db_type``. The value replaces the stored config rather than 546 merging into it. See :class:`AiKnowledgeBaseGraphConfig`. 547 """ 548 kb: dict[str, Any] = {"id": self._kb_id} 549 if description is not None: 550 kb["description"] = description 551 if metadata_fields is not None: 552 kb["metadataFields"] = metadata_fields 553 if embedding_model is not None: 554 kb["embeddingModel"] = embedding_model 555 if chat_model is not None: 556 kb["chatModel"] = chat_model 557 if name is not None: 558 kb["name"] = name 559 if vector_db_type is not None: 560 kb["vectorDbType"] = vector_db_type 561 if graph_rag is not None: 562 kb["graphRag"] = graph_rag 563 await self._http.post("squid-api/v1/ai/knowledge-base/upsert", {"knowledgeBase": kb}) 564 565 async def delete(self) -> None: 566 """Delete the knowledge base and all its contexts permanently.""" 567 await self._http.post("squid-api/v1/ai/knowledge-base/delete", {"id": self._kb_id}) 568 569 # --- Contexts --- 570 571 async def get_context( 572 self, context_id: str, *, truncate_text_after: int | None = None 573 ) -> dict | None: 574 """Get a specific context entry. 575 576 Args: 577 context_id: The unique context identifier. 578 truncate_text_after: The number of characters after which the context's 579 text is truncated. Pass ``0`` to return an empty text. 580 581 Returns: 582 An ``AiKnowledgeBaseContext`` dict with keys: ``id``, ``appId``, 583 ``knowledgeBaseId``, ``createdAt``, ``updatedAt``, ``type``, 584 ``title``, ``text``, ``preview``, ``sizeBytes``, ``metadata``, 585 ``requestConfig``. Returns ``None`` if not found. 586 """ 587 params = ( 588 {"truncateTextAfter": str(truncate_text_after)} 589 if truncate_text_after is not None 590 else None 591 ) 592 return await self._http.get( 593 f"squid-api/v1/ai/knowledge-base/getContext/{self._kb_id}/{context_id}", 594 params=params, 595 ) 596 597 async def list_contexts(self, *, truncate_text_after: int | None = None) -> list[dict]: 598 """List all contexts in the knowledge base. 599 600 Deprecated: fetches every context in one call with no pagination — expensive for large 601 knowledge bases. Use :meth:`list_contexts_page` instead, which supports 602 ``offset``/``limit``/``search``. 603 604 Args: 605 truncate_text_after: The number of characters after which each context's 606 text is truncated. 607 608 Returns: 609 A list of ``AiKnowledgeBaseContext`` dicts. 610 """ 611 params = ( 612 {"truncateTextAfter": str(truncate_text_after)} 613 if truncate_text_after is not None 614 else None 615 ) 616 result = await self._http.get( 617 f"squid-api/v1/ai/knowledge-base/listContexts/{self._kb_id}", params=params 618 ) 619 return result.get("contexts", []) if result else [] 620 621 async def list_contexts_page( 622 self, 623 *, 624 offset: int | None = None, 625 limit: int | None = None, 626 search: str | None = None, 627 truncate_text_after: int | None = None, 628 ) -> dict: 629 """List a page of contexts in the knowledge base. 630 631 Args: 632 offset: The number of contexts to skip, for pagination. 633 limit: The maximum number of contexts to return, for pagination. 634 search: Case-insensitive substring search across id/title only. 635 truncate_text_after: The number of characters after which each context's 636 text is truncated. 637 638 Returns: 639 A dict with ``contexts`` (a list of ``AiKnowledgeBaseContext`` dicts for the 640 requested page) and ``totalCount`` (the total number of contexts in the 641 knowledge base, ignoring ``offset``/``limit``). 642 """ 643 params = { 644 key: str(value) 645 for key, value in { 646 "offset": offset, 647 "limit": limit, 648 "search": search, 649 "truncateTextAfter": truncate_text_after, 650 }.items() 651 if value is not None 652 } 653 result = await self._http.get( 654 f"squid-api/v1/ai/knowledge-base/listContextsPage/{self._kb_id}", 655 params=params or None, 656 ) 657 return result if result else {"contexts": [], "totalCount": 0} 658 659 async def upsert_contexts( 660 self, 661 contexts: list[ContextRequest], 662 files: list[tuple[str, bytes, str]] | None = None, 663 ) -> dict: 664 """Add or update contexts in the knowledge base. 665 666 Args: 667 contexts: A list of context request objects. Each must be either: 668 - A :class:`TextContextRequest`: ``{'contextId', 'type': 'text', 'title', 'text', ...}`` 669 - A :class:`FileContextRequest`: ``{'contextId', 'type': 'file', ...}`` 670 files: For file contexts, provide the actual file data as a list of 671 ``(filename, data_bytes, content_type)`` tuples. Must match the 672 order of file contexts in the ``contexts`` list. 673 674 Returns: 675 A dict with ``failures``: a list of ``UpsertContextStatusError`` dicts 676 for any contexts that failed to upsert. 677 678 Example:: 679 680 await kb.upsert_contexts( 681 [ 682 {"contextId": "doc-1", "type": "text", "title": "FAQ", "text": "..."}, 683 {"contextId": "doc-2", "type": "file"}, 684 ], 685 files=[ 686 ("manual.pdf", pdf_bytes, "application/pdf"), 687 ], 688 ) 689 """ 690 form_data = { 691 "knowledgeBaseId": self._kb_id, 692 "contexts": json.dumps(contexts), 693 } 694 file_tuples: list[tuple[str, tuple[str, bytes, str]]] = [] 695 if files: 696 for fname, fdata, ftype in files: 697 file_tuples.append(("files", (fname, fdata, ftype))) 698 return await self._http.post_form( 699 "squid-api/v1/ai/knowledge-base/upsertContexts", 700 data=form_data, 701 files=file_tuples, 702 ) 703 704 async def delete_contexts(self, context_ids: list[str]) -> None: 705 """Delete contexts by their IDs. 706 707 Args: 708 context_ids: List of context IDs to delete. 709 """ 710 await self._http.post( 711 "squid-api/v1/ai/knowledge-base/deleteContexts", 712 {"knowledgeBaseId": self._kb_id, "contextIds": context_ids}, 713 ) 714 715 # --- Search --- 716 717 async def search( 718 self, 719 prompt: str, 720 options: KnowledgeBaseSearchOptions | None = None, 721 ) -> list[dict]: 722 """Search the knowledge base using semantic search. 723 724 Args: 725 prompt: The search query in natural language. 726 options: Search options. See :class:`KnowledgeBaseSearchOptions`. 727 Supports: ``limit``, ``chunkLimit``, ``rerankProvider``, ``rerankScoreThreshold``, 728 ``chatModel``, ``searchMode``, ``graphOptions``, ``graphFilter``. 729 730 Returns: 731 A list of ``AiKnowledgeBaseSearchResultChunk`` dicts, each with: 732 ``contextId``, ``data``, ``metadata``, ``score``. 733 734 Example:: 735 736 chunks = await kb.search( 737 "How do I reset my password?", 738 options={ 739 "limit": 5, 740 "chatModel": "gemini-3.8-flash", 741 }, 742 ) 743 for chunk in chunks: 744 print(f"Score: {chunk['score']}, Data: {chunk['data'][:100]}") 745 """ 746 response = await self.search_with_graph_context(prompt, options) 747 return response.get("chunks", []) 748 749 # --- Knowledge graph --- 750 751 async def search_with_graph_context( 752 self, 753 prompt: str, 754 options: KnowledgeBaseSearchOptions | None = None, 755 ) -> dict: 756 """Like :meth:`search`, but return the full search response instead of only the chunks. 757 758 With ``searchMode: 'graph'`` and ``graphOptions: {'includeGraphContext': True}`` the 759 response also carries ``graphContext``, the subgraph the search traversed. 760 761 Args: 762 prompt: The search query in natural language. 763 options: Search options. See :class:`KnowledgeBaseSearchOptions`. 764 765 Returns: 766 An ``AiKnowledgeBaseSearchResponse`` dict: ``chunks`` (list of result chunk dicts) 767 and, when requested via ``includeGraphContext``, ``graphContext`` 768 (``{'entities': [...], 'relationships': [...]}``). 769 """ 770 search_options: dict[str, Any] = {"prompt": prompt, **(options or {})} 771 result = await self._http.post( 772 "squid-api/v1/ai/knowledge-base/search", 773 { 774 "knowledgeBaseId": self._kb_id, 775 "prompt": prompt, 776 "options": search_options, 777 }, 778 ) 779 return result or {"chunks": []} 780 781 async def get_graph_status(self, *, include_topics: bool | None = None) -> dict: 782 """Get the knowledge base's graph build/readiness status. 783 784 Args: 785 include_topics: Whether to include the topic table (``topics``, ``topicEdges``). 786 Default True; pass False to poll the build state without it. 787 788 Returns: 789 A ``GetKnowledgeBaseGraphStatusResponse`` dict with ``enabled``, ``entityCount``, 790 ``relationshipCount``, ``contextsIndexed``, ``contextsTotal``, and, where available, 791 ``facets``, ``topics``, ``structureStale``, LLM usage fields, and ``buildJob`` 792 (``{'status': 'in_progress' | 'completed' | 'failed', ...}``) for the most recent 793 rebuild. Poll it after :meth:`rebuild_graph` until ``buildJob`` leaves 794 ``'in_progress'``. 795 """ 796 params: dict[str, str] | None = None 797 if include_topics is not None: 798 params = {"includeTopics": "true" if include_topics else "false"} 799 return await self._http.get( 800 f"squid-api/v1/ai/knowledge-base/getGraphStatus/{self._kb_id}", params=params 801 ) 802 803 async def get_file_status(self, path: str) -> dict: 804 """Look up the durable ingestion status of one file by path. 805 806 Args: 807 path: The file's path: ``folderPath/filename``, or just ``filename`` at the 808 upload root. 809 810 Returns: 811 An ``AiKnowledgeBaseFileStatusInfo`` dict: ``status`` is one of ``'completed'``, 812 ``'failed'`` (with ``errorMessage``/``errorCode``), ``'in_progress'``, or 813 ``'no_record'`` when the knowledge base has no trace of that path. 814 """ 815 return await self._http.get( 816 f"squid-api/v1/ai/knowledge-base/getFileStatus/{self._kb_id}", 817 params={"path": path}, 818 ) 819 820 async def get_folder_status(self, folder_path: str, *, file_limit: int | None = None) -> dict: 821 """Search and aggregate the durable ingestion status of every file matching ``folder_path``. 822 823 Read three ways and unioned: a folder subtree (matched the same segment-safe way as 824 ``$underPath`` metadata filters), a bare filename anywhere in the knowledge base, and, 825 when it contains a ``/``, an exact ``folder_path/filename`` path. 826 827 Args: 828 folder_path: The folder subtree, bare filename, or exact file path to search for. 829 file_limit: Maximum number of files to return in ``files``, prioritizing failures. 830 Defaults to 50. 831 832 Returns: 833 An ``AiKnowledgeBaseFolderStatusResponse`` dict with ``counts`` (per-status totals), 834 ``totalFiles``, ``hasAnyRecords``, ``files`` (capped, failures first), and 835 ``truncated``. 836 """ 837 params = { 838 key: str(value) 839 for key, value in {"folderPath": folder_path, "fileLimit": file_limit}.items() 840 if value is not None 841 } 842 return await self._http.get( 843 f"squid-api/v1/ai/knowledge-base/getFolderStatus/{self._kb_id}", 844 params=params, 845 ) 846 847 async def rebuild_graph( 848 self, 849 *, 850 mode: Literal["full", "structural"] | None = None, 851 ignore_active_bulk_jobs: bool | None = None, 852 ) -> None: 853 """Enqueue a graph rebuild/backfill. Requires ``graphRag.enabled``. 854 855 Only one rebuild can run per knowledge base at a time; track progress via 856 :meth:`get_graph_status`. A rebuild while a bulk-ingestion job on the knowledge base is 857 still active is refused (``GRAPH_REBUILD_BLOCKED_BY_BULK_JOB``). 858 859 Args: 860 mode: ``'structural'`` (the default) keeps the already-extracted entity graph and 861 rebuilds just the concept layer; ``'full'`` wipes the graph and re-extracts every 862 context with an LLM — expensive, and only needed when the extraction itself must 863 be redone (e.g. after changing ``entityTypes`` or ``extractionModel``). 864 ignore_active_bulk_jobs: start the rebuild even while a bulk-ingestion job is active. 865 For a wedged job only: the rebuild re-extracts what a live job is still merging. 866 """ 867 request: dict[str, Any] = {"knowledgeBaseId": self._kb_id} 868 if mode is not None: 869 request["mode"] = mode 870 if ignore_active_bulk_jobs is not None: 871 request["ignoreActiveBulkJobs"] = ignore_active_bulk_jobs 872 await self._http.post("squid-api/v1/ai/knowledge-base/rebuildGraph", request) 873 874 async def query_graph( 875 self, 876 op: KnowledgeBaseGraphQueryOp, 877 *, 878 ref: str | None = None, 879 ref_b: str | None = None, 880 context_id: str | None = None, 881 query: str | None = None, 882 depth: int | None = None, 883 hops: int | None = None, 884 recursive: bool | None = None, 885 limit: int | None = None, 886 context_metadata_filter: dict[str, Any] | None = None, 887 ) -> dict: 888 """Query the knowledge base's graph (documents, entities, themes, facets). 889 890 Requires ``graphRag.enabled`` on the knowledge base. 891 892 Args: 893 op: The operation to run. 894 ref: Node ref (name, facet nodeId, or a topic or entity id from 895 :meth:`explore_graph`). Required by resolve/describe/subtree/docsUnder/ 896 neighborhood/pathBetween/relationship. 897 ref_b: Second node ref for ``pathBetween``, and the target entity for ``relationship``. 898 context_id: The document's contextId for ``conceptsOf``. 899 query: The free-text question for ``globalSummary``. 900 depth: ``subtree``: maximum depth below the resolved node. Default (and cap) 3. 901 hops: ``neighborhood``: expansion hops from the resolved entity. Default 1, max 2. 902 recursive: ``docsUnder``: when True (the default), include documents under the whole 903 subtree, not just the node itself. 904 limit: ``docsUnder`` and ``relationship``: maximum documents returned. Default 25, max 100. 905 context_metadata_filter: ``docsUnder`` and ``relationship``: keeps only the documents 906 whose context matches this metadata filter (context-record metadata only). 907 908 Returns: 909 A ``QueryKnowledgeBaseGraphResponse`` dict; which keys are present depends on ``op`` 910 (e.g. ``overview`` for 'overview', ``matches`` for 'resolve', ``node``/``path``/ 911 ``related`` for 'describe', ``tree``, ``documents``/``totalDocs``, ``concepts``, 912 ``graph``, ``pathBetween``, ``summaries``, ``relationship``). 913 """ 914 request: dict[str, Any] = {"knowledgeBaseId": self._kb_id, "op": op} 915 if ref is not None: 916 request["ref"] = ref 917 if ref_b is not None: 918 request["refB"] = ref_b 919 if context_id is not None: 920 request["contextId"] = context_id 921 if query is not None: 922 request["query"] = query 923 if depth is not None: 924 request["depth"] = depth 925 if hops is not None: 926 request["hops"] = hops 927 if recursive is not None: 928 request["recursive"] = recursive 929 if limit is not None: 930 request["limit"] = limit 931 if context_metadata_filter is not None: 932 request["contextMetadataFilter"] = context_metadata_filter 933 return await self._http.post("squid-api/v1/ai/knowledge-base/queryGraph", request) 934 935 async def explore_graph( 936 self, 937 *, 938 node_limit: int | None = None, 939 topic_id: str | None = None, 940 entity_id: str | None = None, 941 search: str | None = None, 942 context_metadata_filter: dict[str, Any] | None = None, 943 include_topics: bool | None = None, 944 ) -> dict: 945 """Get a bounded slice of the knowledge base's entity graph for exploration/visualization. 946 947 By default returns the highest-degree entities and the relationships among them. Requires 948 ``graphRag.enabled``. ``topic_id``, ``entity_id`` and ``search`` select other entity pools; 949 pass at most one of them. 950 951 Args: 952 node_limit: Hard cap on returned nodes. Default 200, max 1000. 953 topic_id: Restricts the subgraph to entities under the given topic node id. Ids come 954 from :meth:`get_graph_status`'s ``topics`` and churn on rebuild. 955 entity_id: Centers the subgraph on one entity: the entity plus its neighbors, strongest 956 relationships first. Ids come from the returned nodes and churn on rebuild. 957 search: Finds entities by name (exact, then prefix, then substring); when no name 958 matches, returns the entities nearest in meaning. 959 context_metadata_filter: Keeps only the entities mentioned by contexts matching this 960 metadata filter (context-record metadata only). 961 include_topics: Whether to attach the topic table (``topics``). Default True; pass 962 False when the caller already holds it. 963 964 Returns: 965 An ``ExploreKnowledgeBaseGraphResponse`` dict: ``nodes``, ``edges`` (the heaviest, 966 capped; ``edgesTruncated`` when cut), ``totalCount`` when counted, ``searchMatch`` for 967 a search, ``scopeTruncated`` when the filter matched too many contexts, and, once the 968 concept layer has been built, ``topics``. 969 """ 970 request: dict[str, Any] = {"knowledgeBaseId": self._kb_id} 971 if node_limit is not None: 972 request["nodeLimit"] = node_limit 973 if topic_id is not None: 974 request["topicId"] = topic_id 975 if entity_id is not None: 976 request["entityId"] = entity_id 977 if search is not None: 978 request["search"] = search 979 if context_metadata_filter is not None: 980 request["contextMetadataFilter"] = context_metadata_filter 981 if include_topics is not None: 982 request["includeTopics"] = include_topics 983 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?")
509 async def get(self) -> dict | None: 510 """Get the knowledge base details. 511 512 Returns: 513 An ``AiKnowledgeBase`` dict with keys: ``id``, ``appId``, 514 ``description``, ``metadataFields``, ``embeddingModel``, 515 ``chatModel``, ``updatedAt``. Returns ``None`` if not found. 516 """ 517 return await self._http.get(f"squid-api/v1/ai/knowledge-base/get/{self._kb_id}")
Get the knowledge base details.
Returns:
An
AiKnowledgeBasedict with keys:id,appId,description,metadataFields,embeddingModel,chatModel,updatedAt. ReturnsNoneif not found.
519 async def upsert( 520 self, 521 *, 522 description: str | None = None, 523 metadata_fields: list[AiKnowledgeBaseMetadataField] | None = None, 524 embedding_model: str | None = None, 525 chat_model: AiChatModelSelection | None = None, 526 name: str | None = None, 527 vector_db_type: VectorDbType | None = None, 528 graph_rag: AiKnowledgeBaseGraphConfig | None = None, 529 ) -> None: 530 """Create or update the knowledge base. 531 532 Args: 533 description: Description of the knowledge base's content. 534 metadata_fields: Schema for metadata fields used in filtering. 535 Each field: ``{'name': str, 'dataType': str, 'required': bool, 'description'?: str}``. 536 embedding_model: The embedding model name for vectorization. 537 Required when creating a new knowledge base. 538 chat_model: The LLM model for answering questions over this KB. 539 name: Display name for the knowledge base. 540 vector_db_type: The vector store backend. Set at creation (defaulting to the 541 server's default) and immutable thereafter. The knowledge graph requires 542 ``'mongoAtlas'``. 543 graph_rag: Opt-in GraphRAG configuration (``{'enabled': True, ...}``). Only 544 honored on ``'mongoAtlas'`` knowledge bases; mutable, unlike 545 ``vector_db_type``. The value replaces the stored config rather than 546 merging into it. See :class:`AiKnowledgeBaseGraphConfig`. 547 """ 548 kb: dict[str, Any] = {"id": self._kb_id} 549 if description is not None: 550 kb["description"] = description 551 if metadata_fields is not None: 552 kb["metadataFields"] = metadata_fields 553 if embedding_model is not None: 554 kb["embeddingModel"] = embedding_model 555 if chat_model is not None: 556 kb["chatModel"] = chat_model 557 if name is not None: 558 kb["name"] = name 559 if vector_db_type is not None: 560 kb["vectorDbType"] = vector_db_type 561 if graph_rag is not None: 562 kb["graphRag"] = graph_rag 563 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, unlikevector_db_type. The value replaces the stored config rather than merging into it. SeeAiKnowledgeBaseGraphConfig.
565 async def delete(self) -> None: 566 """Delete the knowledge base and all its contexts permanently.""" 567 await self._http.post("squid-api/v1/ai/knowledge-base/delete", {"id": self._kb_id})
Delete the knowledge base and all its contexts permanently.
571 async def get_context( 572 self, context_id: str, *, truncate_text_after: int | None = None 573 ) -> dict | None: 574 """Get a specific context entry. 575 576 Args: 577 context_id: The unique context identifier. 578 truncate_text_after: The number of characters after which the context's 579 text is truncated. Pass ``0`` to return an empty text. 580 581 Returns: 582 An ``AiKnowledgeBaseContext`` dict with keys: ``id``, ``appId``, 583 ``knowledgeBaseId``, ``createdAt``, ``updatedAt``, ``type``, 584 ``title``, ``text``, ``preview``, ``sizeBytes``, ``metadata``, 585 ``requestConfig``. Returns ``None`` if not found. 586 """ 587 params = ( 588 {"truncateTextAfter": str(truncate_text_after)} 589 if truncate_text_after is not None 590 else None 591 ) 592 return await self._http.get( 593 f"squid-api/v1/ai/knowledge-base/getContext/{self._kb_id}/{context_id}", 594 params=params, 595 )
Get a specific context entry.
Arguments:
- context_id: The unique context identifier.
- truncate_text_after: The number of characters after which the context's
text is truncated. Pass
0to return an empty text.
Returns:
An
AiKnowledgeBaseContextdict with keys:id,appId,knowledgeBaseId,createdAt,updatedAt,type,title,text,preview,sizeBytes,metadata,requestConfig. ReturnsNoneif not found.
597 async def list_contexts(self, *, truncate_text_after: int | None = None) -> list[dict]: 598 """List all contexts in the knowledge base. 599 600 Deprecated: fetches every context in one call with no pagination — expensive for large 601 knowledge bases. Use :meth:`list_contexts_page` instead, which supports 602 ``offset``/``limit``/``search``. 603 604 Args: 605 truncate_text_after: The number of characters after which each context's 606 text is truncated. 607 608 Returns: 609 A list of ``AiKnowledgeBaseContext`` dicts. 610 """ 611 params = ( 612 {"truncateTextAfter": str(truncate_text_after)} 613 if truncate_text_after is not None 614 else None 615 ) 616 result = await self._http.get( 617 f"squid-api/v1/ai/knowledge-base/listContexts/{self._kb_id}", params=params 618 ) 619 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.
Arguments:
- truncate_text_after: The number of characters after which each context's text is truncated.
Returns:
A list of
AiKnowledgeBaseContextdicts.
621 async def list_contexts_page( 622 self, 623 *, 624 offset: int | None = None, 625 limit: int | None = None, 626 search: str | None = None, 627 truncate_text_after: int | None = None, 628 ) -> dict: 629 """List a page of contexts in the knowledge base. 630 631 Args: 632 offset: The number of contexts to skip, for pagination. 633 limit: The maximum number of contexts to return, for pagination. 634 search: Case-insensitive substring search across id/title only. 635 truncate_text_after: The number of characters after which each context's 636 text is truncated. 637 638 Returns: 639 A dict with ``contexts`` (a list of ``AiKnowledgeBaseContext`` dicts for the 640 requested page) and ``totalCount`` (the total number of contexts in the 641 knowledge base, ignoring ``offset``/``limit``). 642 """ 643 params = { 644 key: str(value) 645 for key, value in { 646 "offset": offset, 647 "limit": limit, 648 "search": search, 649 "truncateTextAfter": truncate_text_after, 650 }.items() 651 if value is not None 652 } 653 result = await self._http.get( 654 f"squid-api/v1/ai/knowledge-base/listContextsPage/{self._kb_id}", 655 params=params or None, 656 ) 657 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.
- truncate_text_after: The number of characters after which each context's text is truncated.
Returns:
A dict with
contexts(a list ofAiKnowledgeBaseContextdicts for the requested page) andtotalCount(the total number of contexts in the knowledge base, ignoringoffset/limit).
659 async def upsert_contexts( 660 self, 661 contexts: list[ContextRequest], 662 files: list[tuple[str, bytes, str]] | None = None, 663 ) -> dict: 664 """Add or update contexts in the knowledge base. 665 666 Args: 667 contexts: A list of context request objects. Each must be either: 668 - A :class:`TextContextRequest`: ``{'contextId', 'type': 'text', 'title', 'text', ...}`` 669 - A :class:`FileContextRequest`: ``{'contextId', 'type': 'file', ...}`` 670 files: For file contexts, provide the actual file data as a list of 671 ``(filename, data_bytes, content_type)`` tuples. Must match the 672 order of file contexts in the ``contexts`` list. 673 674 Returns: 675 A dict with ``failures``: a list of ``UpsertContextStatusError`` dicts 676 for any contexts that failed to upsert. 677 678 Example:: 679 680 await kb.upsert_contexts( 681 [ 682 {"contextId": "doc-1", "type": "text", "title": "FAQ", "text": "..."}, 683 {"contextId": "doc-2", "type": "file"}, 684 ], 685 files=[ 686 ("manual.pdf", pdf_bytes, "application/pdf"), 687 ], 688 ) 689 """ 690 form_data = { 691 "knowledgeBaseId": self._kb_id, 692 "contexts": json.dumps(contexts), 693 } 694 file_tuples: list[tuple[str, tuple[str, bytes, str]]] = [] 695 if files: 696 for fname, fdata, ftype in files: 697 file_tuples.append(("files", (fname, fdata, ftype))) 698 return await self._http.post_form( 699 "squid-api/v1/ai/knowledge-base/upsertContexts", 700 data=form_data, 701 files=file_tuples, 702 )
Add or update contexts in the knowledge base.
Arguments:
- contexts: A list of context request objects. Each must be either:
- A
TextContextRequest:{'contextId', 'type': 'text', 'title', 'text', ...} - A
FileContextRequest:{'contextId', 'type': 'file', ...}
- A
- 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 thecontextslist.
Returns:
A dict with
failures: a list ofUpsertContextStatusErrordicts 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"),
],
)
704 async def delete_contexts(self, context_ids: list[str]) -> None: 705 """Delete contexts by their IDs. 706 707 Args: 708 context_ids: List of context IDs to delete. 709 """ 710 await self._http.post( 711 "squid-api/v1/ai/knowledge-base/deleteContexts", 712 {"knowledgeBaseId": self._kb_id, "contextIds": context_ids}, 713 )
Delete contexts by their IDs.
Arguments:
- context_ids: List of context IDs to delete.
717 async def search( 718 self, 719 prompt: str, 720 options: KnowledgeBaseSearchOptions | None = None, 721 ) -> list[dict]: 722 """Search the knowledge base using semantic search. 723 724 Args: 725 prompt: The search query in natural language. 726 options: Search options. See :class:`KnowledgeBaseSearchOptions`. 727 Supports: ``limit``, ``chunkLimit``, ``rerankProvider``, ``rerankScoreThreshold``, 728 ``chatModel``, ``searchMode``, ``graphOptions``, ``graphFilter``. 729 730 Returns: 731 A list of ``AiKnowledgeBaseSearchResultChunk`` dicts, each with: 732 ``contextId``, ``data``, ``metadata``, ``score``. 733 734 Example:: 735 736 chunks = await kb.search( 737 "How do I reset my password?", 738 options={ 739 "limit": 5, 740 "chatModel": "gemini-3.8-flash", 741 }, 742 ) 743 for chunk in chunks: 744 print(f"Score: {chunk['score']}, Data: {chunk['data'][:100]}") 745 """ 746 response = await self.search_with_graph_context(prompt, options) 747 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,rerankScoreThreshold,chatModel,searchMode,graphOptions,graphFilter.
Returns:
A list of
AiKnowledgeBaseSearchResultChunkdicts, each with:contextId,data,metadata,score.
Example::
chunks = await kb.search(
"How do I reset my password?",
options={
"limit": 5,
"chatModel": "gemini-3.8-flash",
},
)
for chunk in chunks:
print(f"Score: {chunk['score']}, Data: {chunk['data'][:100]}")
751 async def search_with_graph_context( 752 self, 753 prompt: str, 754 options: KnowledgeBaseSearchOptions | None = None, 755 ) -> dict: 756 """Like :meth:`search`, but return the full search response instead of only the chunks. 757 758 With ``searchMode: 'graph'`` and ``graphOptions: {'includeGraphContext': True}`` the 759 response also carries ``graphContext``, the subgraph the search traversed. 760 761 Args: 762 prompt: The search query in natural language. 763 options: Search options. See :class:`KnowledgeBaseSearchOptions`. 764 765 Returns: 766 An ``AiKnowledgeBaseSearchResponse`` dict: ``chunks`` (list of result chunk dicts) 767 and, when requested via ``includeGraphContext``, ``graphContext`` 768 (``{'entities': [...], 'relationships': [...]}``). 769 """ 770 search_options: dict[str, Any] = {"prompt": prompt, **(options or {})} 771 result = await self._http.post( 772 "squid-api/v1/ai/knowledge-base/search", 773 { 774 "knowledgeBaseId": self._kb_id, 775 "prompt": prompt, 776 "options": search_options, 777 }, 778 ) 779 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:
- prompt: The search query in natural language.
- options: Search options. See
KnowledgeBaseSearchOptions.
Returns:
An
AiKnowledgeBaseSearchResponsedict:chunks(list of result chunk dicts) and, when requested viaincludeGraphContext,graphContext({'entities': [...], 'relationships': [...]}).
781 async def get_graph_status(self, *, include_topics: bool | None = None) -> dict: 782 """Get the knowledge base's graph build/readiness status. 783 784 Args: 785 include_topics: Whether to include the topic table (``topics``, ``topicEdges``). 786 Default True; pass False to poll the build state without it. 787 788 Returns: 789 A ``GetKnowledgeBaseGraphStatusResponse`` dict with ``enabled``, ``entityCount``, 790 ``relationshipCount``, ``contextsIndexed``, ``contextsTotal``, and, where available, 791 ``facets``, ``topics``, ``structureStale``, LLM usage fields, and ``buildJob`` 792 (``{'status': 'in_progress' | 'completed' | 'failed', ...}``) for the most recent 793 rebuild. Poll it after :meth:`rebuild_graph` until ``buildJob`` leaves 794 ``'in_progress'``. 795 """ 796 params: dict[str, str] | None = None 797 if include_topics is not None: 798 params = {"includeTopics": "true" if include_topics else "false"} 799 return await self._http.get( 800 f"squid-api/v1/ai/knowledge-base/getGraphStatus/{self._kb_id}", params=params 801 )
Get the knowledge base's graph build/readiness status.
Arguments:
- include_topics: Whether to include the topic table (
topics,topicEdges). Default True; pass False to poll the build state without it.
Returns:
A
GetKnowledgeBaseGraphStatusResponsedict withenabled,entityCount,relationshipCount,contextsIndexed,contextsTotal, and, where available,facets,topics,structureStale, LLM usage fields, andbuildJob({'status': 'in_progress' | 'completed' | 'failed', ...}) for the most recent rebuild. Poll it afterrebuild_graph()untilbuildJobleaves'in_progress'.
803 async def get_file_status(self, path: str) -> dict: 804 """Look up the durable ingestion status of one file by path. 805 806 Args: 807 path: The file's path: ``folderPath/filename``, or just ``filename`` at the 808 upload root. 809 810 Returns: 811 An ``AiKnowledgeBaseFileStatusInfo`` dict: ``status`` is one of ``'completed'``, 812 ``'failed'`` (with ``errorMessage``/``errorCode``), ``'in_progress'``, or 813 ``'no_record'`` when the knowledge base has no trace of that path. 814 """ 815 return await self._http.get( 816 f"squid-api/v1/ai/knowledge-base/getFileStatus/{self._kb_id}", 817 params={"path": path}, 818 )
Look up the durable ingestion status of one file by path.
Arguments:
- path: The file's path:
folderPath/filename, or justfilenameat the upload root.
Returns:
An
AiKnowledgeBaseFileStatusInfodict:statusis one of'completed','failed'(witherrorMessage/errorCode),'in_progress', or'no_record'when the knowledge base has no trace of that path.
820 async def get_folder_status(self, folder_path: str, *, file_limit: int | None = None) -> dict: 821 """Search and aggregate the durable ingestion status of every file matching ``folder_path``. 822 823 Read three ways and unioned: a folder subtree (matched the same segment-safe way as 824 ``$underPath`` metadata filters), a bare filename anywhere in the knowledge base, and, 825 when it contains a ``/``, an exact ``folder_path/filename`` path. 826 827 Args: 828 folder_path: The folder subtree, bare filename, or exact file path to search for. 829 file_limit: Maximum number of files to return in ``files``, prioritizing failures. 830 Defaults to 50. 831 832 Returns: 833 An ``AiKnowledgeBaseFolderStatusResponse`` dict with ``counts`` (per-status totals), 834 ``totalFiles``, ``hasAnyRecords``, ``files`` (capped, failures first), and 835 ``truncated``. 836 """ 837 params = { 838 key: str(value) 839 for key, value in {"folderPath": folder_path, "fileLimit": file_limit}.items() 840 if value is not None 841 } 842 return await self._http.get( 843 f"squid-api/v1/ai/knowledge-base/getFolderStatus/{self._kb_id}", 844 params=params, 845 )
Search and aggregate the durable ingestion status of every file matching folder_path.
Read three ways and unioned: a folder subtree (matched the same segment-safe way as
$underPath metadata filters), a bare filename anywhere in the knowledge base, and,
when it contains a /, an exact folder_path/filename path.
Arguments:
- folder_path: The folder subtree, bare filename, or exact file path to search for.
- file_limit: Maximum number of files to return in
files, prioritizing failures. Defaults to 50.
Returns:
An
AiKnowledgeBaseFolderStatusResponsedict withcounts(per-status totals),totalFiles,hasAnyRecords,files(capped, failures first), andtruncated.
847 async def rebuild_graph( 848 self, 849 *, 850 mode: Literal["full", "structural"] | None = None, 851 ignore_active_bulk_jobs: bool | None = None, 852 ) -> None: 853 """Enqueue a graph rebuild/backfill. Requires ``graphRag.enabled``. 854 855 Only one rebuild can run per knowledge base at a time; track progress via 856 :meth:`get_graph_status`. A rebuild while a bulk-ingestion job on the knowledge base is 857 still active is refused (``GRAPH_REBUILD_BLOCKED_BY_BULK_JOB``). 858 859 Args: 860 mode: ``'structural'`` (the default) keeps the already-extracted entity graph and 861 rebuilds just the concept layer; ``'full'`` wipes the graph and re-extracts every 862 context with an LLM — expensive, and only needed when the extraction itself must 863 be redone (e.g. after changing ``entityTypes`` or ``extractionModel``). 864 ignore_active_bulk_jobs: start the rebuild even while a bulk-ingestion job is active. 865 For a wedged job only: the rebuild re-extracts what a live job is still merging. 866 """ 867 request: dict[str, Any] = {"knowledgeBaseId": self._kb_id} 868 if mode is not None: 869 request["mode"] = mode 870 if ignore_active_bulk_jobs is not None: 871 request["ignoreActiveBulkJobs"] = ignore_active_bulk_jobs 872 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(). A rebuild while a bulk-ingestion job on the knowledge base is
still active is refused (GRAPH_REBUILD_BLOCKED_BY_BULK_JOB).
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 changingentityTypesorextractionModel). - ignore_active_bulk_jobs: start the rebuild even while a bulk-ingestion job is active. For a wedged job only: the rebuild re-extracts what a live job is still merging.
874 async def query_graph( 875 self, 876 op: KnowledgeBaseGraphQueryOp, 877 *, 878 ref: str | None = None, 879 ref_b: str | None = None, 880 context_id: str | None = None, 881 query: str | None = None, 882 depth: int | None = None, 883 hops: int | None = None, 884 recursive: bool | None = None, 885 limit: int | None = None, 886 context_metadata_filter: dict[str, Any] | None = None, 887 ) -> dict: 888 """Query the knowledge base's graph (documents, entities, themes, facets). 889 890 Requires ``graphRag.enabled`` on the knowledge base. 891 892 Args: 893 op: The operation to run. 894 ref: Node ref (name, facet nodeId, or a topic or entity id from 895 :meth:`explore_graph`). Required by resolve/describe/subtree/docsUnder/ 896 neighborhood/pathBetween/relationship. 897 ref_b: Second node ref for ``pathBetween``, and the target entity for ``relationship``. 898 context_id: The document's contextId for ``conceptsOf``. 899 query: The free-text question for ``globalSummary``. 900 depth: ``subtree``: maximum depth below the resolved node. Default (and cap) 3. 901 hops: ``neighborhood``: expansion hops from the resolved entity. Default 1, max 2. 902 recursive: ``docsUnder``: when True (the default), include documents under the whole 903 subtree, not just the node itself. 904 limit: ``docsUnder`` and ``relationship``: maximum documents returned. Default 25, max 100. 905 context_metadata_filter: ``docsUnder`` and ``relationship``: keeps only the documents 906 whose context matches this metadata filter (context-record metadata only). 907 908 Returns: 909 A ``QueryKnowledgeBaseGraphResponse`` dict; which keys are present depends on ``op`` 910 (e.g. ``overview`` for 'overview', ``matches`` for 'resolve', ``node``/``path``/ 911 ``related`` for 'describe', ``tree``, ``documents``/``totalDocs``, ``concepts``, 912 ``graph``, ``pathBetween``, ``summaries``, ``relationship``). 913 """ 914 request: dict[str, Any] = {"knowledgeBaseId": self._kb_id, "op": op} 915 if ref is not None: 916 request["ref"] = ref 917 if ref_b is not None: 918 request["refB"] = ref_b 919 if context_id is not None: 920 request["contextId"] = context_id 921 if query is not None: 922 request["query"] = query 923 if depth is not None: 924 request["depth"] = depth 925 if hops is not None: 926 request["hops"] = hops 927 if recursive is not None: 928 request["recursive"] = recursive 929 if limit is not None: 930 request["limit"] = limit 931 if context_metadata_filter is not None: 932 request["contextMetadataFilter"] = context_metadata_filter 933 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, facet nodeId, or a topic or entity id from
explore_graph()). Required by resolve/describe/subtree/docsUnder/ neighborhood/pathBetween/relationship. - ref_b: Second node ref for
pathBetween, and the target entity forrelationship. - 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:
docsUnderandrelationship: maximum documents returned. Default 25, max 100. - context_metadata_filter:
docsUnderandrelationship: keeps only the documents whose context matches this metadata filter (context-record metadata only).
Returns:
A
QueryKnowledgeBaseGraphResponsedict; which keys are present depends onop(e.g.overviewfor 'overview',matchesfor 'resolve',node/path/relatedfor 'describe',tree,documents/totalDocs,concepts,graph,pathBetween,summaries,relationship).
935 async def explore_graph( 936 self, 937 *, 938 node_limit: int | None = None, 939 topic_id: str | None = None, 940 entity_id: str | None = None, 941 search: str | None = None, 942 context_metadata_filter: dict[str, Any] | None = None, 943 include_topics: bool | None = None, 944 ) -> dict: 945 """Get a bounded slice of the knowledge base's entity graph for exploration/visualization. 946 947 By default returns the highest-degree entities and the relationships among them. Requires 948 ``graphRag.enabled``. ``topic_id``, ``entity_id`` and ``search`` select other entity pools; 949 pass at most one of them. 950 951 Args: 952 node_limit: Hard cap on returned nodes. Default 200, max 1000. 953 topic_id: Restricts the subgraph to entities under the given topic node id. Ids come 954 from :meth:`get_graph_status`'s ``topics`` and churn on rebuild. 955 entity_id: Centers the subgraph on one entity: the entity plus its neighbors, strongest 956 relationships first. Ids come from the returned nodes and churn on rebuild. 957 search: Finds entities by name (exact, then prefix, then substring); when no name 958 matches, returns the entities nearest in meaning. 959 context_metadata_filter: Keeps only the entities mentioned by contexts matching this 960 metadata filter (context-record metadata only). 961 include_topics: Whether to attach the topic table (``topics``). Default True; pass 962 False when the caller already holds it. 963 964 Returns: 965 An ``ExploreKnowledgeBaseGraphResponse`` dict: ``nodes``, ``edges`` (the heaviest, 966 capped; ``edgesTruncated`` when cut), ``totalCount`` when counted, ``searchMatch`` for 967 a search, ``scopeTruncated`` when the filter matched too many contexts, and, once the 968 concept layer has been built, ``topics``. 969 """ 970 request: dict[str, Any] = {"knowledgeBaseId": self._kb_id} 971 if node_limit is not None: 972 request["nodeLimit"] = node_limit 973 if topic_id is not None: 974 request["topicId"] = topic_id 975 if entity_id is not None: 976 request["entityId"] = entity_id 977 if search is not None: 978 request["search"] = search 979 if context_metadata_filter is not None: 980 request["contextMetadataFilter"] = context_metadata_filter 981 if include_topics is not None: 982 request["includeTopics"] = include_topics 983 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.
By default returns the highest-degree entities and the relationships among them. Requires
graphRag.enabled. topic_id, entity_id and search select other entity pools;
pass at most one of them.
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()'stopicsand churn on rebuild. - entity_id: Centers the subgraph on one entity: the entity plus its neighbors, strongest relationships first. Ids come from the returned nodes and churn on rebuild.
- search: Finds entities by name (exact, then prefix, then substring); when no name matches, returns the entities nearest in meaning.
- context_metadata_filter: Keeps only the entities mentioned by contexts matching this metadata filter (context-record metadata only).
- include_topics: Whether to attach the topic table (
topics). Default True; pass False when the caller already holds it.
Returns:
An
ExploreKnowledgeBaseGraphResponsedict:nodes,edges(the heaviest, capped;edgesTruncatedwhen cut),totalCountwhen counted,searchMatchfor a search,scopeTruncatedwhen the filter matched too many contexts, and, once the concept layer has been built,topics.
758class KnowledgeBaseSearchOptions(TypedDict, total=False): 759 """Options for knowledge base search.""" 760 761 prompt: str 762 """The search prompt.""" 763 limit: int 764 """Max number of results to return.""" 765 chunkLimit: int 766 """How many chunks to search over (default 100).""" 767 rerankProvider: AiRerankProvider 768 """Reranker provider (default 'cohere').""" 769 rerankScoreThreshold: float 770 """Minimum reranker relevance score a chunk must reach to stay once at least 10 chunks are 771 already kept (default 0.2). Score ranges differ per reranker.""" 772 chatModel: AiChatModelSelection 773 """Model to use for answering.""" 774 searchMode: Literal["vector", "hybrid", "keyword", "graph"] 775 """Retrieval mode: 'hybrid' (BM25+dense fusion where supported; default on non-graph KBs), 776 'vector' (dense only), 'keyword' (pure lexical — every whitespace-separated term must appear 777 as a literal, case-insensitive substring), or 'graph' (GraphRAG — seeds entities via vector 778 search, expands relationships via graph traversal, maps entities back to their chunks, fused 779 with a hybrid search; requires a ``vectorDbType: 'mongoAtlas'`` KB with ``graphRag.enabled`` 780 and is the default there).""" 781 graphOptions: AiKnowledgeBaseGraphSearchOptions 782 """Tuning for ``searchMode: 'graph'``. Ignored for other search modes.""" 783 graphFilter: AiKnowledgeBaseGraphFilter 784 """Scopes the search to the documents under one concept of the KB's graph. Requires 785 ``graphRag.enabled``."""
Options for knowledge base search.
Minimum reranker relevance score a chunk must reach to stay once at least 10 chunks are already kept (default 0.2). Score ranges differ per reranker.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
893class MmCategory(TypedDict): 894 """Matchmaking category.""" 895 896 id: str 897 description: str
Matchmaking category.
900class MmEntity(TypedDict, total=False): 901 """Matchmaking entity.""" 902 903 id: str 904 content: str 905 categoryId: str 906 metadata: dict[str, Any]
Matchmaking entity.
909class MmFindMatchesOptions(TypedDict, total=False): 910 """Options for finding matches.""" 911 912 metadataFilter: dict[str, Any] 913 """AiContextMetadataFilter conditions.""" 914 limit: int 915 """Max matches to return (default 100, max 100).""" 916 matchToCategoryId: str 917 """Category to match against."""
Options for finding matches.
920class MmListEntitiesOptions(TypedDict, total=False): 921 """Options for listing entities.""" 922 923 metadataFilter: dict[str, Any] 924 limit: int
Options for listing entities.
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().
The integration ID if this model comes from an integration (OpenAI-compatible, Bedrock). Absent for Squid-provided models.
Short human-readable description of the model. Absent for custom integration models.
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!")
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}'.
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).
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).
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
AiClientinstance.
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")
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
WebClientinstance.
Example::
content = await squid.web().get_url_content("https://example.com")
results = await squid.web().ai_search("latest AI news")
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
MatchmakingClientinstance.
Example::
mm = squid.matchmaking()
await mm.create_match_maker("jobs", "Job matching", categories=[...])
matches = await mm.find_matches("jobs", "entity-1")
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
ExtractionClientinstance.
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"
)
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)
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"})
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"
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
AiQueryOptionscontrolling collection selection, query generation (includingallowClarification), result analysis (includingenableCodeInterpreter), memory, AI validation, per-stage model overrides viaaiOptions, and custom instructions. - response_format: Optional structured output format, e.g.,
{"type": "json_schema", "schema": {...}}.
Returns:
An
AiQueryResponsedict 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"])
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.
61class SquidHttpError(Exception): 62 """Raised when the Squid API returns an HTTP error response (status >= 400). 63 64 Attributes: 65 status_code: The HTTP status code. 66 url: The URL that was requested. 67 body: The parsed response body, if available. 68 """ 69 70 def __init__(self, status_code: int, message: str, url: str, body: Any = None): 71 self.status_code = status_code 72 self.url = url 73 self.body = body 74 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.
876class StableDiffusionOptions(TypedDict, total=False): 877 """Options for Stable Diffusion Core image generation.""" 878 879 modelName: Literal["stable-diffusion-core"] 880 aspectRatio: Literal["16:9", "1:1", "21:9", "2:3", "3:2", "4:5", "5:4", "9:16", "9:21"] 881 negativePrompt: str 882 seed: int 883 stylePreset: str 884 outputFormat: str
Options for Stable Diffusion Core image generation.
656class TextContextRequest(TypedDict, total=False): 657 """Request to upsert a text context.""" 658 659 contextId: str 660 type: Literal["text"] 661 title: str 662 text: str 663 format: Literal["auto", "markdown", "html", "plain"] 664 """Hint about the format of the text. Defaults to 'auto' (sniffed from content).""" 665 extractImages: bool 666 """Whether to extract images embedded in markdown/HTML text. Defaults to False. 667 668 This is the opposite of the file context default, which is True: a pasted blob's inline 669 images are usually layout chrome, while an uploaded document's images are part of its 670 content. 671 """ 672 imageMinSizePixels: int 673 imageExtractionModel: AiChatModelSelection 674 metadata: dict[str, Any] 675 options: AiContextTextOptions 676 scopes: list[str] 677 """Access scopes granting read access to this context. Only meaningful on a knowledge base 678 with ``accessControl.mode: 'enforced'``. Omitted on a re-ingest keeps existing scopes; an 679 empty list makes the context visible to every caller. 680 """
Request to upsert a text context.
Hint about the format of the text. Defaults to 'auto' (sniffed from content).
Whether to extract images embedded in markdown/HTML text. Defaults to False.
This is the opposite of the file context default, which is True: a pasted blob's inline images are usually layout chrome, while an uploaded document's images are part of its content.
455class UpsertAgentOptions(TypedDict, total=False): 456 """Options for creating/updating an agent.""" 457 458 description: str 459 """Description of the agent's purpose.""" 460 isPublic: bool 461 """Whether the agent is publicly accessible.""" 462 auditLog: bool 463 """Enable audit logging.""" 464 auditLogFullContext: bool 465 """Record the full agent context (system instructions and retrieved knowledge-base content) in the audit log.""" 466 apiKey: str 467 """API key for this agent.""" 468 mcpServer: AiAgentMcpServerConfig 469 """Optional configuration for exposing the agent as an MCP server.""" 470 options: AiChatOptions 471 """Default chat options."""
Options for creating/updating an agent.
994class WebAiSearchResponse(TypedDict): 995 """Response from AI web search.""" 996 997 markdownText: str 998 citedUrls: list[dict[str, str]] 999 """Pages the answer cites. A terse answer cites nothing even when the search ran.""" 1000 1001 consultedUrls: list[str] 1002 """Pages the search opened, whether or not the answer cites them."""
Response from AI web search.
16class WebClient: 17 """Web utilities: AI search, URL content, short URLs.""" 18 19 def __init__(self, http: HttpTransport) -> None: 20 self._http = http 21 22 async def ai_search( 23 self, query: str, allowed_domains: list[str] | None = None 24 ) -> WebAiSearchResponse: 25 """Perform an AI-powered web search. 26 27 When allowed_domains is provided, the search is restricted to those domains 28 (subdomains included) and every URL in the response -- cited or consulted -- 29 belongs to one of them. Squid enforces this over the consulted pages; 30 citations arrive already restricted. 31 32 Returns WebAiSearchResponse with 'markdownText', 'citedUrls' and 'consultedUrls'. 33 """ 34 body: dict[str, object] = {"query": query} 35 if allowed_domains is not None: 36 body["allowedDomains"] = allowed_domains 37 return await self._http.post("squid-api/v1/web/aiSearch", body) 38 39 async def get_url_content(self, url: str) -> str: 40 """Fetch and extract content from a URL as markdown.""" 41 result = await self._http.post("squid-api/v1/web/getUrlContent", {"url": url}) 42 if isinstance(result, dict): 43 return result.get("markdownText", "") 44 return str(result) if result else "" 45 46 async def create_short_url( 47 self, 48 url: str, 49 *, 50 seconds_to_live: int | None = None, 51 file_extension: str | None = None, 52 ) -> WebShortUrlResponse: 53 """Create a short URL. 54 55 Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'. 56 """ 57 body: dict = {"url": url} 58 if seconds_to_live is not None: 59 body["secondsToLive"] = seconds_to_live 60 if file_extension is not None: 61 body["fileExtension"] = file_extension 62 return await self._http.post("squid-api/v1/web/createShortUrl", body) 63 64 async def create_short_urls( 65 self, 66 urls: list[str], 67 *, 68 seconds_to_live: int | None = None, 69 file_extension: str | None = None, 70 ) -> WebShortUrlBulkResponse: 71 """Create multiple short URLs in bulk. 72 73 Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'. 74 """ 75 body: dict = {"urls": urls} 76 if seconds_to_live is not None: 77 body["secondsToLive"] = seconds_to_live 78 if file_extension is not None: 79 body["fileExtension"] = file_extension 80 return await self._http.post("squid-api/v1/web/createShortUrls", body) 81 82 async def delete_short_url(self, url_id: str) -> None: 83 """Delete a short URL.""" 84 await self._http.post("squid-api/v1/web/deleteShortUrl", {"id": url_id}) 85 86 async def delete_short_urls(self, url_ids: list[str]) -> None: 87 """Delete multiple short URLs.""" 88 await self._http.post("squid-api/v1/web/deleteShortUrls", {"ids": url_ids})
Web utilities: AI search, URL content, short URLs.
22 async def ai_search( 23 self, query: str, allowed_domains: list[str] | None = None 24 ) -> WebAiSearchResponse: 25 """Perform an AI-powered web search. 26 27 When allowed_domains is provided, the search is restricted to those domains 28 (subdomains included) and every URL in the response -- cited or consulted -- 29 belongs to one of them. Squid enforces this over the consulted pages; 30 citations arrive already restricted. 31 32 Returns WebAiSearchResponse with 'markdownText', 'citedUrls' and 'consultedUrls'. 33 """ 34 body: dict[str, object] = {"query": query} 35 if allowed_domains is not None: 36 body["allowedDomains"] = allowed_domains 37 return await self._http.post("squid-api/v1/web/aiSearch", body)
Perform an AI-powered web search.
When allowed_domains is provided, the search is restricted to those domains (subdomains included) and every URL in the response -- cited or consulted -- belongs to one of them. Squid enforces this over the consulted pages; citations arrive already restricted.
Returns WebAiSearchResponse with 'markdownText', 'citedUrls' and 'consultedUrls'.
39 async def get_url_content(self, url: str) -> str: 40 """Fetch and extract content from a URL as markdown.""" 41 result = await self._http.post("squid-api/v1/web/getUrlContent", {"url": url}) 42 if isinstance(result, dict): 43 return result.get("markdownText", "") 44 return str(result) if result else ""
Fetch and extract content from a URL as markdown.
46 async def create_short_url( 47 self, 48 url: str, 49 *, 50 seconds_to_live: int | None = None, 51 file_extension: str | None = None, 52 ) -> WebShortUrlResponse: 53 """Create a short URL. 54 55 Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'. 56 """ 57 body: dict = {"url": url} 58 if seconds_to_live is not None: 59 body["secondsToLive"] = seconds_to_live 60 if file_extension is not None: 61 body["fileExtension"] = file_extension 62 return await self._http.post("squid-api/v1/web/createShortUrl", body)
Create a short URL.
Returns WebShortUrlResponse with 'id', 'shortUrl', 'expiry'.
64 async def create_short_urls( 65 self, 66 urls: list[str], 67 *, 68 seconds_to_live: int | None = None, 69 file_extension: str | None = None, 70 ) -> WebShortUrlBulkResponse: 71 """Create multiple short URLs in bulk. 72 73 Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'. 74 """ 75 body: dict = {"urls": urls} 76 if seconds_to_live is not None: 77 body["secondsToLive"] = seconds_to_live 78 if file_extension is not None: 79 body["fileExtension"] = file_extension 80 return await self._http.post("squid-api/v1/web/createShortUrls", body)
Create multiple short URLs in bulk.
Returns WebShortUrlBulkResponse with 'ids', 'shortUrls', 'expiry'.
986class WebShortUrlBulkResponse(TypedDict): 987 """Response from creating bulk short URLs.""" 988 989 ids: list[str] 990 shortUrls: list[str] 991 expiry: str
Response from creating bulk short URLs.
978class WebShortUrlResponse(TypedDict): 979 """Response from creating a short URL.""" 980 981 id: str 982 shortUrl: str 983 expiry: str
Response from creating a short URL.