{"_id":"@ageflow/runner-api","_rev":"9-9fbe8e1218eeb9ba307ff5fde33810b1","name":"@ageflow/runner-api","dist-tags":{"latest":"0.4.1"},"versions":{"0.1.0":{"name":"@ageflow/runner-api","version":"0.1.0","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.1.0","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/agentflow/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"a008de09fac503d7b45feff2e05ca34c447eb16a","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.1.0.tgz","fileCount":35,"integrity":"sha512-63Q2SmTCt+ux7CeCCcLiwsVsp/jOv598qaXRM7NignyQYDroREylLSvk0E8CrTOsZIzof07uGHQtGP0hNAOcDQ==","signatures":[{"sig":"MEYCIQDlXYfrVfpALPcnJ5nOFXNlNMNz7PYVRUBYZNnCSXj3SAIhAOCX5uJkX5o3afURXsCmmYEWfcvmEXjwoJFrkcUWAIn3","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":60489},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"3c1183effacdc1009c9067343d5b71d226be05e8","private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"workspace:*"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.1.0_1776330376558_0.16389745930528843","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ageflow/runner-api","version":"0.2.0","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.2.0","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/agentflow/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"d9c30f63949176e0007893d1ccd6454be88859f7","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.2.0.tgz","fileCount":35,"integrity":"sha512-NJimSL6t06/Cxu3jWDKXoFeH73QQBrjBs7j7f6meeOhUFMGyx1USumyGpMtrqhm9FqCNXgoo3pwxUTN65BN0WA==","signatures":[{"sig":"MEQCIGaZxqdz7p2EslxW4Fl6bkf9iz5HXZK2CUqxqKsiv04uAiAc0PmXIqgE0DUvhVTFmqvYUSqQpRyHyOtsUCHvlu1FDQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85415},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c9ec02fd33cba8108a1255623ba329097acfe908","private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"workspace:*"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.2.0_1776330800788_0.17273824738199584","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ageflow/runner-api","version":"0.3.0","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.3.0","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"f1f5e4cd9872a60dcffd0c54eb63baea249c2984","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.3.0.tgz","fileCount":43,"integrity":"sha512-GxNGM6dlCy7b0VU8BcPTftG+JIewVbCFIX41TSNNBwBcVJUl7Ip5+KY1h0WMpKXnWXtMhCUG7yhjEoIMsOPpGw==","signatures":[{"sig":"MEUCIQDmt6grgSrLUBZFa6rD0JGMJEWhrFeRjyX4pI3/iy75/QIgeARDtawqgpVe3DhRLOS0lzv175Eqg0qLjEWI8oU4ikM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":148198},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"f055450765c4b4f8e6a06d3bcedb2e337395adb8","private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"workspace:*","@modelcontextprotocol/sdk":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0","@ageflow/testing":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.3.0_1776377992559_0.43277712579000704","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@ageflow/runner-api","version":"0.3.2","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.3.2","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"1a2794919c5210be5abeb3075e722b4dbd257266","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.3.2.tgz","fileCount":59,"integrity":"sha512-zV6dxCiaJBZciZB6JS4c66mcsZJ1sx5pbIvbhyOOYNZ5L+6U5zjn5FWjAmSBi6TGo/k6DIHYwe1zy0iDhpOFFw==","signatures":[{"sig":"MEUCIA+Jnl/MZSFVbj0tkhjJkLVmoFTGak4reV+pjx2cSs1xAiEAyAt9S3TZ/ibhdYfh4Y9VK7hJsJX9qy124+lrCYYSzTI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":177542},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"67e25292e8f64b4c7643f1ac12164e771122c632","private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"^0.3.2","@modelcontextprotocol/sdk":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0","@ageflow/testing":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.3.2_1776395155720_0.2324029073571432","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@ageflow/runner-api","version":"0.3.3","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.3.3","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"7d56557324dc52e7d083a99c229ffa81cfee1835","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.3.3.tgz","fileCount":71,"integrity":"sha512-iWQsw0g3wTdZFeDkeZDpMRfXsfZJ837TD7Vuw4s4Px1oML35ffZYYoC1pznwo2+QT9jJocgHn25RWKSoLzeSkg==","signatures":[{"sig":"MEUCIH62MVKrkFXQnlX9otosZyCeCH+HGNtTjOxp1cx6N+W6AiEAu2YSiiDE4fm7GxN+2UpGHa7PtAzKeY9vy9dG4zV03tY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":166092},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"^0.4.3","@modelcontextprotocol/sdk":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0","@ageflow/testing":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.3.3_1776415471057_0.7382577308803655","host":"s3://npm-registry-packages-npm-production"}},"0.3.4":{"name":"@ageflow/runner-api","version":"0.3.4","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.3.4","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"7ee9bd9d7d3b6422da67a0c5d94ce84bbed05306","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.3.4.tgz","fileCount":43,"integrity":"sha512-inT8FMJwqYqLzN6R3cLrzN8xDDS/MzOyHCaDCG7azdc6KJt+fzl1ugFSTYX7AIWx2pmUbI63Rvq3jHG+nHNSeg==","signatures":[{"sig":"MEYCIQDGFMDjzJVBKnSuWuBGxoj7MeoXTX/zvQHtyji6F6hV2QIhAJWYGV/uiKUTYQC0Qk1EIonO6xneaPtpJTCJr21eGFd8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":148731},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"^0.4.3","@modelcontextprotocol/sdk":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0","@ageflow/testing":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.3.4_1776416327866_0.3475710671216836","host":"s3://npm-registry-packages-npm-production"}},"0.3.5":{"name":"@ageflow/runner-api","version":"0.3.5","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.3.5","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"65c42ef4e546660cc8c52dfaa0be7a9c10bc1492","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.3.5.tgz","fileCount":43,"integrity":"sha512-5Tor+jFcNwhbeh2n+825gUQVb0j8w8H/SqFqxC78n7MV75euZj7qSg7MDaLb2DZWkO4zYXaNup1SF4RZdVVUMw==","signatures":[{"sig":"MEQCIDt6+Xv9OE5kjQ8gbsKxks5wbpXnHNT+WWvJlniOOmTuAiAobT2eM5tVZx38QND33dEndtutNXsLZJqBN4pj1RP81Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":148731},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"^0.5.0","@modelcontextprotocol/sdk":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0","@ageflow/testing":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.3.5_1776422119990_0.9954438318432204","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ageflow/runner-api","version":"0.4.0","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.4.0","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"dist":{"shasum":"f60ce85e076133121a2ab0e9482175801ff5013c","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.4.0.tgz","fileCount":47,"integrity":"sha512-PlHmMrsh2t77Fucj+jswB/USA4ZFzeCLzKLzfuqCLGXeEF2HNyMP8SpbajiNiq2+9LFFo8Uc7zG+ZKH6kBWgjw==","signatures":[{"sig":"MEUCIQCiQafkERXyy1i/tDvAuE+xc99ueMhdcTqEAVtGqf+SlAIgbTw6K65OUUDjSc52866eQroGxgTyMOF8cFLwyMuACyE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":166941},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"private":false,"scripts":{"lint":"biome check src/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit"},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"repository":{"url":"git+https://github.com/Neftedollar/ageflow.git","type":"git"},"_npmVersion":"11.11.0","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","directories":{},"sideEffects":false,"_nodeVersion":"25.8.1","dependencies":{"@ageflow/core":"^0.6.0","zod-to-json-schema":"^3.23.0","@modelcontextprotocol/sdk":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.23.0","vitest":"^2.1.0","@types/node":"^22.0.0","@ageflow/testing":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/runner-api_0.4.0_1776434937349_0.2780795151776192","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@ageflow/runner-api","version":"0.4.1","description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","type":"module","private":false,"sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"vitest run","lint":"biome check src/"},"dependencies":{"@ageflow/core":"^0.6.0","@modelcontextprotocol/sdk":"^1.0.0","zod-to-json-schema":"^3.23.0"},"devDependencies":{"@ageflow/testing":"workspace:*","@types/node":"^22.0.0","vitest":"^2.1.0","zod":"^3.23.0"},"repository":{"type":"git","url":"git+https://github.com/Neftedollar/ageflow.git"},"keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"license":"MIT","_id":"@ageflow/runner-api@0.4.1","bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"_nodeVersion":"25.8.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-J9C0Umfyudhe+f6YfaqADLof4Oimu7nRFvwYxg74a2ZyvFkJezme+2P2fKi0KhhhRxYRdBNUnfVeNUFwLUR3sw==","shasum":"ccaf54c6b517bbb8a61ccf235063303836326030","tarball":"https://registry.npmjs.org/@ageflow/runner-api/-/runner-api-0.4.1.tgz","fileCount":47,"unpackedSize":168817,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHTOP87Rv5nX/Szck8+RFhlRa8kIw/K6qpRTzMEuvtZCAiEA3ReRJ/Q7QFCcanwXBz/UexQFxWkHJ6td7ORGKQNmmFM="}]},"_npmUser":{"name":"neftedollar","email":"oildollar@gmail.com"},"directories":{},"maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/runner-api_0.4.1_1776439968821_0.6323714496895889"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-16T09:06:16.380Z","modified":"2026-04-17T15:32:49.129Z","0.1.0":"2026-04-16T09:06:16.695Z","0.2.0":"2026-04-16T09:13:20.919Z","0.3.0":"2026-04-16T22:19:52.705Z","0.3.2":"2026-04-17T03:05:55.873Z","0.3.3":"2026-04-17T08:44:31.204Z","0.3.4":"2026-04-17T08:58:48.055Z","0.3.5":"2026-04-17T10:35:20.143Z","0.4.0":"2026-04-17T14:08:57.494Z","0.4.1":"2026-04-17T15:32:48.995Z"},"bugs":{"url":"https://github.com/Neftedollar/ageflow/issues"},"license":"MIT","homepage":"https://github.com/Neftedollar/ageflow/tree/master/packages/runners/api","keywords":["ai","agents","workflow","llm","dsl","typescript","openai","groq","ollama","multi-agent","api-runner"],"repository":{"type":"git","url":"git+https://github.com/Neftedollar/ageflow.git"},"description":"OpenAI-compatible HTTP runner for ageflow (OpenAI, Groq, Together, Ollama, vLLM, LM Studio, Azure).","maintainers":[{"name":"neftedollar","email":"oildollar@gmail.com"}],"readme":"# @ageflow/runner-api\n\n[![npm](https://img.shields.io/npm/v/@ageflow/runner-api)](https://www.npmjs.com/package/@ageflow/runner-api)\n\nOpenAI-compatible HTTP runner for [ageflow](../../../README.md). Talks to any\n`/chat/completions` endpoint via `fetch()`. Supports multi-round tool calling\ninternally, pluggable session storage, and returns `ToolCallRecord[]` for\nobservability. Zero external dependencies.\n\n## Install\n\n```bash\nbun add @ageflow/runner-api\n```\n\n## Quick start\n\n```ts\nimport { registerRunner } from \"@ageflow/core\";\nimport { ApiRunner } from \"@ageflow/runner-api\";\n\nregisterRunner(\n  \"api\",\n  new ApiRunner({\n    baseUrl: \"https://api.openai.com/v1\",\n    apiKey: process.env.OPENAI_API_KEY!,\n    defaultModel: \"gpt-4o-mini\",\n  }),\n);\n```\n\nThen use `runner: \"api\"` in any `defineAgent` call:\n\n```ts\nimport { defineAgent } from \"@ageflow/core\";\nimport { z } from \"zod\";\n\nconst summarize = defineAgent({\n  runner: \"api\",\n  model: \"gpt-4o-mini\",\n  input: z.object({ text: z.string() }),\n  output: z.object({ summary: z.string() }),\n  prompt: (i) =>\n    `Summarize in one sentence as JSON {\"summary\": string}:\\n\\n${i.text}`,\n});\n```\n\n## Provider compatibility\n\n| Provider      | `baseUrl`                                                              |\n|---------------|------------------------------------------------------------------------|\n| OpenAI        | `https://api.openai.com/v1`                                            |\n| Groq          | `https://api.groq.com/openai/v1`                                       |\n| Together AI   | `https://api.together.xyz/v1`                                          |\n| Ollama        | `http://localhost:11434/v1`                                            |\n| vLLM          | `http://localhost:8000/v1`                                             |\n| LM Studio     | `http://localhost:1234/v1`                                             |\n| Azure OpenAI  | `https://<resource>.openai.azure.com/openai/deployments/<model>`      |\n\nFor Azure you must include `?api-version=...` directly in `baseUrl` — the runner\nappends `/chat/completions` to `baseUrl` as a path segment and does not merge\nquery parameters separately. Do **not** pass `api-version` via `headers`; Azure\nrejects requests where it appears only as a header.\n\nExample: `baseUrl: \"https://<resource>.openai.azure.com/openai/deployments/<model>?api-version=2024-02-01\"`\n\n## Configuration\n\n```ts\nnew ApiRunner({\n  // Required\n  baseUrl: \"https://api.openai.com/v1\",  // trailing slash is stripped automatically\n  apiKey: \"sk-...\",\n\n  // Optional\n  defaultModel: \"gpt-4o-mini\",   // used when spawn() args.model is not set\n  tools: {                       // tool registry — see Tool calling below\n    readFile: { description: \"...\", parameters: { ... }, execute: async (args) => ... },\n  },\n  sessionStore: myStore,         // custom SessionStore — see Session persistence below\n  maxToolRounds: 10,             // max tool-call loops before MaxToolRoundsError (default 10)\n  requestTimeout: 120_000,       // ms before AbortController fires (default 120 000)\n  headers: {                     // extra headers forwarded on every request\n    \"x-custom-header\": \"value\",  // e.g. custom tracing headers\n  },\n  fetch: myFetchImpl,            // injectable fetch (default: globalThis.fetch)\n})\n```\n\n## Tool calling\n\nRegister tools that the model may invoke. The runner loops internally until\nthe model stops requesting tool calls or `maxToolRounds` is reached.\n\n```ts\nimport { ApiRunner } from \"@ageflow/runner-api\";\nimport * as fs from \"node:fs/promises\";\n\nconst runner = new ApiRunner({\n  baseUrl: \"https://api.openai.com/v1\",\n  apiKey: process.env.OPENAI_API_KEY!,\n  tools: {\n    readFile: {\n      description: \"Read the contents of a file from disk\",\n      parameters: {\n        type: \"object\",\n        properties: { path: { type: \"string\", description: \"Absolute file path\" } },\n        required: [\"path\"],\n      },\n      execute: async ({ path }) => {\n        return await fs.readFile(String(path), \"utf-8\");\n      },\n    },\n    writeFile: {\n      description: \"Write content to a file\",\n      parameters: {\n        type: \"object\",\n        properties: {\n          path: { type: \"string\" },\n          content: { type: \"string\" },\n        },\n        required: [\"path\", \"content\"],\n      },\n      execute: async ({ path, content }) => {\n        await fs.writeFile(String(path), String(content), \"utf-8\");\n        return \"ok\";\n      },\n    },\n  },\n});\n\nconst result = await runner.spawn({\n  prompt: \"Read ./README.md and summarize it in one sentence.\",\n  tools: [\"readFile\"],            // subset of registered tools exposed to model\n});\n\nconsole.log(result.stdout);      // final model reply\nconsole.log(result.toolCalls);   // ToolCallRecord[] — every tool invocation\n```\n\n## Session persistence\n\nBy default each `spawn()` call gets a fresh UUID session handle and messages\nare stored in an `InMemorySessionStore` (lives for the lifetime of the\n`ApiRunner` instance). Pass a `sessionHandle` to resume a conversation:\n\n```ts\nconst first = await runner.spawn({ prompt: \"My name is Alice.\" });\n// first.sessionHandle === \"some-uuid\"\n\nconst second = await runner.spawn({\n  prompt: \"What is my name?\",\n  sessionHandle: first.sessionHandle,\n});\n// second.stdout === \"Your name is Alice.\"\n```\n\n### Custom `SessionStore` (e.g. Redis)\n\n```ts\nimport type { SessionStore } from \"@ageflow/runner-api\";\nimport type { ChatMessage } from \"@ageflow/runner-api\";\nimport { createClient } from \"redis\";\n\nconst redis = createClient();\nawait redis.connect();\n\nconst redisStore: SessionStore = {\n  async get(handle) {\n    const raw = await redis.get(`session:${handle}`);\n    return raw ? (JSON.parse(raw) as ChatMessage[]) : undefined;\n  },\n  async set(handle, messages) {\n    await redis.set(`session:${handle}`, JSON.stringify(messages), { EX: 3600 });\n  },\n};\n\nconst runner = new ApiRunner({\n  baseUrl: \"https://api.openai.com/v1\",\n  apiKey: process.env.OPENAI_API_KEY!,\n  sessionStore: redisStore,\n});\n```\n\n## Observability\n\n`RunnerSpawnResult.toolCalls` is a `ToolCallRecord[]` containing every tool\ninvocation made during the session:\n\n```ts\nconst result = await runner.spawn({ prompt: \"...\", tools: [\"readFile\"] });\n\nfor (const call of result.toolCalls ?? []) {\n  console.log(call.name);       // \"readFile\"\n  console.log(call.args);       // { path: \"./foo.ts\" }\n  console.log(call.result);     // \"export const ...\"\n  console.log(call.durationMs); // 12\n}\n```\n\nThe executor passes `toolCalls` through to `TaskMetrics` / `ExecutionTrace`\nwhen present, enabling end-to-end observability without extra instrumentation.\n\n## Validation\n\n`runner.validate()` hits `GET /models` and returns `{ ok, version?, error? }`.\nUseful for health-checks and pre-flight guards:\n\n```ts\nconst { ok, version, error } = await runner.validate();\nif (!ok) throw new Error(`API runner not reachable: ${error}`);\nconsole.log(\"First available model:\", version);\n```\n\n## Error types\n\n| Error class         | When thrown                                                       |\n|---------------------|-------------------------------------------------------------------|\n| `MaxToolRoundsError` | Tool-call loop exceeded `maxToolRounds`                          |\n| `ApiRequestError`   | HTTP response was non-2xx                                         |\n| `ToolNotFoundError` | Reserved — executor pre-flight; runner itself soft-errors unknown tools |\n\n```ts\nimport { MaxToolRoundsError, ApiRequestError } from \"@ageflow/runner-api\";\n\ntry {\n  await runner.spawn({ prompt: \"loop forever\", tools: [\"infiniteTool\"] });\n} catch (err) {\n  if (err instanceof MaxToolRoundsError) {\n    console.error(\"Too many tool rounds:\", err.message);\n  }\n}\n```\n\n## Using MCP servers\n\nPass MCP server configuration via `mcp.servers` on any `defineAgent` call. The\nAPI runner spawns each server as a stdio subprocess via\n`@modelcontextprotocol/sdk`. Tools are discovered at spawn time and registered\nin the tool-loop under the fully-qualified name `mcp__<server>__<tool>`.\n\n```ts\nimport { defineAgent, safePath } from \"@ageflow/core\";\nimport { z } from \"zod\";\n\nconst fileAgent = defineAgent({\n  runner: \"api\",\n  model: \"gpt-4o-mini\",\n  input: z.object({ query: z.string() }),\n  output: z.object({ result: z.string() }),\n  prompt: ({ query }) => query,\n  mcp: {\n    servers: [\n      {\n        name: \"filesystem\",\n        command: \"npx\",\n        args: [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/workspace\"],\n        // Allowlist — only these tools are exposed to the model\n        tools: [\"read_file\", \"list_directory\"],\n        // Refine — validate path args before forwarding to the server\n        refine: {\n          read_file: z.object({ path: safePath({ allowAbsolute: false }) }),\n        },\n        // ${env:VAR} is resolved at launch time by the executor\n        env: { NODE_ENV: \"${env:NODE_ENV}\" },\n        // Keep this server alive across spawn() calls on the same runner instance\n        reusePerRunner: true,\n      },\n    ],\n  },\n});\n```\n\n**Allowlist** (`tools`): when set, only the listed tools are added to the\ntool-loop registry. Unlisted tools never reach the model, and a post-dispatch\nguard rejects unexpected call attempts.\n\n**Refine** (`refine`): a map of tool name → Zod schema. Arguments are validated\nagainst the schema before the call is dispatched. Use `safePath()` to prevent\npath traversal.\n\n**Environment expansion** (`env`): values of the form `${env:VAR}` are replaced\nwith the corresponding process environment variable at launch time.\n\n### `reusePerRunner` — server lifecycle pooling\n\nBy default each `spawn()` call starts its own MCP server subprocesses and stops\nthem when the call completes. Set `reusePerRunner: true` on a server to keep it\nalive in a per-runner pool and reuse it across all `spawn()` calls on the same\n`ApiRunner` instance. This avoids repeated cold-start overhead for servers that\nare expensive to initialize.\n\n```ts\n// Server stays up across calls — warm on every spawn()\n{ name: \"filesystem\", command: \"npx\", args: [...], reusePerRunner: true }\n```\n\n### `runner.shutdown()` — draining the pool\n\n`runner.shutdown()` is **process-scoped** — it is called automatically by the\nAgentFlow CLI (`agentwf run`) and the server's `close()` method at process exit.\nYou do not need to call it manually when using those entry points.\n\nIf you are using `ApiRunner` directly (outside the CLI or server), call\n`shutdownAllRunners()` from `@ageflow/core` when your process exits:\n\n```ts\nimport { shutdownAllRunners } from \"@ageflow/core\";\n\nprocess.on(\"SIGTERM\", async () => {\n  await shutdownAllRunners();\n  process.exit(0);\n});\n```\n\n## API reference\n\n### `new ApiRunner(config: ApiRunnerConfig)`\n\nCreates a new runner instance. All config fields except `baseUrl` and `apiKey`\nare optional.\n\n### `runner.validate(): Promise<{ ok: boolean; version?: string; error?: string }>`\n\nChecks connectivity by calling `GET /models`. Returns `ok: false` on any\nerror (network, 4xx, 5xx) — never throws.\n\n### `runner.spawn(args: RunnerSpawnArgs): Promise<RunnerSpawnResult>`\n\nExecutes a prompt, optionally resuming a session, and loops until the model\nproduces a non-tool-call response. Returns `stdout` (final text), `sessionHandle`,\n`tokensIn`, `tokensOut`, and `toolCalls`.\n\n### `runner.shutdown(): Promise<void>`\n\nStops all pooled MCP server subprocesses (`reusePerRunner: true`) and clears\nthe pool. Per-spawn servers are already stopped by `spawn()` itself — only the\npool requires an explicit `shutdown()` call. Safe to call more than once.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}