-
Notifications
You must be signed in to change notification settings - Fork 340
Add mid-turn message steering for running agent sessions #2363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
2bb7953
Add mid-turn message steering for running agent sessions
trungutt 717c63a
Extract SteerQueue interface for pluggable storage
trungutt 3243523
Support steering for remote runtimes
trungutt 9424a47
Separate steer and follow-up into two distinct queues
trungutt eea7d5b
Remove GetLocalRuntime in favor of MessageInjector interface
trungutt 45f220b
Add Lock + Confirm/Cancel semantics to MessageQueue
trungutt bb03a14
Address review: extract queue file, add Steer/FollowUp to Runtime, re…
trungutt e4cc4c6
Remove Confirm call from loop — sess.AddMessage is in-memory
trungutt 0155405
Fix build: add Steer/FollowUp to mockRuntime in cli tests
trungutt 3c28081
Use continue instead of res.Stopped = false for steer injection
trungutt 91a9a0c
Remove unused methods: Confirm, Cancel, Len, DrainSteeredMessages, De…
trungutt 04a8b7a
Merge branch 'main' into steer-mid-turn-messages
trungutt bf665c2
Remove unused App.Steer and App.FollowUp methods
trungutt 6592db8
Compact unconditionally after tool execution
trungutt 5dac5cd
Fix compaction placement: run after stop check, not before
trungutt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| package runtime | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/docker/docker-agent/pkg/chat" | ||
| ) | ||
|
|
||
| // QueuedMessage is a user message waiting to be injected into the agent loop, | ||
| // either mid-turn (via the steer queue) or at end-of-turn (via the follow-up | ||
| // queue). | ||
| type QueuedMessage struct { | ||
| Content string | ||
| MultiContent []chat.MessagePart | ||
| } | ||
|
|
||
| // MessageQueue is the interface for storing messages that are injected into | ||
| // the agent loop. Implementations must be safe for concurrent use: Enqueue | ||
| // is called from API handlers while Dequeue/Drain are called from the agent | ||
| // loop goroutine. | ||
| // | ||
| // Dequeue uses a Lock + Confirm/Cancel pattern: Dequeue locks the next | ||
| // message (making it invisible to subsequent Dequeue calls), Confirm | ||
| // permanently removes it after the message has been successfully processed, | ||
| // and Cancel releases it back to the queue if processing fails. This | ||
| // prevents message loss in persistent queue implementations where the | ||
| // session store is also durable. | ||
| // | ||
| // Note: for the default in-memory queue, Confirm and Cancel are no-ops | ||
| // because the message is consumed from the channel on Dequeue and the | ||
| // session is also in-memory. The pattern exists so that persistent | ||
| // implementations (with a durable session store) can guarantee | ||
| // exactly-once delivery. | ||
| // | ||
| // The default implementation is NewInMemoryMessageQueue. Callers that need | ||
| // durable or distributed storage can provide their own implementation | ||
| // via the WithSteerQueue or WithFollowUpQueue options. | ||
| type MessageQueue interface { | ||
| // Enqueue adds a message to the queue. Returns false if the queue is | ||
| // full or the context is cancelled. | ||
| Enqueue(ctx context.Context, msg QueuedMessage) bool | ||
| // Dequeue locks and returns the next message from the queue. The | ||
| // message is invisible to subsequent Dequeue calls until Confirm or | ||
| // Cancel is called. Returns the message and true, or a zero value | ||
| // and false if the queue is empty. Must not block. | ||
| Dequeue(ctx context.Context) (QueuedMessage, bool) | ||
| // Confirm permanently removes the most recently dequeued message. | ||
| // Must be called after the message has been successfully persisted | ||
| // to the session. For in-memory queues this is a no-op. | ||
| Confirm(ctx context.Context) error | ||
|
trungutt marked this conversation as resolved.
Outdated
|
||
| // Cancel releases the most recently dequeued message back to the | ||
| // queue. For in-memory queues this is a no-op (the message was | ||
| // already consumed from the channel). | ||
| Cancel(ctx context.Context) error | ||
| // Drain locks, returns, and auto-confirms all pending messages. | ||
| // Must not block — if the queue is empty it returns nil. | ||
| Drain(ctx context.Context) []QueuedMessage | ||
| // Len returns the current number of messages in the queue. | ||
| Len(ctx context.Context) int | ||
|
trungutt marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // inMemoryMessageQueue is the default MessageQueue backed by a buffered channel. | ||
| type inMemoryMessageQueue struct { | ||
| ch chan QueuedMessage | ||
| } | ||
|
|
||
| const ( | ||
| // defaultSteerQueueCapacity is the buffer size for the default in-memory steer queue. | ||
| defaultSteerQueueCapacity = 5 | ||
| // defaultFollowUpQueueCapacity is the buffer size for the default in-memory follow-up queue. | ||
| // Higher than steer because follow-ups accumulate while waiting for the turn to end. | ||
| defaultFollowUpQueueCapacity = 20 | ||
| ) | ||
|
|
||
| // NewInMemoryMessageQueue creates a MessageQueue backed by a buffered channel | ||
| // with the given capacity. | ||
| func NewInMemoryMessageQueue(capacity int) MessageQueue { | ||
| return &inMemoryMessageQueue{ch: make(chan QueuedMessage, capacity)} | ||
| } | ||
|
|
||
| func (q *inMemoryMessageQueue) Enqueue(_ context.Context, msg QueuedMessage) bool { | ||
| select { | ||
| case q.ch <- msg: | ||
| return true | ||
| default: | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| func (q *inMemoryMessageQueue) Dequeue(_ context.Context) (QueuedMessage, bool) { | ||
| select { | ||
| case m := <-q.ch: | ||
| return m, true | ||
| default: | ||
| return QueuedMessage{}, false | ||
| } | ||
| } | ||
|
|
||
| // Confirm is a no-op for in-memory queues — the message was already | ||
| // removed from the channel on Dequeue. | ||
| func (q *inMemoryMessageQueue) Confirm(_ context.Context) error { return nil } | ||
|
|
||
| // Cancel is a no-op for in-memory queues — the message cannot be put | ||
| // back into a buffered channel without risking deadlock. | ||
| func (q *inMemoryMessageQueue) Cancel(_ context.Context) error { return nil } | ||
|
|
||
| func (q *inMemoryMessageQueue) Drain(_ context.Context) []QueuedMessage { | ||
| var msgs []QueuedMessage | ||
| for { | ||
| select { | ||
| case m := <-q.ch: | ||
| msgs = append(msgs, m) | ||
| default: | ||
| return msgs | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func (q *inMemoryMessageQueue) Len(_ context.Context) int { | ||
| return len(q.ch) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.