Fragola Class
Fragola API Reference
Constructor
constructor(private clientOptions: ClientOptions, private globalStore: Store<TGlobalStore> | undefined = undefined, sdkClass: typeof OpenAI = OpenAI)Properties
sdkClass
Returns the OpenAI SDK constructor used by this Fragola instance.
get sdkClass()sdk
Returns the OpenAI client instance created from this Fragola configuration.
get sdk()options
Returns the client options configured on this Fragola instance.
get options()store
Acess the instance default global store.
get store(): Store<TGlobalStore> | undefinedMethods
setSdkOpts
Set the options for the underlying sdk. Can be used to refresh the options. Will re-instanciate the sdk
setSdkOpts(clientOptions: OpenaiClientOptions)agent
Create a new agent attached to this Fragola instance.
The returned agent uses this instance's client configuration and can access its global store.
opts: Agent configuration. Returns:A new agent instance.
Example
```ts
const fragola = new Fragola({
model: "gpt-5.4"
});
const agent = fragola.agent({
name: "assistant",
description: "Minimal assistant",
instructions: "You are a helpful assistant."
});
```typescript
agent<TMetaData extends DefineMetaData<any> = {}, TStore = {}>(opts: CreateAgentOptions<TStore>): Agent<TMetaData, TGlobalStore, TStore>getStore
Returns the instance (global) store or a namespaced store casted as T. Recommended when accessing the store from outside an agent store.
namespace: The namespace of the store to access (optional).
getStore<T extends StoreLike<any> = {}>(namespace?: string): Store<T> | undefinedaddStore
Add a namespaced store to the Fragola instance so agents can access it via getStore(namespace).
store: The store to add (must have a namespace defined).
addStore(store: Store<any>): voidremoveStore
Remove a namespaced store from the Fragola instance.
namespace: The namespace of the store to remove
removeStore(namespace: string): voidjson
Runs a one-off JSON extraction with a temporary agent.
If options is omitted, Fragola creates a minimal extraction agent for
this call and returns only the schema parse result.
query: The extraction prompt and Zod schema.options: Optional agent options to use instead of the default extraction agent. Returns:The Zod safe-parse result for the assistant response.
Example
```ts
const result = await fragola.json({
content: "my name is Ada",
name: "extract_person",
schema,
});
if (result.success) {
console.log(result.data);
}
```typescript
async json<S extends ZodSchema = ZodSchema>(query: JsonQuery<S>, options: CreateAgentOptions | undefined = undefined): Promise<SafeParseResult<unknown, Infer<S>>>Agent Class
Agent API Reference
Constructor
constructor(
private opts: CreateAgentOptions<TStore>,
private globalStore: Store<TGlobalStore> | undefined = undefined,
openai: OpenAI,
forkOf: string | undefined = undefined,
instance: Fragola,
state = Agent.defaultAgentState as AgentState<TMetaData>,
)Properties
defaultAgentState
public static defaultAgentState: AgentState = {
messages: [],
stepCount: 0,
status: "idle"
}forkOf
Returns the parent agent id when this agent was created with fork().
get forkOf()context
public context = (() => {
const _this = this;
return new class extends AgentContext<TMetaData, TGlobalStore, TStore> {
get state() { return _this.state; }
get options() { return _this.options; }
get raw() {
return {
updateMessages: (...args: Parameters<typeof _this.updateMessages>) => _this.updateMessages(...args)
};
}
get store() { return _this.opts.store as Store<TStore>; }
get messagesParser() { return messagesUtils<TMetaData>(() => _this.state.messages); }
get instance() { return _this.#instance }
getStore<T extends StoreLike<any>>(namespace?: string): Store<T> | undefined {
let context = namespace ? _this.#namespaceStore.get(namespace) : _this.options.store;
if (context)
return context as unknown as Store<T>;
return undefined;
}
addStore(store: Store<any>): void {
_this.addStore(store);
}
removeStore(namespace: string): void {
_this.removeStore(namespace);
}
get systemPrompt(): string {
return _this.mergedInstructions;
}
setInstructions(instructions: string, scope?: string): void {
// If a scope is provided, context scoped instructions, otherwise update the default instructions
if (scope) {
if (scope == '*')
throw new BadUsage("'*' is a reserved instructions scope and cannot be used.");
_this.instructionScopes.set(scope, instructions);
} else {
_this.opts.instructions = instructions;
}
// Refresh cached merged instructions
_this.updateMergedInstructionsCache();
}
instructions(scope?: string): string | undefined {
if (scope) {
if (scope == '*')
return _this.mergedInstructions;
return _this.instructionScopes.get(scope);
}
return _this.opts.instructions ?? undefined;
}
removeInstructions(scope: string): boolean {
if (scope == '*')
throw new BadUsage("'*' is a reserved instructions scope and cannot be removed.");
const existed = _this.instructionScopes.delete(scope);
if (existed)
_this.updateMergedInstructionsCache();
return existed;
}
setOptions(options: SetOptionsParams): void {
_this.setOptions(options);
}
async stop(): Promise<{ [STOP]: true }> {
await _this.stop();
return {
[STOP]: true
}
}
stopSync(): { [STOP]: true } {
_this.stopSync();
return {
[STOP]: true
}
}
updateTools(callback: (prev: Tool[]) => Tool[]): void {
const updatedTools = callback(_this.opts.tools ?? []);
_this.opts.tools = updatedTools;
_this.toolsToModelSettingsTools();
}
}
})()[FORK_FRIEND]
[FORK_FRIEND] = {
setRegisteredEvents: this.setRegisteredEvents,
getRegisteredEvents: () => this.registeredEvents
}id
Returns the unique id of this agent instance.
get id()state
Returns the current in-memory state for this agent.
get state()options
Returns the current configuration options for this agent.
get options()Methods
fork
Creates a new agent from the current one.
The fork gets a new id, copies the current options, state, hooks, and registered
events, and sets forkOf to this agent's id. The OpenAI client and global context
are shared. If this agent has a local context, the fork receives a new context
instance seeded with the same value.
Returns: A new agent initialized from the current agent.
fork()setOptions
Updates the agent's options.
Note: Can only be called when agent status is "idle".
The name and messages properties are omitted.
options: The new options to set, as a SetOptionsParams object. Throws:BadUsageWhen called while agent is not idle (generating or waiting).
setOptions(options: SetOptionsParams)init
Waits for all pending hook setup to finish without executing a step.
async init()step
Continues execution from the current message history for one or more steps.
Use this when messages were seeded manually or when you want to continue an in-progress model/tool loop without appending a new user message first.
stepParams: Optional per-call limits and step overrides. Returns:The updated agent state after execution completes.
Example
```ts
const agent = fragola.agent({
name: "assistant",
description: "Minimal assistant",
instructions: "You are a helpful assistant",
messages: [{ role: "user", content: "Say hello once." }],
});
await agent.step();
```typescript
async step(stepParams?: StepParams)resetStepCount
Resets the internal step counter to 0 without changing messages or status.
resetStepCount()reset
Resets the agent to an idle state and replaces its message history.
params: Optional replacement messages for the new state. Throws:BadUsageWhen called while the agent is not idle.
reset(params: ResetParams = { messages: [] })stop
Stops the current agent execution. This will abort any ongoing API calls and prevent further tool execution.
async stop()stopSync
Requests cancellation of the current run without awaiting completion.
stopSync()json
Appends a user message, requests structured JSON output, and validates it against a Zod schema.
query: The user prompt, schema, and optional per-call step overrides. Returns:The schema validation result together with the final agent state.
Example
```ts
const result = await agent.json({
content: "my name is Ada",
name: "extract_person",
schema,
});
if (result.success) {
console.log(result.data);
}
```typescript
async json<S extends ZodSchema = ZodSchema>(query: JsonQuery<S>): Promise<JsonResult<S, TMetaData>>userMessage
Appends a user message to the messages and executes the agent for one or more steps. Parameters:
query: The user message and optional per-call step controls. SeeUserMessageQuery
Returns: Promise<AgentState> - The updated agent state after processing the message and any model/tool steps.
Example
// 1) Minimal text message
await agent.userMessage({ content: "Say hello" });
// 2) Multi-part content (text + image)
await agent.userMessage({
content: [
{ type: "text", text: "What's in this image?" },
{ type: "image_url", image_url: { url: "https://example.com/cat.png" } }
]
});
// 3) Limit the number of steps for this turn
await agent.userMessage({
content: "Compute 2+2, then stop.",
step: { by: 1 } // will stop execution after 1 turn (1 llm response maximum)
});
// 4) Override model settings for this call (without changing agent defaults)
await agent.userMessage({
content: "Answer concisely.",
step: { modelSettings: { temperature: 0 } }
});
async userMessage(query: UserMessageQuery<TMetaData>): Promise<AgentState>watch
Register a state watcher for a given watch event id. Returns an unsubscribe function that removes the registered watcher.
Example
const off = agent.watch('state', ({ context }) => {
console.log('State updated:', context.state);
});
// later
off();
watch<TEventId extends AgentEventWatchId>(eventId: TEventId, callback: eventIdToCallback<TEventId, TMetaData, TGlobalStore, TStore>)watchState
Register a handler that watches agent state updates.
State watchers do not return a value and cannot intercept or mutate state. Use these for side-effects such as metrics, logging, or UI updates.
Example
agent.watchState(({ context }) => {
console.log('stepCount', context.state.stepCount);
});
watchState(callback: EventWatchState<TMetaData, TGlobalStore, TStore>)on
Register a handler for a given event id. Returns an unsubscribe function that removes the registered handler.
Example
// listen to userMessage events
const off = agent.on('userMessage', (message, context) => {
// inspect or transform the message
return { ...message, content: message.content.trim() };
});
// later
off();
on<TEventId extends AgentOnEventId>(eventId: TEventId, callback: eventIdToCallback<TEventId, TMetaData, TGlobalStore, TStore>)onToolCall
Register a tool result handler.
This event runs after before:toolCall resolves the current config and after the tool
handler (or an injected result) produces a payload. Each callback receives the current payload
and may transform it before it is exposed to later toolCall handlers, after:toolCall,
and the tool message appended to state.
Example
agent.onToolCall(({ result, params, tool }) => {
if (tool.name !== "getWeather") return result;
if (!result.success) return result;
return {
success: true,
data: {
requestedLocation: params.location,
data: result.data,
},
};
});
onToolCall(callback: EventToolCall<TMetaData, TGlobalStore, TStore>)onAiMessage
Register an assistant message handler.
This event runs for streamed partial assistant messages and for the final assistant message.
During streaming, finish_reason is null until the stream completes.
Return a new assistant message to replace the current one.
Example
agent.onAiMessage(({ message, finish_reason }) => {
if (finish_reason === null) return message;
if (typeof message.content !== "string") return message;
return {
...message,
content: message.content.trim() + "\n\n(checked)",
};
});
onAiMessage(callback: EventAiMessage<TMetaData, TGlobalStore, TStore>)onUserMessage
Register a user message event handler.
Called when a user message is appended to the messages. Handlers may return a modified user message which will be used instead of the original.
Example
agent.onUserMessage(({ message, context }) => {
// enrich user message with metadata
return { ...message, content: message.content.trim() };
});
onUserMessage(callback: EventUserMessage<TMetaData, TGlobalStore, TStore>)onBeforeStep
Register a before step event handler.
Called before a step is executed.
Example
agent.onBeforeStep(({ options, context }) => {
console.log('Before step', options);
});
onBeforeStep(callback: EventBeforeStep<TMetaData, TGlobalStore, TStore>)onAfterStep
Register an after step event handler.
Called after a step is executed.
Example
agent.onAfterStep(({ options, newMessages, stepsTaken, context }) => {
console.log('After step', options, newMessages, stepsTaken);
});
onAfterStep(callback: EventAfterStep<TMetaData, TGlobalStore, TStore>)onBeforeModelInvocation
Register a handler that can alter model invocation config before the request is made.
The callback receives the current invocation config and may:
- return
{ modelSettings, clientOptions }to override the request settings - return
{ injectMessage }to bypass the API call with a final assistant message - return
{ injectResponse }to provide a custom SDK response
Example
agent.onBeforeModelInvocation(() => ({
injectMessage: { content: "hello from cache" },
}));
onBeforeModelInvocation(callback: EventBeforeModelInvocation<TMetaData, TGlobalStore, TStore>)onAfterModelInvocation
Register an after model invocation event handler.
Called after the model is invoked.
Example
agent.onAfterModelInvocation(({ message, context }) => {
console.log('After model invocation', message);
});
onAfterModelInvocation(callback: EventAfterModelInvocation<TMetaData, TGlobalStore, TStore>)onBeforeToolCall
Register a handler that can alter a tool call before execution.
The callback receives { params } before the tool handler runs. It may return a new
{ params } object to rewrite validated arguments or { injectConfig } with a full
ToolCallPayload to bypass the handler entirely.
Example
agent.onBeforeToolCall(({ config, tool }) => {
if (tool.name !== "search" || !("params" in config)) return config;
return { params: { ...config.params, limit: 5 } };
});
onBeforeToolCall(callback: EventBeforeToolCall<TMetaData, TGlobalStore, TStore>)onAfterToolCall
Register an after tool call event handler.
Called after a tool payload is finalized.
Example
agent.onAfterToolCall(({ result, params, tool, context }) => {
console.log('After tool call', tool.name, result);
});
onAfterToolCall(callback: EventAfterToolCall<TMetaData, TGlobalStore, TStore>)onModelInvocation
Register a model invocation handler.
Use this event to inspect or transform data produced by the model before it is turned into the assistant message stored in state.
Handle the payload as a discriminated union by checking invocation.kind:
"chunk": streamed delta payload. The callback receives{ kind, chunk, primaryChoice, delta }before that chunk is merged into the partial assistant message."completion": full assistant message payload. The callback receives{ kind: "completion", data }, wheredatais the complete assistant message.
For kind === "chunk", you may:
- return the raw chunk to replace it directly
- return
{ injectChunk, merge?: true }to update the whole chunk - return
{ injectPrimary, merge?: true }to updatechoices[0] - return
{ injectDelta, merge?: true }to updatechoices[0].delta - set
merge: falseon anyinject*object to replace that target instead of merge-patching it
For kind === "completion", return an updated message object to replace it.
Example
agent.onModelInvocation((payload) => {
if (payload.kind === "completion") {
// payload.data.content can be in some cases an array
if (typeof payload.data.content !== "string") return payload.data;
return {
...payload.data,
content: payload.data.content.trim(),
};
}
if (!payload.delta?.content) return payload.chunk;
return {
injectDelta: {
content: invocation.delta.content.replace("[DEBUG]", ""),
},
};
});
onModelInvocation(callback: EventModelInvocation<TMetaData, TGlobalStore, TStore>)use
Attach a hook to this agent.
Hooks receive the agent instance and may register event handlers or otherwise augment the agent's behavior.
hook: A FragolaHook to attach to the agent Returns:The agent instance (chainable)
Example
```ts
import { Hook } from "@fragola-ai/agent/hook";
const loggingHook = Hook((agent) => {
agent.watchState(({ context }) => {
console.log(context.state.status);
});
});
const agent = fragola.agent({...}).use(loggingHook, "logging");
// agent is returned so additional configuration/calls can be chained
```typescript
use(hook: FragolaHook, name?: string)hasHook
Returns whether a named hook is registered. Pending hooks count as registered.
hasHook(name: string): booleanremoveHook
Removes a named hook, waits for pending setup to finish, and runs its disposer.
async removeHook(name: string): Promise<void>dispose
Removes every hook currently registered on the agent.
async dispose(): Promise<void>AgentContext Class
AgentContext API Reference
Properties
state
The current state of the agent.
abstract get state(): AgentState<TMetaData>options
The configuration options for the agent.
abstract get options(): AgentOptionsraw
Raw methods for advanced context manipulation
abstract get raw(): ContextRaw<TMetaData>store
Acess the agent's default local store.
abstract get store(): Store<TStore>messagesParser
Live parser helpers bound to the current state.messages.
abstract get messagesParser(): MessagesParser<TMetaData>instance
Return the Fragola instance which created this agent
abstract get instance(): Fragola<TGlobalStore>systemPrompt
Returns the agent system prompt exactly as sent to the llm. The system prompt is the result of all the instructions scopes merged
abstract get systemPrompt(): stringMethods
addStore
Add a store that has a namespace. Can be accessed with getStore method.
store: The store to add
abstract addStore(store: Store<any>): voidupdateTools
Updates the agent's tool list using a callback.
callback: Function that receives the current tools and returns the updated list.
Example
agent.context.updateTools(prev => [...prev, newTool]);
agent.context.updateTools(prev => prev.filter(tool => tool.name !== "oldTool"));
abstract updateTools(callback: (prev: Tool[]) => Tool[]): voidremoveStore
Remove a store by its namespace.
namespace: The namespace of the store to remove
abstract removeStore(namespace: string): voidgetStore
Returns the agent's local store or namespace store casted as T. Recommended when accessing the store from a hook.
namespace: The namespace of the store to access (optional).
abstract getStore<T extends StoreLike<any> = {}>(namespace?: string): Store<T> | undefinedsetInstructions
Sets the current instructions for the agent.
instructions: The new instructions as a string.
abstract setInstructions(instructions: string, scope?: string): voidinstructions
Returns the instructions for a given scope.
scope: The instructions scope, leave empty to get the default scope (optional)
abstract instructions(scope?: string): string | undefinedremoveInstructions
Remove the instructions for a given scope.
scope: The instructions scope to remove Returns:a boolean, true = removed, false = scope do not exist
abstract removeInstructions(scope: string): booleansetOptions
Updates the agent's options.
note: the name, fork and messages properties are ommited
options: The new options to set, as a SetOptionsParams object.
abstract setOptions(options: SetOptionsParams): voidstop
Stop the agent execution
abstract stop(): Promise<{[STOP]: true}>stopSync
Stop the agent execution - Sync
abstract stopSync(): {[STOP]: true}Events & Payloads
Events & Payloads
Coming soon.
Store & Utility Functions
Store & Utility Functions
Coming soon.