@statelyai/agent
Version:
Stateful agents that make decisions based on finite-state machine models
85 lines (76 loc) • 1.92 kB
text/typescript
import { AnyActor, AnyMachineSnapshot, fromPromise } from 'xstate';
import {
AnyAgent,
AgentDecideOptions,
AgentDecisionLogic,
AgentDecisionInput,
AgentPlanner,
AgentPlan,
} from './types';
import { simplePlanner } from './planners/simplePlanner';
export async function agentDecide<T extends AnyAgent>(
agent: T,
options: AgentDecideOptions
): Promise<AgentPlan<any> | undefined> {
const resolvedOptions = {
...agent.defaultOptions,
...options,
};
const {
planner = simplePlanner as AgentPlanner<any>,
goal,
events = agent.events,
state,
machine,
model = agent.model,
...otherPlanInput
} = resolvedOptions;
const plan = await planner(agent, {
model,
goal,
events,
state,
machine,
...otherPlanInput,
});
if (plan?.nextEvent) {
agent.addPlan(plan);
await resolvedOptions.execute?.(plan.nextEvent);
}
return plan;
}
export function fromDecision(
agent: AnyAgent,
defaultInput?: AgentDecisionInput
): AgentDecisionLogic<any> {
return fromPromise(async ({ input, self }) => {
const parentRef = self._parent;
if (!parentRef) {
return;
}
const snapshot = parentRef.getSnapshot() as AnyMachineSnapshot;
const inputObject = typeof input === 'string' ? { goal: input } : input;
const resolvedInput = {
...defaultInput,
...inputObject,
};
const contextToInclude =
resolvedInput.context === true
? // include entire context
parentRef.getSnapshot().context
: resolvedInput.context;
const state = {
value: snapshot.value,
context: contextToInclude,
};
const plan = await agentDecide(agent, {
machine: (parentRef as AnyActor).logic,
state,
execute: async (event) => {
parentRef.send(event);
},
...resolvedInput,
});
return plan;
}) as AgentDecisionLogic<any>;
}