-
Notifications
You must be signed in to change notification settings - Fork 7
Run the episode on the host's own agents: the hosted runner #70
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
Changes from all commits
934d6aa
ff87c9a
5d16143
45bc3d6
2f491e9
6472c35
c30669d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,20 @@ | ||
| //! What passes between the conductor and its host: a turn to run, and the | ||
| //! steps the host takes on the conductor's behalf after a wave. | ||
| //! | ||
| //! Every type here is a wire form. A host journals commits and events and | ||
| //! streams them to whatever renders the desk, so the serde representation is | ||
| //! pinned by a unit test: internally tagged, `snake_case`, and every field a | ||
| //! host can act on present by name. | ||
|
|
||
| use serde::{Deserialize, Serialize}; | ||
| use tinyhivemind::Sequence; | ||
| use tinyhivemind::speech::Utterance; | ||
|
|
||
| use crate::driver::Channel; | ||
|
|
||
| /// One turn the host runs this wave. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(rename_all = "snake_case")] | ||
| pub struct Turn { | ||
| /// The seat. | ||
| pub seat: String, | ||
|
|
@@ -31,7 +38,8 @@ impl Turn { | |
|
|
||
| /// A row the desk says to a seat: the host appends it, attributed to the | ||
| /// desk, and nothing is committed back. The wording is the episode's. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(rename_all = "snake_case")] | ||
| pub struct Note { | ||
| /// What the desk says. | ||
| pub body: String, | ||
|
|
@@ -46,7 +54,8 @@ pub struct Note { | |
| /// | ||
| /// The host renders the utterance as its own desk row and calls | ||
| /// [`Conductor::committed`](super::Conductor::committed) with the sequence. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(rename_all = "snake_case")] | ||
| pub struct Commit { | ||
| /// The seat the row is attributed to. | ||
| pub author: String, | ||
|
|
@@ -56,14 +65,29 @@ pub struct Commit { | |
| pub thread: Option<Sequence>, | ||
| /// On the open desk, the one seat it reaches; `None` reaches every seat. | ||
| pub only_for: Option<String>, | ||
| /// The conversation this row belongs to, by the ask row it is rooted at. | ||
| /// | ||
| /// Set for a row said inside a conversation, for desk work a seat lifted | ||
| /// out of one -- a broadcast or an ask made while talking, which lands on | ||
| /// the desk with no `thread` -- and for the row that concludes one to its | ||
| /// asker. `None` for everything said on the desk itself, including the | ||
| /// ask that opens a conversation: that row's own sequence is the root. | ||
| /// A host shows one agent-to-agent exchange whole by taking the ask row | ||
| /// and every row whose `conversation` is its sequence, wherever they | ||
| /// landed. | ||
| pub conversation: Option<Sequence>, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update every commit and event producer for the new required fields Adding this non-optional struct field makes every existing [RULE] compile-error ·
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This compiles: the Rust job on this branch builds every target and runs these tests. Every producer was updated in #69, which this PR is stacked on: the seven sites in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved — the reply explains why it is not a problem (advisory), as of If this is wrong, reopen the conversation and say so; the finding will be re-raised on the next push if it still reproduces. |
||
| /// What the conductor does with the row once it has its sequence. Opaque | ||
| /// to a host: carried so a commit survives the wire whole. | ||
| #[serde(rename = "purpose")] | ||
| pub(super) kind: Kind, | ||
| } | ||
|
|
||
| /// What the conductor does with a commit once it has its sequence. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(tag = "kind", rename_all = "snake_case")] | ||
| pub(super) enum Kind { | ||
| /// A seat spoke in a conversation. | ||
| Thread(Sequence), | ||
| Thread { root: Sequence }, | ||
| /// A seat spoke on the desk; a broadcast is routed. | ||
| Desk, | ||
| /// A conversation concluded: its outcome, cross-posted to the asker. | ||
|
|
@@ -73,7 +97,8 @@ pub(super) enum Kind { | |
| } | ||
|
|
||
| /// Why a seat's row was refused, in the terms the desk tells it. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(tag = "kind", rename_all = "snake_case")] | ||
| pub enum Refusal { | ||
| /// It may not complete: the seats it asked have not answered. | ||
| AwaitingReply { | ||
|
|
@@ -89,9 +114,14 @@ pub enum Refusal { | |
| NotYetShown, | ||
| } | ||
|
|
||
| /// Something the episode did that a host may want to log. Nothing here needs | ||
| /// acting on; every consequence is already a [`Note`] or a [`Commit`]. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| /// Something the episode did that a host may want to show. Nothing here | ||
| /// needs acting on; every consequence is already a [`Note`] or a [`Commit`]. | ||
| /// | ||
| /// An event about a row names it by `at`, the sequence the host gave that | ||
| /// row, so a host attaches the event to the row it drew rather than | ||
| /// inferring it from order. | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(tag = "kind", rename_all = "snake_case")] | ||
| pub enum Event { | ||
| /// A seat was told once that nothing will wake it. | ||
| Nudged { | ||
|
|
@@ -106,16 +136,22 @@ pub enum Event { | |
| seat: String, | ||
| /// Who took it. | ||
| to: Vec<String>, | ||
| /// The broadcast row. | ||
| at: Sequence, | ||
| }, | ||
| /// A broadcast fit no seat; the author keeps the work. | ||
| Unplaced { | ||
| /// The author. | ||
| seat: String, | ||
| /// The broadcast row. | ||
| at: Sequence, | ||
| }, | ||
| /// A broadcast closed its author's own assignment. | ||
| CompletedByBroadcast { | ||
| /// The author. | ||
| seat: String, | ||
| /// The broadcast row. | ||
| at: Sequence, | ||
| }, | ||
| /// An ask opened a conversation. | ||
| Asked { | ||
|
|
@@ -132,20 +168,27 @@ pub enum Event { | |
| to: String, | ||
| /// The author of the broadcast it came from. | ||
| from: String, | ||
| /// The broadcast row it came from. | ||
| origin: Sequence, | ||
| }, | ||
| /// A row was refused, and the seat told why. | ||
| /// A row was refused, and the seat told why. The row is already on the | ||
| /// host's journal; this is what marks it refused. | ||
| Refused { | ||
| /// The seat. | ||
| seat: String, | ||
| /// The thread, or `None` on the desk. | ||
| thread: Option<Sequence>, | ||
| /// Why. | ||
| why: Refusal, | ||
| /// The refused row. | ||
| at: Sequence, | ||
| }, | ||
| /// A seat spent its broadcast budget and was completed with the work. | ||
| Discharged { | ||
| /// The seat. | ||
| seat: String, | ||
| /// The broadcast row that was over budget. | ||
| at: Sequence, | ||
| }, | ||
| /// A conversation concluded. | ||
| Concluded { | ||
|
|
@@ -157,16 +200,21 @@ pub enum Event { | |
| askee: String, | ||
| /// Without an answer: nothing was due, or it ran out of turns. | ||
| forced: bool, | ||
| /// The row that carried the outcome to the asker. | ||
| at: Sequence, | ||
| }, | ||
| } | ||
|
|
||
| /// One step the host takes after a wave, in order. | ||
| #[derive(Clone, Debug, Eq, PartialEq)] | ||
| /// | ||
| /// On the wire, tagged by `step`, with the step's own fields beside the tag. | ||
| #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] | ||
| #[serde(tag = "step", rename_all = "snake_case")] | ||
| pub enum Step { | ||
| /// Append this, attributed to the desk. | ||
| Note(Note), | ||
| /// Append this and report its sequence. | ||
| Commit(Commit), | ||
| /// Log this, or don't. | ||
| /// Show this, or don't. | ||
| Event(Event), | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Require explicit presence for nullable wire fields.
Serde currently accepts an absent
Option<T>field asNone. This behavior can silently change row and event provenance. The required-field tests do not cover these fields.crates/tinyhivemind-driver/src/conduct/steps.rs#L57-L58: use required-null deserialization for nullable fields. Accept explicitnull, but reject field omission.crates/tinyhivemind-driver/src/conduct/test/wire.rs#L115-L115: add missing-field checks for each nullable field inNote,Commit, andEvent.Based on learnings, serialization changes must verify malformed input handling and compatibility.
📍 Affects 2 files
crates/tinyhivemind-driver/src/conduct/steps.rs#L57-L58(this comment)crates/tinyhivemind-driver/src/conduct/test/wire.rs#L115-L115🤖 Prompt for AI Agents
Source: Learnings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, and it is the same rule
LogMessage::audiencealready follows: an omittedonly_fororthreaddecoding toNonewould publish a private row to the desk. These fields landed in #69, which is merged, so this goes as a small PR againstmain: required-null deserialization forNote::{thread, only_for},Commit::{thread, only_for, conversation}and theOptions onEvent, with missing-field checks inwire.rs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sanil-23, agreed. An omitted nullable provenance field must not deserialize asNone.A separate PR against
mainis appropriate because the affected fields are already in#69. The required-null handling and missing-field tests will prevent private rows from becoming desk-visible.🐇
✏️ Learnings added
You are interacting with an AI system.