# Semantic Kernel code interpreter without Azure: a sandbox plugin Wrap Runtime's sandbox functions with `kernel_function` and put them in a `KernelPlugin`. A Semantic Kernel agent then runs code in a microVM. **On Runtime, a Semantic Kernel agent gets a code sandbox without an Azure subscription.** Semantic Kernel's built-in `SessionsPythonTool` runs Python in Azure Container Apps dynamic sessions. That requires a session pool, its management endpoint and role assignments before the first cell runs. A Runtime sandbox needs a `pip install` and one browser approval. It gives the agent a whole Firecracker microVM with a shell, not only Python cells. It costs $0.03125 an hour for 2 vCPU and 4 GiB while the model is thinking. semantic-kernel 1.45.0 was the current PyPI release on 25 October 2026. ## Built-in plugin or Runtime plugin | Question | `SessionsPythonTool` | Runtime plugin | | ----------------------- | ------------------------------------------------------------------ | ------------------------------------------------ | | Where code runs | An Azure Container Apps dynamic session | A Runtime Firecracker microVM | | Setup before first run | Resource group, session pool, pool endpoint, Session Executor role | `pip install withruntime` and a browser approval | | What the agent can do | Run Python code | Run any shell command, read, write, list files | | Credentials in your app | Azure identity (`DefaultAzureCredential` in Microsoft's tutorial) | A Runtime key, or the machine's saved connection | | State | The same session across calls from one tool instance | The same sandbox for the life of your block | The Azure column follows Microsoft's own tutorial for the Python SDK, updated 14 April 2026. That tutorial also advises a separate kernel and tool for each end user, so each user gets their own session. ## Build the plugin In Python, `kernel_function` marks a function for the kernel and reads its signature. Applied to the four Runtime functions, it produces a plugin. The agent can call the plugin's functions: ```bash no-run pip install semantic-kernel withruntime ``` ```python check from semantic_kernel.agents import ChatCompletionAgent from semantic_kernel.functions import KernelPlugin, kernel_function from withruntime import AsyncRuntime from withruntime.tools import sandbox_tools async def solve(service, task: str) -> str: async with AsyncRuntime() as runtime: async with await runtime.sandboxes.create(timeout_seconds=900, on_lease_end="stop") as sbx: plugin = KernelPlugin(name="runtime", functions=[kernel_function(f) for f in sandbox_tools(sbx)]) agent = ChatCompletionAgent( service=service, name="engineer", instructions="Use the runtime plugin to run code in a Linux sandbox. Check exit codes.", plugins=[plugin], ) response = await agent.get_response(messages=task) return str(response.content) ``` `service` is any chat completion service, for example `OpenAIChatCompletion(ai_model_id=...)` or `AzureChatCompletion()`. The sandbox is an `AsyncSandbox`, so the four functions are coroutines. They never block the event loop. The model sees them as `runtime-runtime_exec`, `runtime-runtime_read_file` and so on. Each name is the plugin name joined to the function name. This agent ran on 25 September 2026 against semantic-kernel 1.44.1, with a scripted OpenAI-style endpoint. The agent called `runtime_exec`, got the exit code and output, and answered from them. ## How many tool calls the agent may make A `ChatCompletionAgent` built this way uses automatic function calling. In 1.45.0, its default allows five automatic invocation rounds per response. For a longer task, such as install, run, fix and rerun, pass your own behavior: ```python check from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior behavior = FunctionChoiceBehavior.Auto(maximum_auto_invoke_attempts=15) # ChatCompletionAgent(..., function_choice_behavior=behavior) ``` ## Continue a conversation in the same sandbox `get_response` returns a thread. Pass that thread back, and the agent keeps the conversation. The sandbox keeps the files and installed packages: ```python check from semantic_kernel.agents import ChatCompletionAgent async def two_turns(agent: ChatCompletionAgent) -> str: first = await agent.get_response(messages="Write primes.py that prints primes under 100, then run it.") second = await agent.get_response(messages="Now make it take the limit as an argument.", thread=first.thread) return str(second.content) ``` Both turns work on `/workspace/primes.py` in the same machine. ## Security settings that hold even if the model is tricked Semantic Kernel filters can inspect a function call before it runs. That is a good place for policy. The sandbox adds limits that no prompt can get around, because the host enforces them outside the microVM: - `network={"internet": False}` on the create for pure computation, or an `allow` list of hosts for package installs. - `timeout_seconds` and `on_lease_end="stop"`, so an abandoned conversation does not keep a machine running. - `max_total_cost_micros`, which stops the sandbox once its total cost reaches the value you set. - A daily spending limit on the application's key. Past it, creates fail with `spending_limit_reached` and nothing is charged. - Runtime [secrets](/docs/security#secrets-sandboxes-never-see) for any token the code needs. The sandbox sees a placeholder. The real value is added only on requests to the named hosts. ## Which to use Choose `SessionsPythonTool` when the application already runs on Azure, uses Azure identity throughout, and Python cells are enough. Choose the Runtime plugin when the agent must work outside Azure, needs a shell, `pip`, `apt` or Docker (`sudo enable-docker`), or when the team wants billing by CPU used: $0.025 per vCPU-hour and $0.0075 per GiB-hour, with no plan fee ([pricing](/docs/pricing)). See also [a code interpreter for chatbots](/use-cases/code-interpreter-for-chatbots), [code interpreter](/glossary/code-interpreter) and the [framework guide](/docs/frameworks#any-other-framework). A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card: ```bash no-run printf '%s\n' 'print(sum([125, 250, 375]))' > invoice.py npx withruntime sandboxes run -- python3 - < invoice.py ``` ## Related - [LLM tool use in a sandbox](/use-cases/llm-tool-use-sandbox) - [AutoGen in a sandbox](/integrations/autogen) - [What is an agent loop?](/glossary/agent-loop) ## Sources - [Microsoft Learn: Use code interpreter sessions in Semantic Kernel with Azure Container Apps](https://learn.microsoft.com/en-us/azure/container-apps/sessions-tutorial-semantic-kernel), updated 14 April 2026, read 25 October 2026 - [Microsoft Learn: Provide native code to your agents](https://learn.microsoft.com/en-us/semantic-kernel/concepts/plugins/adding-native-plugins), read 25 October 2026 - [Microsoft Learn: The ChatCompletionAgent](https://learn.microsoft.com/en-us/semantic-kernel/frameworks/agent/agent-types/chat-completion-agent), read 25 October 2026 - [semantic-kernel on PyPI](https://pypi.org/project/semantic-kernel/), version 1.45.0; `KernelPlugin` and the default function choice behavior were read from that release's source on 25 October 2026 Facts on this page were checked on 25 October 2026.