Internal Tools

Built-in tools for planning, memory, widgets, and sub-agent completion.


Overview

Most internal tool categories are on when you omit them from internal_tools. Five categories (meta, artifact, agent, remote, knowledge) are opt-in and stay off until you enable them. Configure categories with internalTools:

1from inferencesh import inference, internal_tools23client = inference(api_key="inf_...")4agent = client.agent({5    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },6    "internal_tools": internal_tools()7        .plan(True)8        .memory(True)9        .widget(True)10        .build()11})

Default behavior

When a category flag is omitted from internal_tools, the runtime applies a built-in default:

Categoryinternal_tools flagDefault when unset
Planplanon
Memorymemoryon
Widgetwidgeton
Finishfinishon
Skillsskillson
Metametaoff (opt-in)
Artifactsartifactoff (opt-in)
Agentagentoff (opt-in)
Remotesremoteoff (opt-in)
Knowledgeknowledgeoff (opt-in)

An explicit true or false always wins over the default. An unset flag is not the same as false. For example, {"finish": false, "meta": false} disables finish and meta tools, but plan, memory, widget, and skills stay enabled because their flags were never set.

Agent editors and UIs should call GET /agents/internal-tools (JavaScript SDK: client.agents.getInternalTools()). Each definition includes default_enabled, which matches this table. Render capability switches from that field.

Tool names

A tool you define on an agent cannot share a name with a built-in tool that the agent has turned on. Saving such a version fails with an error naming the internal_tools flag; rename your tool or turn that category off. A built-in whose category is off leaves its name free, so a tool named agent is fine on an agent that does not enable the agent category. If an older saved version still carries a clashing tool, the runtime leaves out that one tool, logs a warning, and keeps the rest.


Available Internal Tools

CategoryToolsScope
Planplan_create, plan_update, plan_loadAll agents
Memorymemory_set, memory_get, memory_getallAll agents
WidgetwidgetTop-level only
FinishfinishAll agents
Skillsskill_getAll agents
Metasearch_tools, list_tools, execute_toolAll agents (opt-in)
Artifactsartifact_guidance, artifact_publish, artifact_get, artifact_list, artifact_comments, artifact_reply, artifact_resolveAll agents (opt-in)
AgentagentAll agents below the delegation depth limit (opt-in)
Remotesremote_list, remote_execAll agents (opt-in)
Knowledgeknowledge_search, knowledge_get, knowledge_saveAll agents (opt-in)

Meta tools

Enable with meta: true in internal_tools. Meta tools are opt-in.

Use meta tools when an agent needs access to many platform resources without listing every app tool, agent tool, or knowledge ref in its config. Three tools cover the catalog of apps, agents, flows, skills, and knowledge. Every entry is addressed as namespace/name.

ToolParametersPurpose
search_toolsquery, optional kindSearch the platform catalog by keyword
list_toolsnames, optional kindDescribe matches with full argument schemas
execute_toolname, arguments, optional kindRun an app (as a task) or delegate to an agent

Catalog kinds: every match carries a source field that says what it is.

sourceWhat it isRunnable via execute_tool?
appA platform app (possibly multi-function)Yes. Runs as a task
agentAn agent you can delegate toYes. Same call shape as a configured agent tool (task, context, optional images)
flowA saved multi-step pipelineNo. list_tools describes it; execute_tool returns an error
skillRegistry or workspace skill (instructions to follow)No. list_tools returns the content inline
knowledgeStored reference materialNo. list_tools returns the content inline

Pass the source value as kind on list_tools and execute_tool. Without kind, the runtime tries each kind in turn, and can describe or run the wrong thing when a name exists in more than one kind.

kind on search_tools narrows the search to one kind (app, agent, flow, skill, or knowledge). Omit it to search everything. An unknown kind returns an error.

Catalog scope: search uses the same visibility as the rest of the platform: your workspace's resources plus public resources your credentials can read. Private resources owned by other workspaces do not appear. The search_tools description states how many apps the catalog holds.

search_tools query matching: catalog search uses the platform's hybrid keyword and semantic search, the same index behind /search. Queries are passed verbatim, so describe the capability in a few words. Results are ranked by relevance, with a per-kind cap so one kind cannot fill the list.

