Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .verification/object-settings-sources/agent-control.plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"recipes": [
{
"recipe_id": "selected-session-advertisement-control",
"operations": [
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/tests/textual/test_sidebar_projection.py",
"target_qualname": "test_view_menu_discovers_settings_and_keeps_each_objects_state",
"replacements": [
{
"old_source": " native_menu = native_bar.query_one(PanelMenu)\n relationships =",
"new_source": " native_menu = native_bar.query_one(PanelMenu)\n from acp.schema import SetSessionConfigOptionResponse\n from support.agents import AppAgents\n from toad.configured_view import AgentProperties\n from toad.widgets.model_switcher import SessionForm\n agent = AppAgents(app).detached_agent('sidebar-settings')\n native.conversation.bind_agent(agent)\n agent.configuration.receive(SetSessionConfigOptionResponse.model_validate({'configOptions': [\n {'id': 'sample-budget', 'name': 'Budget', 'type': 'boolean', 'currentValue': True},\n ]}).config_options)\n agent_entry = next(entry for entry in native_menu.entries if isinstance(entry.widget, AgentProperties))\n native_menu.picker.value = agent_entry\n await ui.until(lambda: agent_entry.widget.is_mounted and bool(agent_entry.widget.query(SessionForm)),\n why='the actual advertised session form')\n await ui.until(lambda: agent_entry.widget.form.represents(agent.configuration),\n why='new advertisements replace the original fields')\n assert agent_entry.widget.form.prompt is native.conversation.prompt\n assert 'Budget' in {row.field.label for row in agent_entry.widget.form.values.values()}\n agent.configuration.receive(SetSessionConfigOptionResponse.model_validate({'configOptions': [\n {'id': 'sample-budget', 'name': 'Budget', 'type': 'boolean', 'currentValue': False},\n {'id': 'new-setting', 'name': 'New setting', 'type': 'boolean', 'currentValue': True},\n ]}).config_options)\n await ui.until(lambda: agent_entry.widget.form.represents(agent.configuration),\n why='the sidebar follows the source update')\n assert 'New setting' in {row.field.label for row in agent_entry.widget.form.values.values()}\n relationships ="
}
]
}
]
}
]
}
163 changes: 163 additions & 0 deletions .verification/object-settings-sources/agent.plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
{
"recipes": [
{
"recipe_id": "share-the-advertised-form-with-view-properties",
"operations": [
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "SessionModelEditor.history_scope",
"replacements": [
{
"old_source": "self.query_ancestor(ModelSwitcher).prompt.model_history_scope",
"new_source": "self.query_ancestor(SessionForm).prompt.model_history_scope"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "SessionModelEditor.opened",
"replacements": [
{
"old_source": " if self.query_ancestor(ModelSwitcher).is_open:\n self.focus_content(False)",
"new_source": " self.focus_content(False)"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "SessionModelEditor.connect_provider",
"replacements": [
{
"old_source": "self.publish_core(input_events.ProviderLogin())",
"new_source": "self.query_ancestor(SessionForm).prompt.publish_core(input_events.ProviderLogin())"
}
]
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "SessionModelEditor.dismiss_control",
"replacements": [
{
"old_source": "self.query_ancestor(ModelSwitcher).dismiss_control()",
"new_source": "self.query_ancestor(SessionForm).dismiss_control()"
}
]
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "SessionForm.represents",
"source": " def __init__(self, state, parts, prompt):\n super().__init__(state, parts)\n self.prompt = prompt\n\n @classmethod\n def for_prompt(cls, prompt):\n state = prompt.agent_binding.configuration.editing()\n return cls(state, cls.field_family.of(state), prompt)\n\n def dismiss_control(self):\n \"\"\"An inline selection leaves its form open.\"\"\"\n\n"
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "SessionForm.values_changed",
"replacements": [
{
"old_source": "self.publish_core(setting.selection_event(field.value))",
"new_source": "self.prompt.publish_core(setting.selection_event(field.value))"
}
]
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "ModelSwitcher",
"source": "class PopupSessionForm(SessionForm):\n \"\"\"The popup adds dismissal to the same advertised settings form.\"\"\"\n\n def dismiss_control(self):\n self.query_ancestor(ModelSwitcher).dismiss_control()\n\n\n"
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/widgets/model_switcher.py",
"target_qualname": "ModelSwitcher.compose_content",
"replacements": [
{
"old_source": "SessionForm.whole(self.prompt.agent_binding.configuration.editing())",
"new_source": "PopupSessionForm.for_prompt(self.prompt)"
}
]
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/configured_view.py",
"import_source": "from toad.widgets.model_switcher import SessionForm"
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/configured_view.py",
"import_source": "from toad.core_event_carrier import CoreEventReceiver"
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/configured_view.py",
"import_source": "from toad.core.events import ConfigurationChanged"
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/configured_view.py",
"import_source": "from metaclass_registry.mro_dispatch import handles"
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/configured_view.py",
"import_source": "from textual import work"
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/configured_view.py",
"target_qualname": "ObjectConfigurationDialog",
"source": "class AgentProperties(CoreEventReceiver, FillHeight, SidebarPanelWidget):\n \"\"\"The selected native session's advertisements, using its original writer.\"\"\"\n\n def __init__(self, view):\n super().__init__()\n self.view = view\n self.listen(events.Mount, self.follow_binding)\n\n @classmethod\n def panel(cls, view):\n return SideBar.Panel(\"Agent settings\", cls(view), id=\"agent-settings\", flex=True)\n\n def compose(self):\n self.form = SessionForm.for_prompt(self.view.conversation.prompt)\n yield self.form\n\n def follow_binding(self):\n self.watch(self.view.conversation, \"agent_binding\", self.binding_changed)\n\n def binding_changed(self, old, new):\n self.retire_core_observations(old.events)\n self.observe_core(new.events)\n self.configuration_changed()\n\n @handles(ConfigurationChanged)\n def configuration_changed(self):\n if self.is_mounted:\n self.rebuild_form()\n\n @work(exclusive=True, group=\"agent-settings\")\n async def rebuild_form(self):\n await self.recompose()\n\n def finish(self):\n self.form.finish()\n\n\n"
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/agent_binding.py",
"import_source": "from toad.core.events import CoreEventStream"
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/agent_binding.py",
"target_qualname": "NoAgentConnection.presentation",
"source": " @cached_property\n def events(self):\n return CoreEventStream(self)\n\n"
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/screens/main.py",
"target_qualname": "MainScreen.keyboard_scopes",
"source": " @property\n def configuration_panels(self):\n yield from self.operational_sources.configuration_panels(self)\n yield from super().configuration_panels\n\n"
},
{
"operation": "ensure_import",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/session_presentation.py",
"import_source": "from toad.configured_view import AgentProperties"
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/session_presentation.py",
"target_qualname": "OperationalSessionSources.prompt",
"source": " def configuration_panels(self, view):\n yield AgentProperties.panel(view)\n\n"
},
{
"operation": "insert_before_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/session_presentation.py",
"target_qualname": "MailboxSessionSources.prompt",
"source": " def configuration_panels(self, view):\n \"\"\"A mailbox has no native session configuration to advertise.\"\"\"\n return ()\n\n"
},
{
"operation": "patch_target",
"file_path": "/home/ts/wt/codex-live--P181--toad/src/toad/forms/object_configuration.py",
"target_qualname": "ObjectFieldView",
"replacements": [
{
"old_source": " @classmethod\n def admits(cls, field):\n return True",
"new_source": ""
}
]
}
]
}
]
}
109 changes: 109 additions & 0 deletions .verification/object-settings-sources/agent_author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import json
from pathlib import Path
r=Path.cwd(); ops=[]
def patch(f,t,o,n): ops.append(dict(operation='patch_target',file_path=str(r/f),target_qualname=t,replacements=[dict(old_source=o,new_source=n)]))
def insert(f,t,s):ops.append(dict(operation='insert_before_target',file_path=str(r/f),target_qualname=t,source=s))
def imp(f,s):ops.append(dict(operation='ensure_import',file_path=str(r/f),import_source=s))
f='src/toad/widgets/model_switcher.py'
patch(f,'SessionModelEditor.history_scope','self.query_ancestor(ModelSwitcher).prompt.model_history_scope','self.query_ancestor(SessionForm).prompt.model_history_scope')
patch(f,'SessionModelEditor.opened',''' if self.query_ancestor(ModelSwitcher).is_open:
self.focus_content(False)''',''' self.focus_content(False)''')
patch(f,'SessionModelEditor.connect_provider','self.publish_core(input_events.ProviderLogin())','self.query_ancestor(SessionForm).prompt.publish_core(input_events.ProviderLogin())')
patch(f,'SessionModelEditor.dismiss_control','self.query_ancestor(ModelSwitcher).dismiss_control()','self.query_ancestor(SessionForm).dismiss_control()')
insert(f,'SessionForm.represents',''' def __init__(self, state, parts, prompt):
super().__init__(state, parts)
self.prompt = prompt

@classmethod
def for_prompt(cls, prompt):
state = prompt.agent_binding.configuration.editing()
return cls(state, cls.field_family.of(state), prompt)

def dismiss_control(self):
"""An inline selection leaves its form open."""

''')
patch(f,'SessionForm.values_changed','self.publish_core(setting.selection_event(field.value))','self.prompt.publish_core(setting.selection_event(field.value))')
insert(f,'ModelSwitcher','''class PopupSessionForm(SessionForm):
"""The popup adds dismissal to the same advertised settings form."""

def dismiss_control(self):
self.query_ancestor(ModelSwitcher).dismiss_control()


''')
patch(f,'ModelSwitcher.compose_content','SessionForm.whole(self.prompt.agent_binding.configuration.editing())','PopupSessionForm.for_prompt(self.prompt)')
f='src/toad/configured_view.py'
imp(f,'from toad.widgets.model_switcher import SessionForm')
imp(f,'from toad.core_event_carrier import CoreEventReceiver')
imp(f,'from toad.core.events import ConfigurationChanged')
imp(f,'from metaclass_registry.mro_dispatch import handles')
imp(f,'from textual import work')
insert(f,'ObjectConfigurationDialog','''class AgentProperties(CoreEventReceiver, FillHeight, SidebarPanelWidget):
"""The selected native session's advertisements, using its original writer."""

def __init__(self, view):
super().__init__()
self.view = view
self.listen(events.Mount, self.follow_binding)

@classmethod
def panel(cls, view):
return SideBar.Panel("Agent settings", cls(view), id="agent-settings", flex=True)

def compose(self):
self.form = SessionForm.for_prompt(self.view.conversation.prompt)
yield self.form

def follow_binding(self):
self.watch(self.view.conversation, "agent_binding", self.binding_changed)

def binding_changed(self, old, new):
self.retire_core_observations(old.events)
self.observe_core(new.events)
self.configuration_changed()

@handles(ConfigurationChanged)
def configuration_changed(self):
if self.is_mounted:
self.rebuild_form()

@work(exclusive=True, group="agent-settings")
async def rebuild_form(self):
await self.recompose()

def finish(self):
self.form.finish()


''')
f='src/toad/agent_binding.py'
imp(f,'from toad.core.events import CoreEventStream')
insert(f,'NoAgentConnection.presentation',''' @cached_property
def events(self):
return CoreEventStream(self)

''')
f='src/toad/screens/main.py'
insert(f,'MainScreen.keyboard_scopes',''' @property
def configuration_panels(self):
yield from self.operational_sources.configuration_panels(self)
yield from super().configuration_panels

''')
f='src/toad/session_presentation.py'
imp(f,'from toad.configured_view import AgentProperties')
insert(f,'OperationalSessionSources.prompt',''' def configuration_panels(self, view):
yield AgentProperties.panel(view)

''')
insert(f,'MailboxSessionSources.prompt',''' def configuration_panels(self, view):
"""A mailbox has no native session configuration to advertise."""
return ()

''')
f='src/toad/forms/object_configuration.py'
patch(f,'ObjectFieldView',''' @classmethod
def admits(cls, field):
return True''','')
Path('.verification/object-settings-sources/agent.plan.json').write_text(json.dumps({'recipes':[{'recipe_id':'share-the-advertised-form-with-view-properties','operations':ops}]},indent=2))
33 changes: 33 additions & 0 deletions .verification/object-settings-sources/agent_control_author.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import json
from pathlib import Path
r=Path.cwd();ops=[]
def patch(f,t,o,n):ops.append(dict(operation='patch_target',file_path=str(r/f),target_qualname=t,replacements=[dict(old_source=o,new_source=n)]))
patch('tests/textual/test_sidebar_projection.py','test_view_menu_discovers_settings_and_keeps_each_objects_state', ''' native_menu = native_bar.query_one(PanelMenu)
relationships =''',''' native_menu = native_bar.query_one(PanelMenu)
from acp.schema import SetSessionConfigOptionResponse
from support.agents import AppAgents
from toad.configured_view import AgentProperties
from toad.widgets.model_switcher import SessionForm
agent = AppAgents(app).detached_agent('sidebar-settings')
native.conversation.bind_agent(agent)
agent.configuration.receive(SetSessionConfigOptionResponse.model_validate({'configOptions': [
{'id': 'sample-budget', 'name': 'Budget', 'type': 'boolean', 'currentValue': True},
]}).config_options)
agent_entry = next(entry for entry in native_menu.entries if isinstance(entry.widget, AgentProperties))
native_menu.picker.value = agent_entry
await ui.until(lambda: agent_entry.widget.is_mounted and bool(agent_entry.widget.query(SessionForm)),
why='the actual advertised session form')
await ui.until(lambda: agent_entry.widget.form.represents(agent.configuration),
why='new advertisements replace the original fields')
assert agent_entry.widget.form.prompt is native.conversation.prompt
assert 'Budget' in {row.field.label for row in agent_entry.widget.form.values.values()}
agent.configuration.receive(SetSessionConfigOptionResponse.model_validate({'configOptions': [
{'id': 'sample-budget', 'name': 'Budget', 'type': 'boolean', 'currentValue': False},
{'id': 'new-setting', 'name': 'New setting', 'type': 'boolean', 'currentValue': True},
]}).config_options)
await ui.until(lambda: agent_entry.widget.form.represents(agent.configuration),
why='the sidebar follows the source update')
assert 'New setting' in {row.field.label for row in agent_entry.widget.form.values.values()}
relationships =''')
# FieldView already admits every visible declaration; retain its inherited answer.
Path('.verification/object-settings-sources/agent-control.plan.json').write_text(json.dumps({'recipes':[{'recipe_id':'selected-session-advertisement-control','operations':ops}]},indent=2))
Loading
Loading