mirror of
https://github.com/openai/codex.git
synced 2026-10-20 00:18:49 +00:00
Subscribe authors to message-board channels created by posting (#47259)
## Why Posting to a new channel subscribed its author to replies on that post, but not to new discussion roots in the channel. The creator could therefore miss notifications for subsequent discussions. ## What changed Subscribe the author to the channel in the same transaction that creates the channel and its first post. Document this behavior in the API and the `new_channel_name` tool parameter. ## Testing Update coverage to verify that channel creators receive notifications without explicit targeting and that posting to an existing channel preserves an explicit unsubscribe. Adjust thread-deletion test expectations for the additional persisted subscription. GitOrigin-RevId: 5553ebc9f9b51456ab48886e9871733e93370a2b
This commit is contained in:
@@ -391,7 +391,7 @@ async fn thread_delete_removes_persisted_board_even_with_feature_disabled() -> R
|
||||
/*busy_timeout*/ None,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(board_counts(&pool).await?, (1, 1, 1));
|
||||
assert_eq!(board_counts(&pool).await?, (1, 1, 2));
|
||||
let _: ThreadArchiveResponse = app
|
||||
.request(|request_id| ClientRequest::ThreadArchive {
|
||||
request_id,
|
||||
@@ -409,7 +409,7 @@ async fn thread_delete_removes_persisted_board_even_with_feature_disabled() -> R
|
||||
.with_codex_home(home.path())
|
||||
.build_initialized()
|
||||
.await?;
|
||||
assert_eq!(board_counts(&pool).await?, (1, 1, 1));
|
||||
assert_eq!(board_counts(&pool).await?, (1, 1, 2));
|
||||
let _: ThreadDeleteResponse = app
|
||||
.request(|request_id| ClientRequest::ThreadDelete {
|
||||
request_id,
|
||||
|
||||
@@ -51,6 +51,7 @@ pub trait AgentMessageBoard: Send + Sync {
|
||||
/// Uses the caller's configured clock; clock failures must not create a post.
|
||||
/// The request ID identifies a logical call across retries. A retry with
|
||||
/// different input is an error; a successful retry returns the same metadata.
|
||||
/// Creating a channel while posting also subscribes its author to new roots there.
|
||||
fn post(&self, caller: ThreadId, request: PostRequest) -> BoxFuture<'_, Result<PostMetadata>>;
|
||||
|
||||
fn list_threads(
|
||||
|
||||
@@ -235,6 +235,12 @@ impl LocalAgentMessageBoard {
|
||||
PostDestination::NewChannel(channel) => {
|
||||
validate_channel(channel)?;
|
||||
self.insert_channel(&mut tx, channel, &author, now).await?;
|
||||
self.subscribe(
|
||||
&mut tx,
|
||||
&SubscriptionTarget::Channel(channel.clone()),
|
||||
caller,
|
||||
)
|
||||
.await?;
|
||||
(
|
||||
channel.clone(),
|
||||
id,
|
||||
|
||||
@@ -87,6 +87,9 @@ pub(super) fn tool(name: &str, namespace: Option<&str>, namespace_description: &
|
||||
let mut properties = serde_json::Map::new();
|
||||
for field in fields {
|
||||
let schema = match *field {
|
||||
"new_channel_name" => {
|
||||
json!({"type":"string","description":"Create and subscribe to this channel."})
|
||||
}
|
||||
"subscribe" => {
|
||||
json!({"type":"boolean","description":"Subscribe to new roots. Default true."})
|
||||
}
|
||||
|
||||
@@ -102,11 +102,13 @@ async fn shared_handles_resume_posts_and_preserve_subscription_rules() {
|
||||
.await
|
||||
.unwrap();
|
||||
first
|
||||
.create_channel(
|
||||
.post(
|
||||
child,
|
||||
CreateChannelRequest {
|
||||
channel_name: "proofs".into(),
|
||||
subscription: SubscriptionChange::Subscribe,
|
||||
PostRequest {
|
||||
request_id: "create-proofs".into(),
|
||||
destination: PostDestination::NewChannel("proofs".into()),
|
||||
text: "Share proofs here.".into(),
|
||||
agents_to_notify: Vec::new(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -115,7 +117,8 @@ async fn shared_handles_resume_posts_and_preserve_subscription_rules() {
|
||||
request_id: "call-1".into(),
|
||||
destination: PostDestination::Channel("proofs".into()),
|
||||
text: "é🦀 proof".into(),
|
||||
agents_to_notify: vec![AgentPath::root(), child_path.clone(), child_path.clone()],
|
||||
// The creator receives this through its channel subscription.
|
||||
agents_to_notify: vec![AgentPath::root()],
|
||||
};
|
||||
let second = LocalAgentMessageBoard::open(&sqlite, tree, host.clone())
|
||||
.await
|
||||
@@ -180,6 +183,19 @@ async fn shared_handles_resume_posts_and_preserve_subscription_rules() {
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Posting to an existing channel must not re-enable its subscription.
|
||||
resumed
|
||||
.post(
|
||||
child,
|
||||
PostRequest {
|
||||
request_id: "one-off-post".into(),
|
||||
destination: PostDestination::Channel("proofs".into()),
|
||||
text: "One more proof, while staying unsubscribed.".into(),
|
||||
agents_to_notify: Vec::new(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Posting still succeeds when the subscriber lookup returns an empty array.
|
||||
resumed
|
||||
.post(
|
||||
|
||||
Reference in New Issue
Block a user