A3S Docs
A3S CodeExamples

Direct Tools

Run deterministic host tools without spending an LLM turn

Direct Tools

session.tool(name, args) (and the typed helpers like glob, grep, readFile) run a host tool directly, with no model call in the loop. Use them for tests, migrations, and host-driven workflows where you want deterministic results instead of an agent turn.

Direct calls are host control-plane calls. Apply your own product authorization before invoking them; permissionPolicy gates model-selected tool calls inside an agent turn, not whether your application code is allowed to call an SDK helper.

import { Agent } from '@a3s-lab/code';

const agent = await Agent.create('agent.acl');
const session = agent.session('.');

const allowedDirectTools = new Set(['glob', 'grep', 'read', 'generate_object']);
function assertDirectToolAllowed(name: string) {
  if (!allowedDirectTools.has(name)) {
    throw new Error(`direct tool not allowed here: ${name}`);
  }
}

// Glob: list files by pattern
assertDirectToolAllowed('glob');
const files = await session.glob('**/*.ts');
console.log(`glob found ${files.length} TypeScript files`);

// Grep: search file contents
assertDirectToolAllowed('grep');
const matches = await session.grep('Agent.create');
const matchCount = matches.split('\n').filter(Boolean).length;
console.log(`grep found ${matchCount} matching lines`);

// Read a file
assertDirectToolAllowed('read');
const readme = await session.readFile('README.md');
console.log(`README is ${readme.length} bytes`);

// Direct tool call by name
assertDirectToolAllowed('read');
const raw = await session.tool('read', { file_path: 'package.json' });
console.log(`package.json via tool(): ${raw.output.length} bytes`);

// Inspect available tool schemas
const schemas = session.toolDefinitions();
console.log(`session exposes ${schemas.length} tools`);

// Structured output: generate a schema-validated JSON object
assertDirectToolAllowed('generate_object');
const structured = await session.tool('generate_object', {
  schema: {
    type: 'object',
    required: ['count', 'language'],
    properties: {
      count: { type: 'integer' },
      language: { type: 'string' },
    },
  },
  prompt: 'How many TypeScript files are in this project?',
  schema_name: 'file_stats',
});
if (structured.exitCode !== 0) {
  throw new Error(structured.output);
}
console.log('structured output:', JSON.parse(structured.output).object);

session.close();
import json

from a3s_code import Agent

agent = Agent.create("agent.acl")
session = agent.session('.')

ALLOWED_DIRECT_TOOLS = {'glob', 'grep', 'read', 'generate_object'}


def assert_direct_tool_allowed(name: str) -> None:
    if name not in ALLOWED_DIRECT_TOOLS:
        raise RuntimeError(f'direct tool not allowed here: {name}')

# Glob: list files by pattern
assert_direct_tool_allowed('glob')
files = session.glob('**/*.py')
print(f'glob found {len(files)} Python files')

# Grep: search file contents
assert_direct_tool_allowed('grep')
matches = session.grep('Agent.create')
match_count = len([line for line in matches.splitlines() if line])
print(f'grep found {match_count} matching lines')

# Read a file
assert_direct_tool_allowed('read')
readme = session.read_file('README.md')
print(f'README is {len(readme)} bytes')

# Direct tool call by name
assert_direct_tool_allowed('read')
raw = session.tool('read', {'file_path': 'pyproject.toml'})
print(f'pyproject.toml via tool(): {len(raw.output)} bytes')

# Inspect available tool schemas
schemas = session.tool_definitions()
print(f'session exposes {len(schemas)} tools')

# Structured output: generate a schema-validated JSON object
assert_direct_tool_allowed('generate_object')
structured = session.tool('generate_object', {
    'schema': {
        'type': 'object',
        'required': ['count', 'language'],
        'properties': {
            'count': {'type': 'integer'},
            'language': {'type': 'string'},
        },
    },
    'prompt': 'How many Python files are in this project?',
    'schema_name': 'file_stats',
})
if structured.exit_code != 0:
    raise RuntimeError(structured.output)
print('structured output:', json.loads(structured.output)['object'])

session.close()

Direct tools execute under the session workspace and should be treated as privileged host operations. Most calls (read, glob, grep) are purely deterministic; generate_object is the exception — it still calls the model to fill a schema-validated JSON object, but you drive it explicitly rather than through a free-form agent turn.

A runnable version ships at crates/code/sdk/node/examples/basic/test_generate_object.ts (Python: crates/code/sdk/python/examples/test_generate_object.py).

On this page