> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veadk.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Remote skills proxy

## Overview

Remote skills provide a declarative way to expose skills hosted in the AgentKit Skills Sandbox as individual tools on an agent. You describe each remote skill — its name, description, and input schema — in a JSON manifest, and VeADK generates a corresponding tool function for each one. When the agent calls a tool, the framework forwards the request to the remote sandbox through `invoke_skill` and `poll_skill`; the actual skill code runs only on the remote side and is never loaded or executed locally.

Remote skills are useful when you want to:

* Expose remote skills as standalone tools so the agent can invoke them by name with structured arguments;
* Control the timeout for each skill individually;
* Manage the skill list through a declarative manifest instead of writing tool functions one by one in code.

<Note>
  Remote skills reuse the sandbox infrastructure and credential configuration of `execute_skills`. Environment variables, Tool IDs, and other prerequisites are the same as those described on the [Code sandboxes](/productions/veadk/preview/en/components/tools/code-sandbox) page.
</Note>

## Prerequisites

Complete [skills sandbox setup](/productions/veadk/preview/en/components/tools/code-sandbox), ensure the target Skill Space contains executable skills, and save the JSON in [Manifest format](#manifest-format) as `remote-skills.json` in the current directory. A manifest only describes capabilities; it does not upload or deploy a skill. Names and inputs must match deployed remote skills.

Loading definitions and building tools do not contact the cloud. Calling the default executor requires a valid tool context, model, and sandbox configuration.

## Usage

Import path:

```python lines theme={null}
from veadk.tools.builtin_tools.remote_skills import (
    RemoteSkillDefinition,
    load_remote_skill_definitions,
    build_remote_skill_tools,
)
```

Steps:

1. Write a JSON manifest describing the remote skills to expose;
2. Call `load_remote_skill_definitions` to load the manifest into a list of `RemoteSkillDefinition`;
3. Call `build_remote_skill_tools` to convert the definitions into tool functions;
4. Pass the tool functions to the `Agent` `tools` parameter.

```python title="remote_skills_agent.py" lines theme={null}
import asyncio

from veadk import Agent, Runner
from veadk.memory.short_term_memory import ShortTermMemory
from veadk.tools.builtin_tools.remote_skills import (
    load_remote_skill_definitions,
    build_remote_skill_tools,
)

definitions = load_remote_skill_definitions("remote-skills.json")
tools = build_remote_skill_tools(definitions)

agent = Agent(
    name="remote_skill_agent",
    instruction="Call the appropriate remote skill for the user's request.",
    skills=["space:your-skill-space-id"],
    skills_mode="skills_sandbox",
    tools=tools,
)
runner = Runner(agent=agent, short_term_memory=ShortTermMemory())


async def main():
    response = await runner.run("Write a technical report")
    print(response)


if __name__ == "__main__":
    asyncio.run(main())
```

You can also pass a JSON string directly instead of a file path:

```python lines theme={null}
definitions = load_remote_skill_definitions(
    '{"remote_skills": [{"name": "report_writer", "description": "Generate a technical report", "input_schema": {"type": "object"}}]}'
)
tools = build_remote_skill_tools(definitions)
```

## Manifest format

The manifest is a JSON object containing a `remote_skills` array. Each element describes one remote skill:

```json title="remote-skills.json" lines theme={null}
{
  "remote_skills": [
    {
      "name": "report_writer",
      "description": "Write a technical report from the given parameters",
      "input_schema": {
        "type": "object",
        "properties": {
          "format": {
            "type": "string",
            "enum": ["doc", "pdf"],
            "description": "Output format"
          }
        },
        "required": ["format"]
      },
      "display_name": "Report writer",
      "timeout": 600
    }
  ]
}
```

### Skill fields

| Field | Type | Default | Description |
| :- | :- | :- | :- |
| `name` | `str` | — | Skill name, used as the generated tool function name. Must be unique. |
| `description` | `str` | — | Skill description, included in the tool's docstring so the model can decide when to call it. |
| `input_schema` | `dict` | — | JSON Schema describing the structure of `arguments`. |
| `display_name` | `str` | `None` | Optional display name. |
| `timeout` | `int` | `1800` | Execution timeout for the skill, in seconds. Must be between 1 and 1800. |
| `timeout_seconds` | `int` | `1800` | Alias for `timeout`; when both are present, `timeout` takes precedence. |

<Warning>
  `name` and `description` must be non-empty strings, and `input_schema` must be a JSON object; otherwise loading raises an error. `timeout` (or `timeout_seconds`) must be between 1 and 1800. Duplicate `name` values are not allowed in the same manifest.
</Warning>

## Generated tool function

`build_remote_skill_tools` generates one tool function per `RemoteSkillDefinition`. The function name is taken from the skill's `name`, and the docstring contains the description and input schema. The generated tool function signature is:

```python lines theme={null}
def remote_skill(
    query: str,
    arguments: dict[str, Any] | None = None,
    tool_context: ToolContext | None = None,
) -> str:
    ...
```

| Parameter | Type | Default | Description |
| :- | :- | :- | :- |
| `query` | `str` | — | The query instruction passed to the remote skill. |
| `arguments` | `dict[str, Any] \| None` | `None` | Skill input arguments, which must conform to the `input_schema` declared in the manifest. |
| `tool_context` | `ToolContext \| None` | `None` | Tool runtime context, injected automatically by VeADK; required at call time. |

When the tool runs, the framework assembles `skill_name`, `query`, `arguments`, and an auto-generated `request_id` into a query input, sends it to the remote sandbox through `invoke_skill` and `poll_skill`, and enforces the timeout configured on the skill definition.

<Note>
  `tool_context` is marked optional in the signature but is required at call time; omitting it raises an error. VeADK injects it automatically during agent execution — you do not need to pass it manually.
</Note>

## API

### RemoteSkillDefinition

`RemoteSkillDefinition` is the runtime definition of a skill, holding its name, description, input schema, and timeout configuration.

| Attribute | Type | Default | Description |
| :- | :- | :- | :- |
| `name` | `str` | — | Skill name. |
| `description` | `str` | — | Skill description. |
| `input_schema` | `dict[str, Any]` | — | JSON Schema for the input arguments. |
| `display_name` | `str \| None` | `None` | Display name. |
| `timeout` | `int` | `1800` | Execution timeout in seconds. |

### load\_remote\_skill\_definitions

```python lines theme={null}
def load_remote_skill_definitions(
    value: str | os.PathLike[str],
) -> list[RemoteSkillDefinition]:
    ...
```

| Parameter | Type | Default | Description |
| :- | :- | :- | :- |
| `value` | `str \| os.PathLike[str]` | — | A JSON string or a path to a local manifest file. |

Returns a list of `RemoteSkillDefinition`. When the value starts with `{`, it is parsed as a JSON string; otherwise it is read as a file path.

### build\_remote\_skill\_tools

```python lines theme={null}
def build_remote_skill_tools(
    definitions: list[RemoteSkillDefinition],
    *,
    executor: Callable[..., str] = execute_remote_skill,
) -> list[Callable[..., str]]:
    ...
```

| Parameter | Type | Default | Description |
| :- | :- | :- | :- |
| `definitions` | `list[RemoteSkillDefinition]` | — | Skill definitions. |
| `executor` | `Callable[..., str]` | `execute_remote_skill` | Executor function, defaulting to `execute_remote_skill`; typically left unchanged. |

Returns a list of tool functions that can be passed directly to the `Agent` `tools` parameter.

## Input validation and custom executors

`input_schema` is included in the tool description for the model; the current proxy does not automatically perform full JSON Schema validation before execution. Enforce required fields, enums, and business constraints in the application or remote skill. The manifest loader checks names, descriptions, object structure, and duplicate names. Direct construction of `RemoteSkillDefinition` does not imply those loader checks ran.

The default `execute_remote_skill` executor calls `invoke_skill`, then polls with `poll_skill`, returning text only after completion. Input-required or authentication-required states end the current wait with an error. A timeout does not guarantee the remote task was canceled.

A custom executor accepts workflow text plus `tool_context` and `timeout` keyword arguments, and returns a string. This example prepares an executor that inspects serialized input without executing a remote skill:

```python lines theme={null}
import json
from veadk.tools.builtin_tools.remote_skills import load_remote_skill_definitions, build_remote_skill_tools


def preview_executor(workflow_prompt, *, tool_context, timeout):
    payload = json.loads(workflow_prompt)
    return json.dumps({"skill": payload["skill_name"], "arguments": payload["arguments"], "timeout": timeout})


definitions = load_remote_skill_definitions('{"remote_skills":[{"name":"report_writer","description":"Write a report","input_schema":{"type":"object"}}]}')
functions = build_remote_skill_tools(definitions, executor=preview_executor)
print([function.__name__ for function in functions])
print(preview_executor(
    json.dumps({"skill_name": "report_writer", "arguments": {"format": "pdf"}}),
    tool_context=None, timeout=600,
))
```

Register `functions` using `Agent(tools=functions)` to use the custom executor in an agent; the runtime injects context. The example builds tools and directly checks the custom executor input and output, without calling a model or sandbox.