search_tools response:

FieldMeaning
matchesArray of { name, description, source } entries
totalNumber of matches returned (the length of matches)
queryEcho of the search term
kindEcho of the filter. Present only when kind was passed

A multi-function app appears once in search results. Call list_tools on it to see its functions and schemas.

list_tools response: call this before execute_tool for apps and agents, because search results do not include argument schemas.

FieldMeaning
toolsArray of { name, description, source, input_schema? } entries
totalNumber of entries returned
  • For multi-function apps, the response has one entry per function, each with its own input_schema. The default function is listed first and keeps the bare namespace/name ref. Other functions are named namespace/name:function. If names already includes a function ref (for example google/gmail:send_message), only that function is returned.
  • For agents, list_tools returns the sub-agent call schema (task, context, images), which is what execute_tool expects. It does not return the agent's configuration.
  • For skills and knowledge, list_tools returns the content in description.

Typical flow (app):

code
1Agent: [calls search_tools(query="gmail")]2> matches: { name: "google/gmail", source: "app", description: "..." }34Agent: [calls list_tools(names=["google/gmail"], kind="app")]5> google/gmail: input_schema { q: string }6> google/gmail:list_messages: input_schema { max_results: integer }7> google/gmail:send_message: input_schema { to: string }89Agent: [calls execute_tool(name="google/gmail:send_message", kind="app", arguments={ to: "..." })]10> task output

Typical flow (agent delegation):

code
1Agent: [calls search_tools(query="code review", kind="agent")]2> matches: { name: "acme/reviewer", source: "agent", description: "..." }34Agent: [calls list_tools(names=["acme/reviewer"], kind="agent")]5> acme/reviewer: input_schema { task, context, images }67Agent: [calls execute_tool(name="acme/reviewer", kind="agent", arguments={ task: "Review the diff", context: "..." })]8> sub-agent result

execute_tool resolves name in this order:

  1. Tools already declared on the agent config
  2. The platform catalog by ref. Apps run as tasks. Agents delegate through the same path as configured sub-agents, with the same depth and fan-out limits

Meta tools are added alongside your configured tools. They do not remove tools you declare explicitly.

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "system_prompt": "Discover and run platform apps as needed.",4    "internal_tools": {"meta": True},5})

Host context tools (deprecated)

Host context is disabled. internal_tools.host_context is accepted and ignored, and no agent is offered get_host_context or send_to_host. These tools ran in the browser, and only the hosted embed page answered them, so on any other surface the call never completed and the chat stalled. A replacement for passing host page context to embedded agents is planned.


Artifact tools

Enable with artifact: true in internal_tools. Artifact tools are opt-in.

Agents use these tools to publish small self-contained HTML or Markdown pages to a shareable URL that updates in place, and to answer the comment threads people leave on them:

ToolPurpose
artifact_guidanceReturn the page contract and the skills that carry the detail. Meant to be called before writing a page
artifact_publishCreate an artifact, or update one in place by artifact_id or name. Returns the artifact id, URL, and version
artifact_getRead an artifact's metadata (title, URL, version, visibility) and page source
artifact_listList artifacts the user owns or that were shared with them, newest first, with optional search
artifact_commentsRead the comment threads on an artifact. Each thread says whether it was sent to the agent
artifact_replyReply into one comment thread. Only works on a thread that was sent to the agent
artifact_resolveMark a comment thread resolved. Only works on a thread that was sent to the agent
artifact_asset_uploadStore a file beside an artifact and return the URL its page loads it by. Takes file_url: a file on inference.sh the credential can read, such as an app tool's output. Up to 25 MiB
artifact_asset_listList the files stored beside an artifact and what it uses against its budget
artifact_asset_deletePermanently delete one stored file

A page loads stored files only when it was published with the assets capability.

Enabling artifact tools also offers the artifact guidance skills through skill_get, even when the agent has no skills of its own.

See Publishing artifacts for publishing, visibility, and sharing outside the agent runtime.

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "internal_tools": {"artifact": True},4})

Agent tool

Enable with agent: true in internal_tools. The agent tool is opt-in. It was called spawn before; internal_tools.spawn is still read as agent.

