intentcall_codegen 1.0.0 copy "intentcall_codegen: ^1.0.0" to clipboard
intentcall_codegen: ^1.0.0 copied to clipboard

PRE-RELEASE — Optional @AgentTool annotations and build_runner codegen for intentcall.

⚠️ Pre-release train — Highly experimental. APIs may change without notice. Not for production. Details.

intentcall_codegen #

pub package pub points repository

Optional @AgentTool / @AgentParam annotations and build_runner codegen pilot.

Hand-written AgentCallEntry remains first-class; codegen is opt-in for stable tools with typed parameters.

Catalog mental model #

@AgentTool          →  tool implementation + (usually) catalog row
handwritten getter  →  tool implementation only
catalog row         →  @AgentCatalog list
agent_catalog.g.dart →  merge of all three sources

See ADR 0021.

Wiring instance methods #

When a tool handler needs host state (services, config, or UI policy), keep the business logic on an instance method and expose an AgentCallEntry getter whose handler closes over this. This matches the mcp_flutter harness pattern: one shared host object, instance methods for behavior, catalog rows for projection.

  1. Host class with a shared singleton
final class DemoHostTools {
  DemoHostTools();

  static final DemoHostTools shared = DemoHostTools();

  Future<AgentResult> inbox(final String folder) async { /* … */ }

  AgentCallEntry get inboxCallEntry => AgentCallEntry.tool(
    namespace: 'app',
    name: 'demo_inbox',
    description: 'Read inbox folder',
    inputSchema: const <String, Object?>{ /* … */ },
    handler: (final args) async => inbox(args['folder'] as String),
  );
}
  1. Merge catalog rows with @AgentCatalog

Co-locate a top-level or static List<AgentRegistryCatalogEntry> with the host class and annotate it with @AgentCatalog. The catalog builder discovers annotated lists under lib/ and spreads them into lib/generated/agent_catalog.g.dart alongside @AgentTool rows. Static host lists merge as HostClass.catalogEntries. Optional per-row projection uses EntryProjection (same as @AgentProjection on annotated tools).

final class DemoHostTools {
  static final DemoHostTools shared = DemoHostTools();

  AgentCallEntry get inboxCallEntry => AgentCallEntry.tool(/* … */);

  @AgentCatalog()
  static final List<AgentRegistryCatalogEntry> demoHostCatalogEntries =
      <AgentRegistryCatalogEntry>[
    AgentRegistryCatalogEntry(
      registryKey: 'app_demo_inbox',
      entry: shared.inboxCallEntry,
      projection: const EntryProjection(
        surfaces: {AgentManifestSurface.webMcp: true},
      ),
    ),
  ];
}

After dart run build_runner build, lib/generated/agent_catalog.g.dart spreads @AgentCatalog lists next to @AgentTool rows discovered from generated *.g.dart parts. Duplicate registryKey values between codegen and @AgentCatalog rows fail the build.

  1. Export manifest and register at runtime
dart run build_runner build --delete-conflicting-outputs
dart run intentcall_cli:intentcall manifest export --check

Register from the merged catalog in app setup, or invoke by registryKey.

Probe anchor for manifest export #

intentcall manifest export evaluates each catalog row's entry: expression in a subprocess (resolveDescriptor()). Use a compile-time anchor such as Host.shared.<getter>CallEntry or a top-level *CallEntry getter — not a per-request or widget-scoped instance. The probe needs descriptor metadata only; your runtime registry may bind a different live instance as long as qualifiedName and schema stay aligned.

static shared is optional. When absent, instance @AgentTool catalog rows use descriptor: (manifest metadata only); register extension getters from your live host at bootstrap. When present, catalog may use entry: Host.shared.* for one-line registerAll demos.

Handwritten projection #

Use inline EntryProjection on @AgentCatalog rows (recommended for small hosts):

AgentRegistryCatalogEntry(
  registryKey: 'app_demo_inbox',
  entry: shared.inboxCallEntry,
  projection: const EntryProjection(
    surfaces: {AgentManifestSurface.webMcp: true},
  ),
),

For manifest-only rows without a handler at probe time, use descriptor: on AgentRegistryCatalogEntry and register the handler separately at runtime.

@AgentCatalog placement #

Placement Spread in agent_catalog.g.dart
Static field on host (recommended) ...HostClass.catalogEntries
Top-level list ...catalogEntries
Instance field Not supported

