A workflow's subject is one word, read off the class or off the run - #142
Merged
Merged
Conversation
The declaration and the run's live subject shared the name, so __init_subclass__ deleted the class attribute and kept a private copy — leaving Build.subject as None and two modules reading _subject_class across the wall. A descriptor answers both: the workflow with the kind of thing, a run with the particular one. field_notes spelled "summary" over three unrelated things — the agent's prose, the platform's board header, and two classes of the same name. The note's domain word is now its gist. FeedItem.from_event and AgentCallResponse.from_call were copying fields off one object, so they become model_validate and aliases. The two derivations the latter reached for move onto AgentCall as live_status and token_usage.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Three things the subject arc left behind.
subjectis one word, answering twiceA workflow declares what its runs are about. The declaration and the run's live
subject share the name, so
__init_subclass__moved the class attribute out ofthe way and kept a private copy:
Which left
Build.subjectansweringNonewhileBuildis plainly about aWorkItem, and two modules reaching across for the truth —signals.pyandextensions/base.pyboth readworkflow_class._subject_classto derive asubscriber's filter and an extension's mounted boards.
A descriptor is what the two readings were asking for. The declaration becomes
one, and the same word answers the workflow with the kind of thing and a run
with the particular one:
Build.subject is WorkItemis true now,_subject_classis gone, and the twocross-module private reads are
workflow.subject.Presence in
cls.__dict__still decides, not the value: an explicitsubject = Noneis a declaration of nothing, and stays an error.The proof extension said "summary" three times
field_notesis what an extension author copies from, and it spelled one wordover three unrelated things:
Note.summary(the agent's prose),Note.get_summary()(the platform's board header), and two classes both namedNoteSummary— one anAgentOutput, one aSubjectSummary.get_summary()/list_summaries()is the platform's pair and stays. Thedomain word moves: a note has a
body, and the agent writes its gist.Note.summary→Note.gist,save_summary()→save_gist()contracts.NoteSummary(AgentOutput)→GistOutput, returninggistschemas.NoteSummary(SubjectSummary)keeps its name — it is the platform summaryTwo more builders that were copying fields
Same reduction as #139: a builder that only reads attributes off one object is
model_validateand a few aliases.FeedItem.from_event—seq/at/kindalias to the event'sid/created_at/type,workflowbecomesAliasPath("payload", "kind"), andidis thef"event:{seq}"computed fieldDashboardItem.keyalready models.AgentCallResponse.from_call—account_usernamebecomesAliasPath("account", "username")andlabela computed field. The twoderivations it reached for move onto the row that owns them:
AgentCall.get_live_status()is thelive_statusproperty, andnormalize_token_usage(call.cost_metadata)isAgentCall.token_usage, whichretires the
_token_usagehelper inschemas.py.statusis typedAgentCallStatusrather than a restated literal union, so the# type: ignorethe mismatch needed goes with it.
Both wire shapes are unchanged, field for field.
The
from_*builders that stay are the ones that aren't field copies:AgentCallFiles.from_callwalks the filesystem,RunResponse.from_runtakes asecond argument,
HarnessResponse.from_rowjoins three sources,SettingsFieldResponse.from_fieldreads aFieldInfoplus kwargs, and the fourfrom_settingsare config constructors.