While Python dominates the AI research space, TypeScript is the engine of the modern full-stack web. From high-performance Node.js backends to complex React frontends, TypeScript provides the structure and safety that large-scale engineering teams demand.
When we built the apcore-js SDK, we didn't just want to "port" the Python logic. We wanted to create a first-class, type-safe experience that leverages the unique strengths of the JavaScript ecosystem.
In this twentieth article of our series, we explore how to build AI-Perceivable modules in TypeScript using apcore and TypeBox.
A core tenet of the apcore protocol is that a module’s behavior should be identical regardless of the implementation language. A module named executor.user.get
must accept the same JSON input and produce the same output in both Python and TypeScript.
apcore-js achieves this by using TypeBox as its core schema engine. TypeBox allows us to define JSON Schemas that double as TypeScript types, giving us compile-time safety and runtime validation in a single definition.
In apcore-js, you define your module's contract using TypeBox's Static
and Type
primitives:
import { Type, Static } from '@sinclair/typebox';
export const InputSchema = Type.Object({
userId: Type.String({ description: "The unique UUID of the user." }),
includePrivate: Type.Boolean({ default: false, description: "Whether to include sensitive fields." })
});
export type Input = Static<typeof InputSchema>;
By adding the description
field directly into the TypeBox definition, you are creating the "Cognitive Interface" for the AI while simultaneously providing type hints for your IDE.
apcore-js supports both class-based and functional module definitions. The class-based approach is idiomatic for TypeScript developers:
import { ClassModule, ModuleAnnotations, Context } from '@apcore/core';
export class GetUserModule extends ClassModule {
id = "executor.user.get";
description = "Retrieve detailed user profiles.";
inputSchema = InputSchema;
annotations = new ModuleAnnotations({
readonly: true,
destructive: false
});
async execute(inputs: Input, context: Context): Promise<object> {
// inputs is fully typed!
const user = await db.users.findUnique({ where: { id: inputs.userId } });
return { status: "success", user };
}
}
Managing a registry in Node.js is just as easy as in Python. apcore-js includes a FileSystem
that scans your directory structure.
One of the cleverest parts of the SDK is its Automatic ID Normalization. In TypeScript, it’s common to name your files using camelCase
(e.g., sendEmail.ts
). apcore-js automatically maps this to the canonical snake_case
(e.g., send_email
) required by the protocol. This ensures that an AI Agent sees a consistent naming convention even in a polyglot environment.
AI Agents in the Node ecosystem often live inside microservices. apcore-js is built for distributed environments. It automatically propagates the trace_id
through Promise
chains and can integrate with existing tracing headers (like Zipkin or Jaeger) via custom middleware.
const result = await executor.callAsync("executor.user.get", { userId: "123" }, context);
By combining the rigor of the apcore protocol with the safety of TypeScript and TypeBox, apcore-js allows you to build AI-Perceivable systems that are as reliable as they are intelligent. You get the best of both worlds: high-velocity development and rock-solid architectural constraints.
Now that we’ve mastered the two most popular languages for AI, it’s time to look at the performance tier. In our next article, we dive into Zero-Cost Abstraction: Building High-Performance AI Modules in Rust.
This is Article #20 of the Building the AI-Perceivable World series. Type safety is the first step to AI safety.
GitHub: aiperceivable/apcore-typescript