@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
74 lines • 3.19 kB
JavaScript
/** The receipt an `agent`-kind call returns the moment its delegate is under way. */
export function detachedStarted(args) {
return {
detached: true,
status: 'started',
agent: args.agent,
runId: args.runId,
note: `The "${args.agent}" agent is now working on this in the background. Its answer is NOT part of this turn and will arrive in this conversation as a separate message when it is ready. Tell the user the work has started; do not state or guess what it will find.`,
};
}
/** The outcome written onto the delegating tool call when a detached run finishes its answer. */
export function detachedDelivered(args) {
return {
detached: true,
status: 'delivered',
agent: args.agent,
runId: args.runId,
text: args.text,
};
}
/**
* The outcome written onto the delegating tool call when a detached run never produced an answer.
* Written by the RUNNER, not the loop: a run that crashed or was stopped cannot record its own ending.
*/
export function detachedUnsettled(args) {
return {
detached: true,
status: args.status,
agent: args.agent,
runId: args.runId,
...(args.error !== undefined ? { error: args.error } : {}),
};
}
/**
* Settle the delegation a detached run was started for, when that run ends with no answer.
*
* Two writes, because a reader needs both: the tool-call row, so a governance surface stops counting
* it as in flight, and a MESSAGE in the delegating thread, so the person who asked finds out. A
* delivered answer already arrives as a message; without this, failure is the one outcome that
* silently never does, and the conversation shows "started" for ever.
*
* Called by the RUNNER, never the loop. Skipped when the thread is gone (as delivery is), and when the
* thread already holds a message from this run — so a second settle is a no-op.
*/
export async function settleUnsettledDelegation(args) {
const { store, delivery, agent, runId, status } = args;
const thread = await store.getThread(delivery.threadId);
// Gone, or already told: a run posts into the delegating thread once, whichever path settles it
// (its own answer, its failure, or a Stop that reached the runner after the body had ended).
if (thread === null || thread.messages.some((message) => message.runId === runId)) {
return;
}
await store.appendMessage({
threadId: delivery.threadId,
role: 'assistant',
content: status === 'cancelled'
? `The "${agent}" agent was stopped before it could answer.`
: `The "${agent}" agent stopped before it could answer: ${args.error ?? 'unknown error'}`,
agentName: agent,
runId,
});
await store.updateToolCall({
toolCallId: delivery.toolCallId,
...(args.parentRunId !== undefined ? { runId: args.parentRunId } : {}),
status: 'executed',
output: detachedUnsettled({
agent,
runId,
status,
...(args.error !== undefined ? { error: args.error } : {}),
}),
});
}
//# sourceMappingURL=delegation.js.map