Skip to content

Typescript sdk#100

Open
spichen wants to merge 29 commits intooracle:mainfrom
spichen:typescript-sdk
Open

Typescript sdk#100
spichen wants to merge 29 commits intooracle:mainfrom
spichen:typescript-sdk

Conversation

@spichen
Copy link

@spichen spichen commented Feb 13, 2026

Resolves #97

…ation

Implements a complete TypeScript SDK providing the same core capabilities
as the Python SDK (pyagentspec) for authoring, validating, and
serializing/deserializing Agent Spec configurations.

Core features:
- All component types: Agent, Swarm, ManagerWorkers, Flow, 14 node types,
  4 tool types, 6 LLM config types, edges, datastores, transforms
- Property system with JSON Schema mapping (9 typed property factories)
- Full serialization/deserialization with JSON and YAML support
- $component_ref referencing for shared components
- Template variable extraction from {{placeholder}} syntax
- Plugin architecture for custom component types
- Version-gated field serialization (agentspec_version 25.4.1+)
- camelCase/snake_case field name conversion for Python SDK interop
- FlowBuilder with ergonomic builder pattern API

Technical details:
- Zod schemas + factory functions (no class hierarchies)
- Discriminated unions on componentType for type-safe polymorphism
- Strict TypeScript with zero `any` types in public API
- ESM + CJS dual build via tsup
- 384 tests across 29 test files (vitest)

Signed-off-by: Salah <nh.salah@gmail.com>
…ComponentUnion

Several component types had Zod schemas registered in BUILTIN_SCHEMA_MAP
but no corresponding factory functions in BUILTIN_FACTORY_MAP, causing
deserialization to crash at runtime. Added create* factories for:
RemoteAgent, A2AConnectionConfig, all transport types, Oracle/Postgres
datastores, and their connection configs. Also added RemoteAgent to the
AgenticComponentUnion discriminated union so it is accepted where
AgenticComponent is expected.
…mponent

versionLt now uses Math.max instead of Math.min when comparing version
segments, treating missing segments as 0. This fixes the latent bug where
versionLt("1.0", "1.0.1") incorrectly returned false.

Extracted isComponent to a shared utility in component.ts with a stronger
UUID check on the id field, eliminating the duplicate definitions in
serialization-context.ts and referencing.ts.
- Add input size and nesting depth limits to AgentSpecDeserializer to
  prevent resource exhaustion from untrusted input (backwards-compatible
  constructor accepts both legacy plugin array and new options object)
- Add license, repository, homepage, keywords, and engines to package.json
- Add 77 new tests (384 -> 461) covering previously untested components:
  A2AAgent, SpecializedAgent, MCP tools/transports, datastores,
  transforms, version-gated serialization, sensitive field exclusion,
  and negative deserialization paths (malformed data, size/depth limits)
…ation

Address critical and important issues found during code review:

Critical fixes:
- Add depth check to fromDict() to prevent resource exhaustion bypass
- Filter __proto__/constructor/prototype keys in deserialization to
  prevent prototype pollution
- Use safe YAML schema ({ schema: "core" }) to restrict type resolution
- Move FlowBuilder.addConditional validation before state mutation
- Always increment conditional edge counter for unique data edge names
- Use user-provided outputs in InputMessageNode instead of discarding them

Important fixes:
- Extract duplicated map helpers (inferMapInputs, getDefaultReducers,
  inferMapOutputs) into shared map-helpers.ts
- Extract duplicated getEndNodeBranches into shared node-helpers.ts
- Remove redundant .optional() before .default() in transform schemas
- Add minNumMessages <= maxNumMessages validation
- Fix AgentNode operator precedence with explicit parentheses
- Remove redundant Buffer.isBuffer check (Uint8Array covers Buffer)
- Recurse priority key values in makeOrderedDict for consistency
- Document camelToSnake/snakeToCamel scope limitations
- Document circular-dep workarounds in Swarm/ManagerWorkers/Flow schemas
- Add explanatory comment on FactoryFn `any` type necessity
…ml/fromJson/fromYaml

Remove Python-ism toDict/fromDict public methods and replace with
private _toDict/_fromDict. The snake_case conversion is now controlled
via a camelCase option on toJson/toYaml/fromJson/fromYaml instead of
being exposed as a separate API surface.

- Add camelCase flag to SerializationContext and DeserializationContext
- Remove ComponentAsDict and DisaggregatedComponentsConfig from public exports
- Update all tests to use toJson+JSON.parse / fromJson+JSON.stringify
Eight examples covering basic agents, tools, multi-agent patterns,
flows, MCP tools, serialization, A2A agents, and datastores.
@oracle-contributor-agreement
Copy link

Thank you for your pull request and welcome to our community! To contribute, please sign the Oracle Contributor Agreement (OCA).
The following contributors of this PR have not signed the OCA:

To sign the OCA, please create an Oracle account and sign the OCA in Oracle's Contributor Agreement Application.

When signing the OCA, please provide your GitHub username. After signing the OCA and getting an OCA approval from Oracle, this PR will be automatically updated.

If you are an Oracle employee, please make sure that you are a member of the main Oracle GitHub organization, and your membership in this organization is public.

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Required At least one contributor does not have an approved Oracle Contributor Agreement. label Feb 13, 2026
- Add depth limits to serialization (dumpField, makeOrderedDict) to
  prevent stack overflow from deeply nested plain objects