The agent tool runs a copy of the calling agent on a self-contained side task. The copy has the same version, system prompt, and tools, but a fresh context with none of the parent conversation. Use it to keep a long side task, such as reading many files or trying an approach that may not work, out of the parent's context window.

ParameterRequiredDescription
taskYesWhat the copy should do and what to report back, stated so it stands on its own
contextNoEverything the copy needs that it cannot see: findings so far, constraints, file paths, identifiers
imagesNoImage URLs to pass along

The copy cannot ask the parent follow-up questions, so include everything it needs in task and context. It returns its result through the same path as a configured sub-agent.

Depth limit: a chat a person starts is depth 0, and each delegation adds one. The agent tool is offered at any depth below 3, so a copy can start another copy until the chain reaches depth 3. An agent at depth 3 gets neither agent nor its configured agent tools, and a delegation call at that depth returns an error. Configured sub-agents and spawned copies share this limit.

Fan-out limit: a chat can have at most 2 delegated sub-chats running at once, counting both spawned copies and configured sub-agents. A further call returns an error until one of them reports back.

Agent tool vs configured sub-agents: configured sub-agents are separate agents you add as agent-type tools, which is useful when you need a different system prompt or tool set. The agent tool reuses the current agent without a second agent definition. Both can be enabled on the same agent.

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "internal_tools": {"agent": True},4})

Remote tools

Enable with remote: true in internal_tools. Remote tools are opt-in.

Use remote tools when an agent should run shell commands on machines the user connected with belt remote. The same exec-run path backs these tools as belt remote exec and POST /remotes/{id}/execs. Runs started from the agent loop are recorded with requested_by=loop and tied to the active agent run.

Enabling the category is necessary but not sufficient: the remote daemon must be connected and started with --exec, and the credential running the agent needs the same scopes as the REST routes (remotes:read to list, remotes:write to dispatch execs).

ToolParametersPurpose
remote_listnoneList remotes (id, name, status, OS, exec_enabled)
remote_execremote, command; optional description, cwd, timeout_secondsRun a shell line on a remote

Choosing a remote: pass the id from remote_list, or a display name (case-insensitive). If the name is ambiguous, use the id.

Command shape: remote_exec runs the line through sh -c on Unix (cmd /C on Windows), so pipes, &&, and redirects work as in a normal shell.

Approval card: Pass description, a one-line summary of what the command does and why (for example Install dependencies before building). It is stored in the tool arguments, never sent to the shell, and shown above the command when the call pauses for approval.

How the turn waits: remote_exec behaves like an app tool. The runtime dispatches the exec run, leaves the tool invocation in progress, and returns. The turn continues when the run reaches a terminal status; the completed invocation includes JSON with exec_run_id, status, optional exit_code, and the last 30,000 characters of each of stdout and stderr (tails are kept so errors near the end are not dropped). Non-zero exits, timeouts, kills, and disconnects are reported in that result — they complete the tool call with information for the model, not a separate tool failure.

Approvals: With no matching chat or governance rule, remote_exec asks before dispatch. Add an allow rule on the chat, or test a command against the rules, with Chat permissions rules (RemoteExec kind). Rules and always-allow options can target specific commands in a compound line (for example git clone:*) instead of the whole remote; commands the policy engine cannot fully analyse ask for approval.

Timeouts: timeout_seconds kills the remote command after that many seconds (default 600).

Trace: Each in-chat remote_exec gets an execution graph node (like an app tool's task). Use GET /chats/:id/trace or the workspace chat trace to see the run (resource_type exec_run, label such as exec on my-laptop) while it is in progress.

Stopping a chat: Stopping the chat sweeps running execution graph nodes. An in-flight exec run is signaled the same way as a running app task, so remote commands do not keep running in the background after you stop.

Disconnected remote: If the remote drops before the command finishes, the exec run fails with a clear error (remote disconnected before the command finished) so the turn cannot hang on a laptop that went offline.

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "internal_tools": {"remote": True},4})

→ Remotes guide · Remotes API · Exec runs API


Knowledge tools

Enable with knowledge: true in internal_tools. Knowledge tools are opt-in.