Do not list tools in @AgentCatalog when @AgentTool already emits their catalog row (duplicate registryKey fails the build).

Full runnable example: example/lib/tools/demo_host_tools.dart.

Catalog builder options #

Configure intentcall_codegen|agent_catalog in build.yaml:

targets:
  $default:
    builders:
      intentcall_codegen|agent_catalog:
        options:
          tool_part_globs: [lib/**.g.dart]   # @AgentTool via agent_tool parts
          tool_globs: [lib/**.dart]          # @AgentCatalog scan only
          tool_exclude_globs: [lib/**.g.dart, lib/generated/**]
          host_binding_field: shared         # optional static probe anchor name
  • tool_part_globs — catalog rows come from generated parts, not raw @AgentTool sources.
  • tool_globs / tool_exclude_globs — scope @AgentCatalog discovery only.
  • lib/src/ — not hard-excluded; tools under lib/src/ join the catalog when agent_tool emits their .g.dart.

See example/build.yaml for a commented template.

Pilot usage #

  1. Add dependencies from the current hosted train:
dart pub add intentcall_core intentcall_schema intentcall_codegen
dart pub add --dev build_runner
  1. Annotate a top-level function:
import 'package:intentcall_codegen/intentcall_codegen.dart';
import 'package:intentcall_core/intentcall_core.dart';
import 'package:intentcall_schema/intentcall_schema.dart';

part 'my_tools.g.dart';

@AgentTool(namespace: 'app', name: 'demo_ping', description: 'Ping')
Future<AgentResult> demoPing(@AgentParam('Message') String message) async {
  return AgentResult.success(data: {'pong': message});
}
  1. Run codegen:
dart run build_runner build --delete-conflicting-outputs

This emits lib/generated/agent_catalog.g.dart (all @AgentTool registrations) and per-file *.g.dart part files.

  1. Export the platform manifest (host project with intentcall.yaml):
dart run intentcall_cli:intentcall manifest export --check
  1. Register generated intents:
registry.register(demoPingRegistration);
// or
registerAll(registry, {demoPingCallEntry});

Runnable example #

See example/ for a self-contained Dart host (lib/tools/, lib/generated/agent_catalog.g.dart, web/agent_manifest.json):

cd example
dart pub get
dart run build_runner build
dart run intentcall_cli:intentcall manifest export --check --project-dir .

The library package root intentionally has no committed catalog or manifest — only annotations and builders.

Generated output #

For each top-level @AgentTool function, .g.dart emits:

  • _<name>InputSchema — JSON Schema from parameter types
  • <name>CallEntry — top-level AgentCallEntry.tool(...) factory
  • <name>Registration — RegisteredAgentIntent via .toRegistration()

For each instance @AgentTool method on a host class, .g.dart emits:

  • _<name>InputSchema constants
  • extension <Host>AgentCodegen on <Host> with <name>CallEntry getters whose handlers call instance methods on this
  • optional top-level <name>Registration aliases when a static binding field (default shared) exists

The aggregate catalog references instance rows as Host.shared.<name>CallEntry when a binding static exists, otherwise descriptor: metadata only.

@AgentProjection uses typed AgentManifestSurface keys:

@AgentProjection(surfaces: {AgentManifestSurface.webMcp: true})

Supported parameter types: String, int, bool, double.

host_binding_field (see Catalog builder options) overrides the default shared static field name used for optional catalog probe anchors.

platforms.enabled in intentcall.yaml scopes default manifest surface families (see ADR 0020).

Scope (pilot) #

  • Top-level @AgentTool functions and optional instance-method codegen on host classes (see Wiring instance methods); handwritten AgentCallEntry getters remain the canonical path for host-bound tools
  • Tool kind only (resources: hand-write AgentCallEntry.resource)
  • Test fixtures: test/fixtures/demo_ping_tool.dart, test/fixtures/host_instance_tool.dart

See DX FAQ for current codegen workflow and Design FAQ for the IntentPack direction.

0
likes
150
points
608
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

PRE-RELEASE — Optional @AgentTool annotations and build_runner codegen for intentcall.

Repository (GitHub)
View/report issues
Contributing

Topics

#mcp #codegen #build-runner

License

MIT (license)

Dependencies

analyzer, build, glob, intentcall_core, intentcall_platform_sync, intentcall_schema, path, source_gen

More

Packages that depend on intentcall_codegen