@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
63 lines • 2.86 kB
JavaScript
import { createAgentClient } from './client.js';
import { agUiChatStream as baseAgUiChatStream, } from './core/ag-ui-backend.js';
import { csrfHeaders } from './csrf.js';
/**
* the local React adapter's `agUiChatStream`, with `@adonisjs/shield`'s CSRF header read
* from the page on every call (yours, in `options.headers`, win over it).
*
* The re-exported original sends only the headers it is handed, captured once — and shield refuses
* a `POST` without a current token, so behind an Adonis session it would be refused on the first
* send, or on the first send after the token rotated.
*/
export function agUiChatStream(request, options) {
return baseAgUiChatStream(request, {
...options,
headers: { ...csrfHeaders(), ...options.headers },
});
}
function agentPath(path) {
const trimmed = (path ?? '/agent').replace(/\/+$/, '');
return trimmed.startsWith('/') || trimmed === '' ? trimmed : `/${trimmed}`;
}
/**
* A backend whose chat turns run over AG-UI 1.0 (`agUiAdapter()` on the server) while everything
* else — threads, the queue, approvals, uploads — stays on this package's REST routes:
*
* ```tsx
* import { AgentProvider, agUiBackend } from '@adonis-agora/agent/react'
*
* <AgentProvider backend={agUiBackend()}><Chat /></AgentProvider>
* ```
*
* Every AG-UI request carries the session cookie, the CSRF header (read per request) and the
* connection's own `headers` / `getHeaders`. Point `url` at any other AG-UI 1.0 producer to drive
* that one instead.
*/
export function agUiBackend(options = {}) {
const { url, client, agUi, ...connection } = options;
const rest = client ?? createAgentClient(connection);
const endpoint = url ?? `${(connection.baseUrl ?? '').replace(/\/+$/, '')}${agentPath(connection.path)}/ag-ui`;
const baseFetch = connection.fetch ?? globalThis.fetch.bind(globalThis);
const fetchWithConnection = async (input, init) => baseFetch(input, {
...init,
credentials: connection.credentials ?? 'same-origin',
headers: {
...csrfHeaders(),
...connection.headers,
...((await connection.getHeaders?.()) ?? {}),
...init?.headers,
},
});
const openChatStream = (request) => baseAgUiChatStream(request, { ...agUi, url: endpoint, fetch: fetchWithConnection });
// A Proxy rather than a spread: the default backend is a class instance, whose methods live on
// its prototype, where `{ ...client }` would not find them.
return new Proxy(rest, {
get(target, property) {
if (property === 'openChatStream')
return openChatStream;
const value = Reflect.get(target, property, target);
return typeof value === 'function' ? value.bind(target) : value;
},
});
}
//# sourceMappingURL=ag-ui.js.map