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