mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 18:01:22 +00:00
feat(coding-agent): expose deliverAs option in hook sendMessage() API
- pi.sendMessage(msg, options?) now accepts { triggerTurn?, deliverAs? }
- deliverAs: 'steer' (default) or 'followUp' controls delivery timing
- Update all mode handlers to pass options through
- Update file-trigger example to use new API
- Update CHANGELOG
This commit is contained in:
parent
d404f8fcfa
commit
9d8230dfc6
8 changed files with 29 additions and 18 deletions
|
|
@ -15,7 +15,7 @@
|
|||
- `queuedMessageCount` → `pendingMessageCount`
|
||||
- `getQueuedMessages()` → `getSteeringMessages()` and `getFollowUpMessages()`
|
||||
- `clearQueue()` now returns `{ steering: string[], followUp: string[] }`
|
||||
- **sendHookMessage() signature changed**: Second parameter changed from `triggerTurn?: boolean` to `options?: { triggerTurn?, deliverAs? }`. Use `deliverAs: "followUp"` for follow-up delivery.
|
||||
- **Hook API signature changed**: `pi.sendMessage()` second parameter changed from `triggerTurn?: boolean` to `options?: { triggerTurn?, deliverAs? }`. Use `deliverAs: "followUp"` for follow-up delivery. Affects both hooks and internal `sendHookMessage()` method.
|
||||
- **RPC API changes**:
|
||||
- `queue_message` command → `steer` and `follow_up` commands
|
||||
- `set_queue_mode` command → `set_steering_mode` and `set_follow_up_mode` commands
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export default function (pi: HookAPI) {
|
|||
content: `External trigger: ${content}`,
|
||||
display: true,
|
||||
},
|
||||
true, // triggerTurn - get LLM to respond
|
||||
{ triggerTurn: true }, // triggerTurn - get LLM to respond
|
||||
);
|
||||
fs.writeFileSync(triggerFile, ""); // Clear after reading
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ type HandlerFn = (...args: unknown[]) => Promise<unknown>;
|
|||
*/
|
||||
export type SendMessageHandler = <T = unknown>(
|
||||
message: Pick<HookMessage<T>, "customType" | "content" | "display" | "details">,
|
||||
triggerTurn?: boolean,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" },
|
||||
) => void;
|
||||
|
||||
/**
|
||||
|
|
@ -177,8 +177,11 @@ function createHookAPI(
|
|||
list.push(handler);
|
||||
handlers.set(event, list);
|
||||
},
|
||||
sendMessage<T = unknown>(message: HookMessage<T>, triggerTurn?: boolean): void {
|
||||
sendMessageHandler(message, triggerTurn);
|
||||
sendMessage<T = unknown>(
|
||||
message: HookMessage<T>,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" },
|
||||
): void {
|
||||
sendMessageHandler(message, options);
|
||||
},
|
||||
appendEntry<T = unknown>(customType: string, data?: T): void {
|
||||
appendEntryHandler(customType, data);
|
||||
|
|
|
|||
|
|
@ -692,12 +692,15 @@ export interface HookAPI {
|
|||
* @param message.content - Message content (string or TextContent/ImageContent array)
|
||||
* @param message.display - Whether to show in TUI (true = styled display, false = hidden)
|
||||
* @param message.details - Optional hook-specific metadata (not sent to LLM)
|
||||
* @param triggerTurn - If true and agent is idle, triggers a new LLM turn. Default: false.
|
||||
* If agent is streaming, message is queued and triggerTurn is ignored.
|
||||
* @param options.triggerTurn - If true and agent is idle, triggers a new LLM turn. Default: false.
|
||||
* If agent is streaming, message is queued and triggerTurn is ignored.
|
||||
* @param options.deliverAs - How to deliver when agent is streaming. Default: "steer".
|
||||
* - "steer": Interrupt mid-run, delivered after current tool execution.
|
||||
* - "followUp": Wait until agent finishes all work before delivery.
|
||||
*/
|
||||
sendMessage<T = unknown>(
|
||||
message: Pick<HookMessage<T>, "customType" | "content" | "display" | "details">,
|
||||
triggerTurn?: boolean,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" },
|
||||
): void;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -344,7 +344,10 @@ function createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; fa
|
|||
const handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();
|
||||
const messageRenderers = new Map<string, any>();
|
||||
const commands = new Map<string, any>();
|
||||
let sendMessageHandler: (message: any, triggerTurn?: boolean) => void = () => {};
|
||||
let sendMessageHandler: (
|
||||
message: any,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" },
|
||||
) => void = () => {};
|
||||
let appendEntryHandler: (customType: string, data?: any) => void = () => {};
|
||||
let newSessionHandler: (options?: any) => Promise<{ cancelled: boolean }> = async () => ({ cancelled: false });
|
||||
let branchHandler: (entryId: string) => Promise<{ cancelled: boolean }> = async () => ({ cancelled: false });
|
||||
|
|
@ -358,8 +361,8 @@ function createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; fa
|
|||
list.push(handler);
|
||||
handlers.set(event, list);
|
||||
},
|
||||
sendMessage: (message: any, triggerTurn?: boolean) => {
|
||||
sendMessageHandler(message, triggerTurn);
|
||||
sendMessage: (message: any, options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" }) => {
|
||||
sendMessageHandler(message, options);
|
||||
},
|
||||
appendEntry: (customType: string, data?: any) => {
|
||||
appendEntryHandler(customType, data);
|
||||
|
|
@ -383,7 +386,9 @@ function createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; fa
|
|||
handlers,
|
||||
messageRenderers,
|
||||
commands,
|
||||
setSendMessageHandler: (handler: (message: any, triggerTurn?: boolean) => void) => {
|
||||
setSendMessageHandler: (
|
||||
handler: (message: any, options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" }) => void,
|
||||
) => {
|
||||
sendMessageHandler = handler;
|
||||
},
|
||||
setAppendEntryHandler: (handler: (customType: string, data?: any) => void) => {
|
||||
|
|
|
|||
|
|
@ -404,10 +404,10 @@ export class InteractiveMode {
|
|||
|
||||
hookRunner.initialize({
|
||||
getModel: () => this.session.model,
|
||||
sendMessageHandler: (message, triggerTurn) => {
|
||||
sendMessageHandler: (message, options) => {
|
||||
const wasStreaming = this.session.isStreaming;
|
||||
this.session
|
||||
.sendHookMessage(message, { triggerTurn })
|
||||
.sendHookMessage(message, options)
|
||||
.then(() => {
|
||||
// For non-streaming cases with display=true, update UI
|
||||
// (streaming cases update via message_end event)
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ export async function runPrintMode(
|
|||
if (hookRunner) {
|
||||
hookRunner.initialize({
|
||||
getModel: () => session.model,
|
||||
sendMessageHandler: (message, triggerTurn) => {
|
||||
session.sendHookMessage(message, { triggerTurn }).catch((e) => {
|
||||
sendMessageHandler: (message, options) => {
|
||||
session.sendHookMessage(message, options).catch((e) => {
|
||||
console.error(`Hook sendMessage failed: ${e instanceof Error ? e.message : String(e)}`);
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -181,8 +181,8 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
|||
if (hookRunner) {
|
||||
hookRunner.initialize({
|
||||
getModel: () => session.agent.state.model,
|
||||
sendMessageHandler: (message, triggerTurn) => {
|
||||
session.sendHookMessage(message, { triggerTurn }).catch((e) => {
|
||||
sendMessageHandler: (message, options) => {
|
||||
session.sendHookMessage(message, options).catch((e) => {
|
||||
output(error(undefined, "hook_send", e.message));
|
||||
});
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue