multitaskStrategy: "enqueue" lets the user fire additional submits while another run is in flight. The queue is fully client-side — entries drain sequentially as the active run terminates — and is observable through the injectSubmissionQueue companion injector.
Learn more: For queued-input UX, see the message queues documentation.
Pass multitaskStrategy to submit() to control what happens when a submit lands while a run is already active:
| Strategy | Behaviour |
|---|---|
"rollback" |
Default. Aborts the active run and immediately dispatches the new one. |
"reject" |
Drops the new submit. The returned promise rejects. |
"enqueue" |
Appends the submit to the client-side queue. Entries drain sequentially once the active run terminates. |
"interrupt" |
Currently falls back to "rollback" semantics client-side, pending server-side support. |
import { HumanMessage } from "@langchain/core/messages";
void stream.submit({ messages: [new HumanMessage("follow-up")] }, { multitaskStrategy: "enqueue" });
Nothing special happens on the return value — the promise resolves when the enqueued run eventually completes. You can fire several in a row; they dispatch in call order.
injectSubmissionQueueSubscribe to the queue reactively from any component:
import { Component, Input } from "@angular/core";
import { HumanMessage } from "@langchain/core/messages";
import { injectSubmissionQueue, type AnyStream } from "@langchain/angular";
@Component({
standalone: true,
template: `
<button (click)="queueTurn()">Queue turn</button>
@if (queue.size() > 0) {
<div>
<p>{{ queue.size() }} queued</p>
<ol>
@for (entry of queue.entries(); track entry.id) {
<li>
pending...
<button (click)="queue.cancel(entry.id)">cancel</button>
</li>
}
</ol>
<button (click)="queue.clear()">Clear queue</button>
</div>
}
`,
})
export class ComposerComponent {
@Input({ required: true }) stream!: AnyStream;
readonly queue = injectSubmissionQueue(this.stream);
queueTurn() {
void this.stream.submit(
{ messages: [new HumanMessage("go")] },
{ multitaskStrategy: "enqueue" },
);
}
}
| Field | Type | Description |
|---|---|---|
entries |
Signal<readonly SubmissionQueueEntry[]> |
All pending entries, in dispatch order. |
size |
Signal<number> |
Alias for entries().length. |
cancel(id) |
(id: string) => Promise<boolean> |
Removes one entry by id; resolves true on hit. |
clear() |
() => Promise<void> |
Empties the queue. |
Each SubmissionQueueEntry carries { id, input, options, enqueuedAt } so you can render the queued input ahead of its dispatch.
cancel(id) removes a single entry. The run is never dispatched.clear() empties the queue but does not affect the active run. Pair with stream.stop() if you also need to abort the in-flight work.threadId clears the queue — entries were targeted at the previous thread, so dispatching them against the new one would be surprising.