@schift-io/agent-workflow-protocol
v0.1.5
Published
AWP: a YAML-first protocol for portable agent workflows.
Maintainers
Readme
Agent Workflow Protocol
AWP is a YAML-first protocol for portable agent workflows.
Write an agent workflow once as .awp.yaml, then compile it into runtime-specific
targets such as Schift, LangGraph, Vercel AI SDK, OpenAI Responses/Agents,
Anthropic Messages, Gemini Function Calling, or MCP tool surfaces.
schema: agent-workflow-protocol
version: "0.1"
id: research-router
name: Research routerStatus
AWP v0.1 is a draft contract.
Compatibility has been checked against the official SDK/runtime surfaces listed
below. Installing @schift-io/agent-workflow-protocol also installs the Schift
SDK and the current companion projection adapters for Vercel AI SDK, Google Gen
AI, and LangGraph.js. The protocol package still owns the portable YAML shape,
schema, parser, validator, supported-target metadata, and SDK mapping rules.
| Area | Status | | --- | --- | | YAML schema | Implemented | | TypeScript contract types | Implemented | | Parser / serializer | Implemented | | Structural validation | Implemented | | Tool-calling normalization spec | Implemented | | Native token/log/audit evidence spec | Implemented | | Cost and quality observation persistence | Implemented | | Companion npm adapters | Shipped | | Reference runner | Implemented |
The public conformance YAML set lives in examples/conformance/*.awp.yaml.
Schift Workflow v2 is the Schift-native managed-workflow target for these AWP
templates; internal Schift block names are implementation details, not the
public YAML contract.
Companion Adapters
The main package exposes convenience subpaths for the bundled projection adapters:
import { asVercelAI } from "@schift-io/agent-workflow-protocol/adapters/vercel-ai";
import { asGoogleGenAI } from "@schift-io/agent-workflow-protocol/adapters/google-genai";
import { asLangGraph } from "@schift-io/agent-workflow-protocol/adapters/langgraph";Use classifyAwpAdapterProjection() before projection to keep the direct
adapter/runtime boundary explicit:
import {
classifyAwpAdapterProjection,
} from "@schift-io/agent-workflow-protocol";
const status = classifyAwpAdapterProjection(template, "vercel-ai");
if (status.requiresRuntime) {
// Hand the workflow to the Schift/local runtime instead of forcing a
// side-effecting graph through a single-call SDK adapter.
}Why AWP Exists
Agent frameworks all describe similar ideas with different shapes:
- agents and roles
- model settings
- tools and function calling
- connectors and external context
- graph topology or step loops
- approval and human review
- token accounting, logging, and audit traces
AWP makes those concepts explicit in one neutral contract. The protocol is the source of truth; SDK adapters are compilation targets.
Compatibility Matrix
| Target | Support level | Contract status | Adapter target |
| --- | --- | --- | --- |
| Schift API and UI | Full workflow | Native target | Managed agents, hosted workflows, dashboard builder state |
| LangGraph Python | Full workflow | Mapped | StateGraph, nodes, edges, conditional routing, subgraphs, checkpointers |
| LangGraph JS | Full workflow | Mapped | StateGraph, stream/custom events, persistence, interrupts |
| Vercel AI SDK | Full workflow | Mapped | generateText, streamText, tool(...), bounded step loops |
| OpenAI Responses / Agents SDK | Tool surface | Mapped | Function tools, built-in tools, MCP tools, host-side approval |
| Anthropic Messages | Tool surface | Mapped | Claude tools, tool_use, tool_result, streaming content blocks |
| Gemini Function Calling | Tool surface | Mapped | Function declarations, function response parts, safety and usage metadata |
| MCP tools | Connector surface | Mapped | MCP tool list/call schema and server capability surfaces |
Machine-readable target metadata is exported as SUPPORTED_SDK_TARGETS.
Core Guarantees
YAML Is Canonical
AWP templates are authored as .awp.yaml. Generated JSON or SDK objects are
adapter outputs, not the canonical source.
Adapter Projection Is Explicit
Every adapter target should classify a template before execution:
direct: the target can run the AWP subset without hiding semantics.requires_runtime: a host runtime such as Schift must enforce bindings, approvals, writes, webhooks, secrets, or multi-step dataflow.unsupported: the template violates policy or cannot be represented safely.
The conformance examples cover simple LLM calls, structured output, tool calls, retrieval, approval-gated writes, outbound webhook allowlists, streaming, multi-step graphs, subworkflows, and policy-disabled code.
Tool Calls Have Stable IDs
Every tool call gets an AWP-owned protocol_call_id.
Provider ids are preserved as metadata:
- OpenAI
call_id - Anthropic
tool_use.id - Gemini response/function metadata
- LangGraph or Vercel runtime ids
The AWP id is the audit and correlation key across all targets.
Native Evidence Is Part Of The Protocol
AWP does not treat observability as an afterthought. Templates can require:
- token counters
- structured run logs
- model identity and per-step duration
- tool-call records
- streaming deltas
- structured output artifacts
- provider-exposed reasoning summaries
- optional cost and quality observations
- approval events
- intermediate audit checkpoints
This lets Schift, LangGraph, and Vercel AI SDK runs produce comparable evidence. AWP does not require or permit storing hidden raw chain-of-thought; adapters log reasoning summaries, token metadata, or redacted traces only when the provider or host runtime exposes them.
Quick Start
Install AWP in a TypeScript or Node.js project:
npm install @schift-io/agent-workflow-protocolnpm install
npm testimport {
parseAwpYaml,
stringifyAwpYaml,
validateAwpTemplate,
SUPPORTED_SDK_TARGETS,
} from "@schift-io/agent-workflow-protocol";const template = parseAwpYaml(source);
const result = validateAwpTemplate(template);
if (!result.valid) {
console.error(result.diagnostics);
}Run A Template
The first executable target is the reference runner. It does not call real models or tools. It walks the graph and writes the standard run evidence that real adapters must also produce.
Validate a template from an installed package:
npx @schift-io/agent-workflow-protocol validate ./workflow.awp.yamlOr run the repository build directly while developing AWP:
npm run build
node dist/cli.js run examples/research-router.awp.yaml \
--target reference \
--input '{"query":"How should logs work?"}'Adapters that already have pricing or evaluator output can pass portable observations through the reference persistence path:
node dist/cli.js run examples/research-router.awp.yaml \
--target reference \
--cost '{"source":"adapter_estimate","estimated":true,"currency":"USD","total_cost":0.0020515}' \
--quality '[{"source":"evaluator","kind":"score","metric":"faithfulness","score":90,"scale_min":0,"scale_max":100,"passed":true}]'Output:
run_id: awp_run_...
status: completed
events: <count>
artifacts: <count>
log: .awp-runs/<run_id>/events.jsonl
summary: .awp-runs/<run_id>/run.jsonThe run directory contains:
.awp-runs/<run_id>/
├── run.json
├── events.jsonl
├── artifacts.json
└── intermediate-results.jsonevents.jsonl includes lifecycle, model, streaming, tool, token, optional
cost/quality, audit, and duration events. run.json carries aggregate usage and
any aggregate cost/quality observations that were supplied by the adapter.
artifacts.json includes intermediate results, normalized tool results,
structured outputs, reasoning summaries, audit decisions, and the final output.
This is the debugging surface Schift API/UI and SDK adapters should read instead
of scraping provider-specific logs.
See examples/run-observations/cost-quality/ for a compact persisted fixture
with token.usage, cost.observed, quality.observed, and aggregate
run-level cost/quality.
Minimal Template
schema: agent-workflow-protocol
version: "0.1"
id: support-triage
name: Support triage
inputs:
ticket:
type: string
required: true
state:
ticket: string
answer: string
agents:
triage:
role: support-triage
model:
provider: openai
name: gpt-4.1-mini
tools: [memory.search]
max_steps: 6
tools:
memory.search:
kind: schift.memory.search
description: Search connected Schift memory.
schema_format: json_schema
strict: true
side_effect: read
idempotent: true
runtime: schift
execution:
mode: server
binding: schift.memory.search
timeout_ms: 10000
approval:
mode: none
input_schema:
type: object
additionalProperties: false
required: [query]
properties:
query:
type: string
tool_calling:
default_choice:
mode: auto
allowed_tools: [memory.search]
parallelism:
enabled: true
max_concurrent: 4
return_results_together: true
require_results_for_all_calls: true
mint_protocol_call_id: true
native:
token_counter:
required: true
fields:
- prompt_tokens
- completion_tokens
- reasoning_tokens
- cached_tokens
- tool_call_tokens
- total_tokens
logging:
level: info
events:
- run.started
- step.started
- model.started
- model.output.delta
- model.structured_output
- reasoning.summary
- model.completed
- token.usage
- cost.observed
- quality.observed
- tool.call.delta
- tool.started
- tool.completed
- run.completed
- run.failed
streaming:
enabled: true
persist_deltas: true
include_text_deltas: true
include_tool_call_deltas: true
structured_output:
required: true
mode: adapter
reasoning:
capture: provider_summary
include_raw_thinking: false
summary_required: true
audit:
checkpoints:
- id: before_final_answer
type: pre_response
required: true
graph:
start: triage
nodes:
triage:
type: agent
ref: triage
done:
type: end
edges:
- from: triage
to: doneSee examples/research-router.awp.yaml for a fuller graph with parallel specialist branches and audit checkpoints.
Tool Calling Model
AWP standardizes the full tool lifecycle.
| Layer | AWP field / event | Purpose |
| --- | --- | --- |
| Declaration | tools.* | Stable tool identity, schema, runtime, side effects, approval policy |
| Choice | tool_calling.default_choice | Model-level tool-choice policy |
| Parallelism | tool_calling.parallelism | Concurrency and result-buffering policy |
| Correlation | protocol_call_id | Runtime-neutral call id for logs, replay, and audit |
| Streaming | tool.call.delta | Partial arguments or incremental tool-call data |
| Approval | tool.approval.requested, tool.approval.decided | Host/runtime approval before side effects |
| Execution | tool.started, tool.completed, tool.failed | Tool execution evidence |
| Accounting | AwpTokenUsage | Provider-exposed token counters, never fabricated |
Detailed rules are in docs/tool-calling.md.
Repository Map
.
├── docs/
│ ├── sdk-mapping.md
│ ├── schift-workflow-v2-target.md
│ └── tool-calling.md
├── examples/
│ └── research-router.awp.yaml
├── schemas/
│ └── awp.v0.schema.json
├── spec/
│ └── awp.v0.md
├── src/
│ ├── index.ts
│ ├── supported-sdks.ts
│ ├── types.ts
│ ├── validate.ts
│ └── yaml.ts
└── test/
└── awp.test.mjsDesign Docs
Roadmap
- Add adapter test fixtures for every supported target.
- Implement
@schift-io/awp-langgraph. - Implement
@schift-io/awp-vercel-ai-sdk. - Add OpenAI, Anthropic, Gemini, and MCP tool-surface normalizers.
- Wire Schift API/UI import, preview, validation, and run evidence storage.
Non-Goals
- AWP does not execute workflows by itself.
- AWP is not the existing Schift block workflow YAML.
- AWP is not a LangGraph-only schema.
- AWP is not a canvas-state persistence format.
