Client
Use flue-eve/client anywhere you want the Eve session protocol without
hand-writing POST requests and NDJSON stream parsing: scripts, evals, tests,
backend jobs, or custom UIs.
Quick start
import { Client } from 'flue-eve/client'
const client = new Client({ host: 'http://127.0.0.1:5173' })
const session = client.session()
const response = await session.send('Hello')
const result = await response.result()
console.log(result.status)
console.log(result.message)Create a client
const client = new Client({
host: '', // same-origin by default
auth: {
bearer: async () => await getAccessToken(),
},
headers: async () => ({
'x-request-id': crypto.randomUUID(),
}),
maxReconnectAttempts: 3,
})host is the origin where /eve/v1/* is mounted. Use "" for same-origin
browser code and a full URL for scripts or server-to-server calls.
Check health and info
const health = await client.health()
console.log(health.status, health.workflowId)
const info = await client.info()
console.log(info.agent?.name, info.tools)Non-2xx responses throw ClientError, which carries the HTTP status and
response body.
Start a session
const session = client.session()
const response = await session.send({
message: 'Hello',
agent: 'assistant',
outputSchema: {
type: 'object',
properties: {
answer: { type: 'string' },
},
},
clientContext: {
userId: 'user-123',
tier: 'pro',
},
})
for await (const event of response) {
console.log(event.type)
}After send(), the session state contains the returned sessionId,
continuationToken, and next streamIndex.
Multi-turn conversations
Use the same ClientSession for follow-up turns:
const session = client.session()
await (await session.send('What is 2+2?')).result()
await (await session.send({ message: 'Now multiply by 3' })).result()
await (await session.send({ message: 'Add 10 to that' })).result()Each send() call reuses the session's sessionId and continuationToken.
Wait for a result
send() returns a MessageResponse. Call result() when you want the final
turn summary instead of handling every stream event:
const response = await session.send('Summarize this file')
const result = await response.result()
console.log(result.status) // "completed" | "failed" | "waiting"
console.log(result.message) // final assistant text, when present
console.log(result.data) // structured output, when outputSchema is usedWhen outputSchema is used, type the expected result:
const response = await session.send<{ colors: string[] }>({
message: 'List 3 colors',
outputSchema: {
type: 'object',
properties: {
colors: { type: 'array', items: { type: 'string' } },
},
},
})
const result = await response.result()
console.log(result.data?.colors)Stream events
MessageResponse is also an async iterable:
const response = await session.send('Explain the plan')
for await (const event of response) {
switch (event.type) {
case 'message.appended':
process.stdout.write(String(event.data.messageDelta ?? ''))
break
case 'actions.requested':
console.log('Actions requested:', event.data.actions)
break
case 'action.result':
console.log('Action result:', event.data.result)
break
case 'session.waiting':
console.log('Turn complete')
break
}
}Reconnect after disconnect
The session stores the next stream index as it consumes events. To resume an
existing stream, restore the session state and call stream():
const restored = client.session(savedSessionState)
for await (const event of restored.stream()) {
console.log(event.type)
}You can also override the replay point:
for await (const event of restored.stream({ startIndex: savedSessionState.streamIndex })) {
console.log(event)
}The streamIndex is owned by the server-side journal, ensuring consistent
replay even though Flue uses its own stream offsets internally.
Authentication
For production, provide bearer or basic auth:
const client = new Client({
host: 'https://api.example.com',
auth: { bearer: process.env.EVE_AUTH_TOKEN ?? '' },
})The token is sent as Authorization: Bearer <token> on every request,
including reconnects.
Save and load session state
Persist session cursors to resume after reloads:
import { loadSessionState, saveSessionState } from 'flue-eve/client'
saveSessionState(localStorage, session.state)
const saved = loadSessionState(localStorage)
if (saved) {
const resumed = new Client({ host: '' }).session(saved)
await resumed.send('Continue from here')
}See React for the hook wrapper that handles this pattern inside a browser UI.