15 Commits
Author SHA1 Message Date
Chad Hietala 460142bf26 Expose semantic execution hooks to libfx hosts
Signed-off-by: Chad Hietala <chad.hietala@vercel.com>
2026-10-15 09:43:27 -04:00
Pranit 1f510c93b1 Run libfx agents on a custom OpenAI-compatible provider
- Run a libfx agent on any server that speaks OpenAI Chat Completions by passing `provider: { name, baseUrl, models }`. Requests go to `{baseUrl}/chat/completions` through the host's `fetch`, with the CLI's own request and reply handling.
- Supply the provider's API key through the shared `credentials({ provider, sessionId })` callback, or omit it for a server that needs none. libfx adds the key only to that chat URL, so it never reaches the engine or a saved session.
- Check a custom provider's name, base URL and model details when the agent is created, require a `model`, and reject `onCredentials`, since a key is never refreshed.
- Continue a durable session on a custom provider in a new process. The crash test now covers Codex, Grok and a custom provider.
2026-10-11 04:20:12 -04:00
Pranit dabb6f2294 Run libfx agents on a Grok plan
- Run a libfx agent on Grok with `provider: "grok"`: model requests and the model list go to xAI's Grok endpoints through the host's `fetch` instead of AI Gateway.
- Supply Grok credentials through the shared `credentials({ provider, sessionId })` callback. libfx adds the token and account id only to Grok requests, so they never reach the engine or a saved session.
- Refresh Grok tokens five minutes before they expire and once after a 401, refuse a refreshed token for a different account, and pass new tokens to `onCredentials`.
- Continue a durable Grok session in a new process, which asks `credentials` for that session's credentials.
- Sign in with a Grok plan from `libfx/grok` with device code, or by pasting the callback address, and refresh tokens from there.
2026-10-11 02:42:37 -04:00
Pranit b9be2de170 Run libfx agents on Codex with ChatGPT sign-in
- Run a libfx agent on Codex with `provider: "codex"`: model requests and the model list go to ChatGPT's Codex endpoints through the host's `fetch` instead of AI Gateway.
- Supply each session's ChatGPT credentials through a `chatgpt` callback. libfx adds them only to Codex requests, so tokens never reach the engine or a saved session.
- Refresh ChatGPT tokens five minutes before they expire and once after a 401, and pass the new tokens to `onChatgptCredentials`.
- Continue a durable Codex session in a new process, which asks `chatgpt` for that session's credentials.
- Sign in with ChatGPT from `libfx/chatgpt` by pasting the callback address, or with device code where the workspace allows it, and refresh tokens from there.
2026-10-10 20:22:57 -04:00
Pranit 8de5bf9e9f Accept an app's World, ship types, and bound repeated deadline cut-offs
- `world()` from `libfx/durable-world` keeps sessions in a World the app
  creates, such as Workflow's Postgres World. `local()` and `vercel()` are
  built on it. libfx never starts or closes a World it was given, and agents
  that share one take its deliveries in turn instead of the last one taking
  over.
- `agent.newSessionId()` gives an id before the first prompt, every tool
  call receives `sessionId`, and `session(null)` throws like any other
  invalid id. The README states the id rule for each durability.
- TypeScript declarations for every entry point, wired through `exports` and
  checked under node16 and bundler resolution against the runtime exports.
- `createFxEngine()` names itself in its option errors, `createFxAgent()`
  refuses `env` when created, and the README lists what code written for
  0.0.12 now does differently.
- A step the deadline cuts off 3 times in a row is not run again: a cut-off
  call is answered as possibly run, and a model request cancels its turn.
  Records carry the step their turn is at, so continuing a cut-off model
  request counts as the same step. `session.deadline` reports `cutoffs`.
  The TLA+ model bounds it, a witness shows the endless rerun without the
  bound, and a new walk drives the code to the bound.
