/** * What started an agent's turn — the "trigger" of everything it posts from * that turn (agent-provenance audit 2026-10-14). * * The harness writes every prompt into a turn (terminal `/write` and * `/deliver`, `sendMessageToAgent`). Each delivery is classified here into a * finer kind than {@link classifyDelivery} (which lumps restarts, reminders, * app changes and agent-to-agent messages into `system`), with the sending * agent when another agent wrote it. The last trigger of each session is kept * in memory, so a reply posted from that turn can say why it exists. * * Agent-to-agent sends are noted when the sender's request arrives * ({@link TurnTriggerTracker.noteSender}) and matched to the delivery by text, * so a message queued while the target was busy keeps its sender. * * @module services/trace/turn-trigger */ import { type MessageRoute } from '../orc/message-route.js'; /** Fine-grained kinds of what started a turn. */ export declare const TURN_TRIGGER_KINDS: readonly ["owner_message", "agent_message", "delegated_result", "dispatch", "redelivery", "follow_up", "owner_report_due", "follow_through", "stale_item", "decision", "restart", "scheduled", "app_change", "status", "system"]; /** What started a turn. */ export type TurnTriggerKind = (typeof TURN_TRIGGER_KINDS)[number]; /** A classified delivery. */ export interface ClassifiedTrigger { triggerKind: TurnTriggerKind; /** Work item the prompt names (`[CREWLY-DISPATCH] WorkItem `, task recovery) */ workItemId?: string; /** Ticket or decision label the prompt names (`TKT-12`, `D-4`) */ ticket?: string; /** Chat conversation of an owner message (`[CHAT:]`) */ conversationId?: string; /** Slack thread key of an owner message (`[SLACK-THREAD:]`), when it names one */ thread?: string; /** * The destination the message carries (message-route.ts): the route token * of an agent message or a delegated result. The answer to the whole * chain goes there. */ route?: MessageRoute; /** Sending agent named by the text itself (`[RESULT] From `) */ textSender?: string; } /** The trigger of a session's current turn. */ export interface TurnTrigger extends ClassifiedTrigger { /** Agent session that sent it, for `agent_message` */ sender?: string; /** Run trace the delivery joined, if any */ traceId?: string; /** * What started the chain: the trigger kind of the first hop. For an * agent message, the sender's own trigger kind (and so on up the chain). */ rootKind: TurnTriggerKind; /** The root's reference: conversation, work item or ticket id */ rootRef?: string; /** Agents the request passed through before this one, oldest first */ viaAgents: string[]; /** When it was delivered (epoch ms) */ at: number; } /** Provenance record stored on a chat row (`metadata.triggeredBy`). */ export interface TriggeredByMetadata { traceId?: string; rootKind: TurnTriggerKind; rootRef?: string; triggerKind: TurnTriggerKind; viaAgents: string[]; /** The rendered line, without the markdown wrapper (empty when not shown) */ label?: string; } /** * Classify a delivered prompt. * * @param text - Exactly what was written into the turn * @returns The trigger kind and the ids the prompt names */ export declare function classifyTurnTrigger(text: string): ClassifiedTrigger; /** * Last trigger of each session. Singleton (see {@link getTurnTriggerTracker}). */ export declare class TurnTriggerTracker { private readonly current; /** Per session: the latest trigger that names what the agent answers ({@link ROUTED_KINDS}) */ private readonly routed; private readonly sends; /** Per session: conversation id → when the owner last wrote to it there */ private readonly ownerAsks; /** Per session: its routed agent message that it already answered with send-message (crewly#1381) */ private readonly answered; /** * Note that `sender` asked to write `text` to `target` (the terminal write * route, before delivery or queueing). * * @param target - Receiving session * @param text - Message text * @param sender - Sending agent session * @param now - Clock (epoch ms) */ noteSender(target: string, text: string, sender: string, now?: number): void; /** * Record what started `session`'s turn. * * @param session - Agent session written to * @param text - Exactly what was delivered * @param opts - Trace the delivery joined; sender when the caller knows it * @param now - Clock (epoch ms) * @returns The recorded trigger */ noteDelivery(session: string, text: string, opts?: { traceId?: string | null; sender?: string | null; }, now?: number): TurnTrigger; /** * Whether the owner wrote to `session` in `conversationId` recently — a * post there is then an answer to the owner, whatever came in since (a * reminder delivered mid-turn must not relabel it). * * @param session - Agent session * @param conversationId - Conversation posted to * @param now - Clock (epoch ms) * @returns True within {@link TURN_TRIGGER_CONSTANTS.OWNER_ANSWER_WINDOW_MS} */ ownerAskedRecently(session: string, conversationId: string, now?: number): boolean; /** * Whether the owner wrote to `session` in `conversationId` within `windowMs`. * * @param session - Agent session * @param conversationId - Conversation * @param windowMs - How far back * @param now - Clock (epoch ms) * @returns True when the owner asked there within the window */ ownerAskedWithin(session: string, conversationId: string, windowMs: number, now?: number): boolean; /** * The latest trigger of `session` that names what it is answering (an * owner message, an agent message, a delegated result, a dispatch), while * fresh. Reminders and notices delivered since do not replace it. * * @param session - Agent session * @param now - Clock (epoch ms) * @returns The trigger, or null */ routedTrigger(session: string, now?: number): TurnTrigger | null; /** * `session` wrote to `recipient` (send-message / deliver). When its routed * input is `recipient`'s agent message, that message is answered: a later * bare `reply` no longer goes back to `recipient` (crewly#1381 item 3). * The route it carried still travels with the agent's messages * ({@link routedTrigger} is unchanged). * * @param session - Agent that wrote * @param recipient - Agent it wrote to * @param now - Clock (epoch ms) */ noteAnsweredAgent(session: string, recipient: string, now?: number): void; /** * {@link routedTrigger}, unless it is an agent message the session already * answered with send-message ({@link noteAnsweredAgent}): what a bare * `reply` still answers. * * @param session - Agent session * @param now - Clock (epoch ms) * @returns The trigger, or null */ openRoutedTrigger(session: string, now?: number): TurnTrigger | null; /** * The trigger of `session`'s current turn, while fresh. * * @param session - Agent session * @param now - Clock (epoch ms) * @returns The trigger, or null */ trigger(session: string, now?: number): TurnTrigger | null; /** Forget everything (tests). */ reset(): void; /** * The sender of a noted send whose text the delivery contains (consumed). * * @param target - Receiving session * @param text - Delivered text * @param now - Clock * @returns Sender session, or undefined */ private takeSender; } /** * The process-wide tracker. * * @returns The singleton */ export declare function getTurnTriggerTracker(): TurnTriggerTracker; /** * Replace the singleton (tests). * * @param tracker - Replacement, or null to drop it */ export declare function setTurnTriggerTrackerForTesting(tracker: TurnTriggerTracker | null): void; //# sourceMappingURL=turn-trigger.d.ts.map