Skip to main content
IllaSDK is the main SDK client. Use it when you want one object to manage chat sessions, tool-result loops, and async action polling.

Typical usage

import { IllaSDK } from '@illalabs/sdk'

const sdk = new IllaSDK({
  apiKey: process.env.ILLA_API_KEY!,
})

const result = await sdk.sendMessage(
  'Swap 1 ETH to USDC on Base',
  { userContext: { address: '0x1234...' } },
)

When to use IllaSDK

Use IllaSDK if your integration needs:
  • a high-level chat client
  • chat ID management
  • helper methods for returning tool results
  • polling utilities for long-running actions
If you need lower-level control over transport or context storage, use Chat, CoreApiProvider, and ContextManager directly.

Constructor

new IllaSDK(config, options?)
The constructor accepts API transport settings in config and context/cache customization in options.

config

apiKey
string
required
API key used as x-api-key for Core API requests.
baseURL
string
Optional Core API base URL override.
timeout
number
HTTP timeout in milliseconds.
headers
Record<string, string>
Extra headers merged into requests.
httpClientFactory
HttpClientFactory
Optional Axios client factory.
routes
CoreApiProviderRoutes
Optional route overrides (chat, actionStatus).

options

Provide either:
  • cache + optional contextManagerOptions, or
  • contextManager (custom implementation)

Property

chatIds: string[]

List of active chat IDs managed by the instance.

Core workflow

Most integrations use IllaSDK in this order:
  1. sendMessage(...) to start or continue a chat
  2. inspect response.data.pendingTools
  3. execute the returned tools in your app
  4. sendToolResults(...) to continue the loop
  5. use polling helpers if the action completes asynchronously

Core methods

sendMessage

sendMessage(
  msg: string | Prompt,
  context: { chatId: string } | { userContext: UserContext },
  chatOptions?: Omit<ChatOptions, 'userContext'>,
  options?: { signal?: AbortSignal; onRequestId?: (requestId: string) => void },
): Promise<SendMessageResult>
Starts or continues a chat turn. When creating a new chat via { userContext }, you can include signerWallet for smart-account flows where a separate EOA signs transactions/messages. This is the main entry point for non-streaming chat requests.

sendMessageStreaming

sendMessageStreaming(
  msg: string | Prompt,
  context: { chatId: string } | { userContext: UserContext },
  options?: SendMessageStreamingOptions,
  chatOptions?: Omit<ChatOptions, 'userContext'>,
): Promise<void>
Streams telemetry and final result via a single SSE request. Use this when you want streaming events and the final assistant response from a single request.

sendToolResult

sendToolResult(chatId: string, toolResult: IllaToolOutcomeJSON): Promise<SendMessageResult>
Sends one tool outcome.

sendToolResults

sendToolResults(chatId: string, toolResults: IllaToolOutcomeJSON[]): Promise<SendMessageResult>
Sends multiple tool outcomes in one request. Throws SdkEmptyToolsResultsError if toolResults is empty. The returned SendMessageResult can include:
  • Final assistant text (response.data.text)
  • Additional pendingTools (for multi-step tool loops)
Use sendToolResults for the common case. It reduces request overhead and keeps the tool loop explicit.

Chat and context methods

getMessages(chatId: string): Promise<MessageHistoryType>
appendMessages(chatId: string, messages: MessageHistoryType): Promise<void>
clearContext(chatId: string): Promise<void>
deleteChat(chatId: string): Promise<void>
createChat(options: ChatOptions, contextManager?: ContextManager): Chat
getChat(chatId: string): Chat
getChatIds(): string[]
Use these methods when you need direct access to stored conversation state or want to manage chat instances manually.

Polling methods

subscribeToToolStatus(
  params: { toolName: string; protocol: string; descriptor: BaseLongPollingArgs },
  callbacks: AsyncCheckerEvents,
  config?: Partial<PollingConfig>,
): EventSubscription
awaitAction(
  chatId: string,
  descriptor: { toolName: string; protocol: string; args: BaseLongPollingArgs },
): Promise<AwaitActionResult>
Polling config units are seconds. Use polling after you have already submitted a transaction or other long-running tool action and want status updates.

Utilities

getResponseMetadata(result: SendMessageResult): ResponseMetadata
static createNewContextManager(cache: ICache, options: ContextManagerOptions): ContextManager

Tool loop example

import { IllaSDK } from '@illalabs/sdk'
import { IllaToolError, IllaToolOutcome } from '@illalabs/interfaces'

const sdk = new IllaSDK({ apiKey: process.env.ILLA_API_KEY! })

const first = await sdk.sendMessage(
  'Swap 1 ETH to USDC on Base',
  {
    userContext: {
      address: '0x1234...',
      // Optional signer EOA for smart-account flows
      // signerWallet: '0x5678...'
    },
  },
)

if (first.response.isError) {
  throw new Error(first.response.error.message)
}

let pendingTools = [...(first.response.data.pendingTools ?? [])]

while (pendingTools.length > 0) {
  const outcomes = await Promise.all(
    pendingTools.map(async (tool) => {
      try {
        const executionResult = await executeTool(tool)
        return IllaToolOutcome.success(tool.toolCallId, tool.toolName, executionResult).toJSON()
      } catch (error) {
        return IllaToolOutcome.error(
          tool.toolCallId,
          tool.toolName,
          IllaToolError.execution(
            tool.toolCallId,
            tool.toolName,
            error instanceof Error ? error.message : 'Execution failed',
          ),
        ).toJSON()
      }
    }),
  )

  const followUp = await sdk.sendToolResults(first.chatId, outcomes)
  if (followUp.response.isError) {
    throw new Error(followUp.response.error.message)
  }

  pendingTools = [...(followUp.response.data.pendingTools ?? [])]
}