2026-10-08 22:27:30 -04:00
Pranit b0d83eb894 Make libfx sessions durable
- `createFxAgent()` returns the agent at once instead of a promise, and does no I/O until a session runs a turn.
- `agent.session(id)` opens a session, and `session.prompt()` returns a turn view with `accepted`, `result`, async iteration over its events, and an NDJSON `readable`.
- Sessions are durable by default: `vercel()` on Vercel, `local()` files in Node.js elsewhere, and `memory()` in browsers. The `durability` option picks one.
- `libfx/durable-local` and `libfx/durable-vercel` bundle their World, so an app installs no other package.
- A turn whose process crashes, redeploys, or reaches its function deadline continues from its last record in the next process that gets work for the session.
- On Vercel, a turn stops at its next model request 30 seconds before the function deadline and continues in a new invocation from the same queue message.
- A model request or tool call still running 2 seconds before the deadline is cut off, and `onEvent` receives `session.deadline`.
- One process runs a session's turns at a time, and a prompt for a busy session queues behind the running turn.
- A process that froze and was replaced stops at its next write and never starts a tool with effects, and `onEvent` receives `session.fenced`.
- After an interruption, a call to an `idempotent: true` tool runs again. Any other call never reruns, and the model gets an error saying it may have partly run.
- `executionId` is the same each time a call runs, including after a crash.
- A prompt sent again with the same `messageId` starts nothing new: its view follows the original turn, or resolves with `repeated: true`.
- `session.stream(cursor)` replays a session's events from any cursor on any server, with `turn_start`, `turn_end`, `turn_resume`, and `turn_yield` lines.
- Every reader of a session's stream shows the same lines, because lines a replaced worker lands late are hidden.
- `session.steer()` and `session.cancel()` reach the session's running turn, and `session.resume()` continues a turn a stopped process left open.
- Every turn end and yield saves a checkpoint, so continuing a session reads one checkpoint and the records after it.
- Checkpoints record the libfx version, tool set, and model. A session or checkpoint saved under different ones still loads, and `onEvent` receives `checkpoint.mismatch`.
- `session.checkpoint()` exports a session's history, and the `checkpoint` option starts a new agent's session from it.
- `agent.wakeHandler()` is the queue delivery route an app mounts on Vercel and subscribes to `__libfx_wkf_workflow_session` in `vercel.json`.
- On Vercel, libfx authenticates to the AI Gateway with the deployment's OIDC token when neither `apiKey` nor `AI_GATEWAY_API_KEY` is set.
- `createFxEngine()` accepts a `persistence` store, and `createMemoryPersistence()` provides one in memory. A store that rejects a stale append with `FxFencedError` stops a second writer.
- A turn whose store append fails stops at once with `FX_JOURNAL_APPEND_FAILED`, and the agent refuses later prompts.
2026-10-07 01:47:00 -04:00
Pranit b031612036 Reuse resolved model metadata in libfx
Resolve selected capabilities during configuration and carry a scoped,
expiring descriptor into fresh agents. Preserve kernel validation without
per-message catalog discovery.

Complete consumed native HTTP responses under bounded cleanup instead of
aborting successful streams before EOF.
2026-10-02 13:08:37 -04:00
Pranit 2264cdc587 Fix libfx loading in Node deployments 2026-09-06 13:18:36 -04:00
Pranit 2bd1828fc1 Stream SDK output with bounded backpressure 2026-09-04 08:50:03 -04:00
Pranit 21dc542da2 Simplify the libfx kernel
Preserve caller-built bounded context projections.
Collapse the headless SDK to one session and active turn.
Remove duplicate lifecycle and startup state while retaining checkpoint freshness.
Include optional adapters in local package staging.
2026-09-02 01:06:49 -04:00
Pranit 51bfe627b1 Fix embedded Node runtime boundaries
Honor host-owned startup roots and propagate native runtime failures through the JavaScript adapter.

Discard canceled fetches before reuse and include the project license in package artifacts.
2026-08-16 13:33:35 -04:00
Pranit 09deb7f30d Embed fx in Node.js
Add a Node-API addon for running headless fx agents inside Node.js while keeping fetch streaming and cancellation in JavaScript.

Expose Node and browser package entry points with WebAssembly fallback and terminal support. Build, test, and package native macOS/Linux addons alongside ReleaseSmall WebAssembly artifacts.
2026-08-16 04:06:49 -04:00
Pranit 76513aba4b Use coding agent gateway routes 2026-08-15 19:08:42 -04:00
Pranit 37279a8da4 Send session identity headers with agent requests
Propagate the active session ID through normal and Vision provider requests, then derive matching x-session-id and x-session-affinity headers in native and JS-host transports.
2026-08-12 15:21:34 -04:00
Pranit 439f83ce94 Initial commit 2026-08-11 17:29:04 -04:00