Use knowledge tools when an agent should find, load, or record skills and knowledge entries in the user's registry: the same entries as belt knowledge, belt skill, and the MCP knowledge_* / skill_* tools. skill_get only serves the skills configured on the agent; knowledge tools reach any entry the credential can see. The credential running the agent needs knowledge:read to search and load, and knowledge:write to save.

ToolArgumentsDescription
knowledge_searchoptional query, source, type, limitSearch entries (or list the most recent when query is omitted). source: "store" searches the public store of approved skills instead of the user's own. Returns ref, type, description
knowledge_getref; optional pathLoad an entry's content and the paths of its supporting files, or one supporting file with path
knowledge_savename, content; optional type, description, allowed_tools, filesCreate an entry in the team's namespace. Saving under an existing name adds a new version; identical content is a no-op
knowledge_deleterefPermanently delete one of the user's entries with all its versions. Needs knowledge:write

type is one of skill, concept, observation (default), preference, reference, person, project. files and allowed_tools apply to skills only.

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "internal_tools": {"knowledge": True},4})

Plan Tools

Help agents organize multi-step tasks:

plan_create

Create a new plan with steps:

code
1Agent creates: ["Research topic", "Write outline", "Draft content"]

plan_update

Update step status (pending, in_progress, completed, failed):

code
1Agent marks step 1 as completed

plan_load

Load the current plan to see progress.

Example conversation:

code
1User: "Write me a blog post about AI"23Agent: [calls plan_create with steps]4> Plan created:5> [ ] Research AI trends6> [ ] Create outline  7> [ ] Write draft8> [ ] Review and polish910Agent: [calls plan_update to mark step 1 in progress]11> Plan updated:12> [/] Research AI trends ← in progress13> [ ] Create outline14> ...

Memory Tools

Scratch key-value notes for this chat only. Values persist across turns of the chat, and only this chat sees them. Use memory for working state during a task (intermediate results, IDs to reuse on the next turn). Lasting facts, preferences, and reference material belong in the Knowledge tools registry, not memory.

memory_set

Save a scratch note under a key for this chat:

code
1Agent calls: memory_set(key="browser_session", value="sess_abc123")

memory_get

Read the scratch note saved under a key:

code
1Agent calls: memory_get(key="browser_session")2Returns: "sess_abc123"

memory_getall

Read every scratch note in this chat:

code
1Returns: {"browser_session": "sess_abc123", "draft_outline": "..."}

Good fits:

  • Intermediate results while a multi-step task runs in one chat
  • Session IDs or partial outputs to carry to the next turn

Use knowledge instead when:

  • The agent should remember something in a later chat (user preferences, project facts, saved procedures)

Widget Tool

Render interactive UI elements (top-level agents only):

widget

Create UI components:

  • Forms with inputs
  • Buttons and actions
  • Cards and layouts
  • Status displays

Example widget call:

json
1{2  "type": "ui",3  "title": "Order Confirmation",4  "children": [5    {"type": "text", "value": "Your order is ready"},6    {"type": "badge", "label": "confirmed", "variant": "secondary"},7    {"type": "row", "children": [8      {"type": "button", "label": "Track Order", "action": "track"},9      {"type": "button", "label": "Cancel", "action": "cancel", "variant": "destructive"}10    ]}11  ]12}

See the Widget System documentation for full component reference.


Finish Tool

Report completion with structured output. Works on all agents. When called, the output is stored on chat.output.

finish

Report status and result:

json
1{2  "status": "succeeded",  // or "failed", "cancelled"3  "result": "Research complete. Found 5 key trends..."4}

The finish output is stored on the chat and accessible after completion. Use run() to get it directly:

1output = agent.run("Research AI trends")2print(output)  # {"status": "succeeded", "result": "Research complete. Found 5 key trends..."}

With output_schema for structured output:

When output_schema is set on the agent config, the finish tool requires the result to match the schema. This gives you typed, predictable JSON output from your agent. See Structured Output for details.

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "system_prompt": "Analyze the input text.",4    "output_schema": {5        "type": "object",6        "properties": {7            "summary": {"type": "string", "description": "Brief summary"},8            "confidence": {"type": "number", "description": "Confidence 0-1"}9        },10        "required": ["summary", "confidence"]11    },12    "internal_tools": { "finish": True }13})1415output = agent.run("The weather is great today!")16print(output)  # {"summary": "Positive weather comment", "confidence": 0.95}

