ImpoDocs
Browse documentation

DocumentationExtend the framework

Add tools and instructions

Define an operation, register it for the right agent context, and make its behavior recoverable.

On this pageDefine a small read-only toolRegister and expose itWrite the instructionChoose the retry policyVerify and ship

Server tools live under server/src/tools/. A ToolDefinition combines a model-facing JSON schema with runtime validation, execution and a retry policy. The ToolRegistry is an immutable code catalog; it contains no user's credentials or execution state.

Define a small read-only tool#

This complete example returns the current time in a requested time zone. Save it as server/src/tools/time-tools.ts in your fork. It uses the existing registry and error types.

ts
import { ServiceError } from '../errors.js';
import { ToolRegistry } from './registry.js';

export const timeTools = new ToolRegistry([{
  name: 'impo_time_in_zone', version: 1,
  family: 'internal', executionLocation: 'server',
  description: 'Read the current time in an IANA time zone.',
  parameters: {
    type: 'object', additionalProperties: false,
    properties: { timeZone: { type: 'string', maxLength: 100 } },
    required: ['timeZone'],
  },
  timeoutMs: 1000, retry: 'read-only',
  validate(input) {
    const value = input as Record<string, unknown> | null;
    const timeZone = value?.timeZone;
    try {
      if (!value || Array.isArray(value) ||
          Object.keys(value).length !== 1 ||
          typeof timeZone !== 'string' || timeZone.length > 100) {
        throw new Error('Invalid arguments');
      }
      new Intl.DateTimeFormat('en-US', { timeZone }).format();
      return { timeZone };
    } catch {
      throw new ServiceError(422, 'invalid_tool_arguments',
        'Provide one valid IANA timeZone.');
    }
  },
  async execute(input, context) {
    context.signal.throwIfAborted();
    const now = new Date();
    const timeZone = input.timeZone as string;
    return { ok: true, data: {
      utc: now.toISOString(), timeZone,
      local: new Intl.DateTimeFormat('en-US', {
        timeZone, dateStyle: 'full', timeStyle: 'long',
      }).format(now),
    } };
  },
}]);

For account data, inject an owned repository and use context.userId. For durable side effects, use context.invocationId as part of the receipt or deduplication strategy. Never let tool arguments select an arbitrary account.

Register and expose it#

In server/src/runtime.ts, import timeTools and include it in the existing ToolRegistry.merge(...) that constructs serverTools. Main Chat's agentConfig already takes function definitions from that catalog.

Task tools are selected separately in taskAgentConfig. If the new operation is appropriate for Tasks, add ...timeTools.functionDefinitions() there too. Do not replace the existing catalogs. Native-device tools and recursive task creation remain excluded from Tasks.

The deterministic development runtime does not make real model tool selections. Validate the tool directly first; use the Rebyte protocol test path or a configured Rebyte runtime for integration.

Write the instruction#

Put behavior guidance in the English modules under server/src/prompts/, not in the mobile app. For the example: “When the user asks for the current time in a place, resolve the IANA time zone and use impo_time_in_zone. Report the returned time and zone.”

Update the applicable prompt version when changing a Session's configuration. Existing accepted work must retain its execution configuration. Follow the existing Session refresh and capability-selection behavior rather than mutating an active turn.

Choose the retry policy#

PolicyAppropriate use
read-onlyA repeated read has no external side effect.
transactionalThe implementation has a durable operation identity and can return its prior result.
neverRepeating an uncertain operation could duplicate a side effect.

Selecting transactional does not create idempotency automatically. The operation and its receipt must enforce it. Return explicit errors and respect context.signal when calling external services.

Verify and ship#

Test invalid arguments, unavailable dependencies, account ownership and the declared retry behavior. Run npm run typecheck and npm run test:server; use npm run test:rebyte when changing durable provider dispatch. Deploy the API and worker configuration together when both construct the runtime.

Read the registry, runtime composition and gadget tools for production examples.