(
message: string,
options?: SendMessageOptions & { fileParts?: FilePart[] },
internal?: QueuedMessageInternalOptions
)
| 166 | } |
| 167 | |
| 168 | private addInternal( |
| 169 | message: string, |
| 170 | options?: SendMessageOptions & { fileParts?: FilePart[] }, |
| 171 | internal?: QueuedMessageInternalOptions |
| 172 | ): boolean { |
| 173 | const trimmedMessage = message.trim(); |
| 174 | const hasFiles = options?.fileParts && options.fileParts.length > 0; |
| 175 | |
| 176 | // Reject if both text and file parts are empty |
| 177 | if (trimmedMessage.length === 0 && !hasFiles) { |
| 178 | return false; |
| 179 | } |
| 180 | |
| 181 | const incomingIsCompaction = isCompactionMetadata(options?.muxMetadata); |
| 182 | const incomingIsAgentSkill = isAgentSkillMetadata(options?.muxMetadata); |
| 183 | const incomingIsWorkspaceTurn = isWorkspaceTurnMetadata(options?.muxMetadata); |
| 184 | const incomingHasAcceptedCallbacks = |
| 185 | internal?.onAccepted != null || |
| 186 | internal?.onAcceptedPreStreamFailure != null || |
| 187 | internal?.onCanceled != null; |
| 188 | const queueHasMessages = !this.isEmpty(); |
| 189 | const incomingMode = options?.queueDispatchMode ?? "tool-end"; |
| 190 | const nextQueueDispatchMode = !queueHasMessages |
| 191 | ? incomingMode |
| 192 | : incomingMode === "tool-end" |
| 193 | ? "tool-end" |
| 194 | : this.queueDispatchMode; |
| 195 | |
| 196 | const queueHasAgentSkill = isAgentSkillMetadata(this.firstMuxMetadata); |
| 197 | const queueHasWorkspaceTurn = isWorkspaceTurnMetadata(this.firstMuxMetadata); |
| 198 | const queueHasAcceptedCallbacks = |
| 199 | this.onAccepted != null || this.onAcceptedPreStreamFailure != null || this.onCanceled != null; |
| 200 | |
| 201 | // Avoid leaking agent-skill metadata to later queued messages. |
| 202 | // A skill invocation must be sent alone (or the user should restore/edit the queued message). |
| 203 | if (queueHasAgentSkill) { |
| 204 | throw new Error( |
| 205 | "Cannot queue additional messages: an agent skill invocation is already queued. " + |
| 206 | "Wait for the current stream to complete before sending another message." |
| 207 | ); |
| 208 | } |
| 209 | |
| 210 | if (queueHasWorkspaceTurn) { |
| 211 | throw new Error( |
| 212 | "Cannot queue additional messages: a workspace turn follow-up is already queued. " + |
| 213 | "Wait for it to dispatch before sending another message." |
| 214 | ); |
| 215 | } |
| 216 | if (queueHasAcceptedCallbacks) { |
| 217 | throw new Error( |
| 218 | "Cannot queue additional messages: an internal workspace turn follow-up is already queued. " + |
| 219 | "Wait for it to dispatch before sending another message." |
| 220 | ); |
| 221 | } |
| 222 | |
| 223 | if (incomingHasAcceptedCallbacks && queueHasMessages) { |
| 224 | throw new Error( |
| 225 | "Cannot queue workspace turn follow-up: queue already has messages. " + |
no test coverage detected