SDK builders

Use internalTools() / internal_tools() to build the internal_tools object on ad-hoc agents. The runtime also accepts a plain JSON object (REST and YAML agent configs).

JavaScript (@inferencesh/sdk): chain methods on internalTools():

MethodSets
.plan(), .memory(), .widget(), .finish(), .skills()Default-on categories
.meta()Meta tools (opt-in; available since v0.6.42)
.artifact(), .agent(), .remote(), .knowledge()Opt-in categories (v0.14.1+; use a plain object on older SDKs)
.all()Enables plan, memory, widget, and finish only (not opt-in categories)
.none()Disables plan, memory, widget, and finish

v0.14.1 also removed internalTools().hostContext() (the API ignores host_context). The serialized field is agent, not spawn. Older stored configs may still use "spawn": true; the API treats it as agent.

Python (inferencesh v0.14.1+): chain methods on internal_tools() (same categories as JavaScript):

MethodSets
.plan(), .memory(), .widget(), .finish(), .skills()Default-on categories
.meta(), .artifact(), .agent(), .remote(), .knowledge()Opt-in categories
.all()Enables plan, memory, widget, and finish only (not opt-in categories)
.none()Disables plan, memory, widget, and finish

InternalToolsConfig in inferencesh.types uses agent (not spawn) and includes optional knowledge. On older Python SDKs, set opt-in flags with a plain dict: {**internal_tools().memory().build(), "knowledge": True, "agent": True}.

→ JavaScript SDK — Tool Builder · Python SDK — Tool Builder


Configuration Examples

1# Disable all internal tools2internal_tools().none().build()34# Enable only memory5internal_tools().plan(False).memory(True).widget(False).build()67# Enable plan, memory, widget, and finish (does not set the opt-in categories)8internal_tools().all().build()910# Opt-in categories: set the flags in the agent config11"internal_tools": {"meta": True, "artifact": True, "agent": True, "remote": True, "knowledge": True}

Skills Tool

Load skill content on-demand instead of embedding everything in the system prompt.

Overview

Skills are reusable packages of instructions and context that agents can retrieve when needed. This follows the progressive disclosure pattern—agents see available skills in the tool description and load full content only when required.

skill_get

Retrieve a skill's full content:

code
1Agent calls: skill_get(skill="code-review")2Returns: "# Code Review Guidelines\n\nWhen reviewing code..."

Defining Skills

Skills are defined in the agent config, not in internal_tools:

1agent = client.agent({2    "core_app": { "ref": "infsh/claude-sonnet-4@latest" },3    "system_prompt": "You are a helpful assistant.",4    "skills": [5        {6            "name": "code-review",7            "description": "Guidelines for reviewing pull requests",8            "content": "# Code Review\n\nWhen reviewing code, check for..."9        },10        {11            "name": "api-docs",12            "description": "API documentation for the project",13            "url": "https://example.com/skills/api-docs.md"14        }15    ]16})

Skill Sources

SourceDescription
contentInline text/markdown content
urlURL to fetch skill content from (cached per session)

How the Agent Sees Skills

The skill_get tool description includes all available skills:

code
1skill_get: Retrieves the full content of a skill.23Available skills:4- code-review: Guidelines for reviewing pull requests5- api-docs: API documentation for the project67Parameters:8- skill: The name of the skill to retrieve

Example Conversation

code
1User: "Review this pull request"23Agent: [calls skill_get(skill="code-review")]4> # Code Review Guidelines5> When reviewing code, check for:6> 1. Security vulnerabilities7> 2. Performance issues8> ...910Agent: "Based on the code review guidelines, here's my review..."

Use cases:

  • Documentation and guidelines
  • Domain-specific knowledge
  • Multi-step procedures
  • Context that's only needed sometimes

Scope Rules

Tool CategoryTop-level AgentSub-agent
Plan✓✓
Memory✓✓
Widget✓✗
Finish✓✓
Skills✓✓
Meta✓✓
Artifacts✓✓
Agent✓✓ (below depth 3)

we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.