- Rewrite deserializer checkDepth() iteratively to avoid stack overflow
  in the depth checker itself
- Filter __proto__/constructor/prototype keys in serialization
  (dumpField, dumpModelObject) to prevent prototype pollution via
  round-tripping through external systems
- Deduplicate DANGEROUS_KEYS into shared types.ts module
- Fix Uint8Array.toString() in templating returning byte values instead
  of meaningful content; now returns empty array
- Add tests for prototype pollution prevention, circular reference
  detection, serialization depth limits, and dangerous key filtering
…d more

Add comprehensive tests targeting low-coverage areas, bringing overall
coverage from ~93% to 99%+ statements. Key additions include property
comparison helpers (type equality, castability, union/object/dict),
serialization context (version gating, camelCase mode, dangerous keys),
deserialization context (loadField, loadReference, camelCase round-trip),
flow builder edge cases, map node reducers, and factory functions for
remote agents and OCI configs.
@dhilloulinoracle
Copy link
Contributor

Thanks a lot @spichen for this big contribution!
We will start reviewing it.

To be able to merge it, we would need you to sign the CLA. Would it be possible for you to have a look at that?

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces a comprehensive TypeScript SDK for the Oracle Open Agent Specification. The SDK provides a strongly-typed, developer-friendly API for defining AI agents, multi-agent systems, workflows, tools, and related components with full serialization/deserialization support.

Changes:

  • Complete TypeScript SDK implementation with Zod schemas for validation
  • Comprehensive test suite with 30+ test files covering all major features
  • Full serialization/deserialization system supporting JSON/YAML with version gating
  • 8 detailed examples demonstrating SDK usage patterns

Reviewed changes

Copilot reviewed 135 out of 136 changed files in this pull request and generated 22 comments.

Show a summary per file
File Description
package.json Package configuration with dependencies (zod, yaml) and dev tooling
tsconfig.json Strict TypeScript configuration with modern ES2022 target
tsup.config.ts Build configuration for dual CJS/ESM output with type definitions
vitest.config.ts Test configuration with v8 coverage
src/component.ts Base component schemas and type system
src/agents/*.ts Agent types: Agent, Swarm, ManagerWorkers, RemoteAgent, A2AAgent, SpecializedAgent
src/tools/*.ts Tool types: ServerTool, ClientTool, RemoteTool, BuiltinTool, MCPTool, ToolBox
src/llms/*.ts LLM configs: OpenAI, vLLM, Ollama, OCI GenAI
src/flows/*.ts Flow system with nodes, edges, and FlowBuilder
src/mcp/*.ts MCP tool and transport support
src/serialization/*.ts Complete serialization system with plugins, version gating, and sensitive field exclusion
src/versioning.ts Version tracking and comparison utilities
src/templating.ts Template placeholder extraction from strings/objects
src/sensitive-field.ts Security: marks fields for exclusion from serialization
tests/**/*.test.ts Comprehensive test coverage for all components
examples/*.ts 8 working examples demonstrating SDK usage

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@spichen spichen marked this pull request as ready for review February 13, 2026 13:51
@spichen spichen requested a review from a team February 13, 2026 13:51
@oracle-contributor-agreement
Copy link

Thank you for signing the OCA.

@oracle-contributor-agreement oracle-contributor-agreement bot added OCA Verified All contributors have signed the Oracle Contributor Agreement. and removed OCA Required At least one contributor does not have an approved Oracle Contributor Agreement. labels Feb 13, 2026
- Validate sourceOutput/destinationInput exist on nodes in createDataFlowEdge
- Add type castability check between connected properties
- Use stringProperty constructor for LLM node default output
- Add tests for nested objectProperty and complex dictProperty value types
Replace Record<string, unknown> with ComponentWithIO for sourceNode
and destinationNode parameters, eliminating unknown type casts.
…erfaces

Replace the untyped Record<string, unknown> alias with discriminated
interfaces (SerializedComponent, CamelCaseSerializedComponent,
ComponentRef) and centralize protocol field management via PROTOCOL_KEYS,
getProtocolKeys(), and ALL_PROTOCOL_FIELDS. This eliminates duplicate
field sets across 4+ files, fixes camelCase-mode bugs in nested component
detection and key ordering, and moves type guards to a single source of
truth in types.ts.
…ction

PropertySchema no longer defaults jsonSchema to {} or title to "property".
The jsonSchema field now requires a non-empty title and either a type or
anyOf field. propertyFromJsonSchema applies the same validation instead of
silently falling back. ApiNode default output now explicitly declares
type "string".
…ration

Replace z.record(z.unknown()) workarounds with LazyNodeRef/LazyFlowRef
backed by z.lazy() and late-binding registration, breaking the circular
dependency (Flow -> NodeUnion -> FlowNodeSchema -> FlowSchema) while
enabling proper schema validation for nodes, subflows, and edge refs.
spichen added 4 commits March 19, 2026 02:03
Accept any non-empty string ID (not just UUID), reject empty swarm
relationships and empty manager-workers, validate manager-not-a-worker,
add flow graph invariant checks, make data-flow-edge validation
unconditional, add fail-fast version compatibility check, and extend
version gates map with new gated fields.
@spichen spichen requested a review from sonleoracle March 19, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeScript SDK for Agent Spec

4 participants