by-framework 0.2.2.dev2__py3-none-any.whl → 0.2.2.dev4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. by_framework/client/client.py +15 -7
  2. by_framework/core/__init__.py +69 -0
  3. by_framework/core/availability.py +495 -0
  4. by_framework/core/delivery_gate.py +60 -0
  5. by_framework/core/discovery.py +359 -0
  6. by_framework/core/extensions/__init__.py +29 -0
  7. by_framework/core/extensions/agent_config.py +64 -0
  8. by_framework/core/extensions/plugin.py +312 -0
  9. by_framework/core/extensions/registry.py +704 -0
  10. by_framework/core/extensions/trace_provider.py +20 -0
  11. by_framework/core/protocol/__init__.py +99 -0
  12. by_framework/core/protocol/action_type.py +33 -0
  13. by_framework/core/protocol/agent_state.py +78 -0
  14. by_framework/core/protocol/byai_codec.py +96 -0
  15. by_framework/core/protocol/byai_command.py +53 -0
  16. by_framework/core/protocol/byai_types.py +7 -0
  17. by_framework/core/protocol/commands.py +285 -0
  18. by_framework/core/protocol/content_codec.py +17 -0
  19. by_framework/core/protocol/content_type.py +38 -0
  20. by_framework/core/protocol/data_message.py +45 -0
  21. by_framework/core/protocol/data_shapes.py +83 -0
  22. by_framework/core/protocol/event_type.py +34 -0
  23. by_framework/core/protocol/events.py +69 -0
  24. by_framework/core/protocol/message.py +99 -0
  25. by_framework/core/protocol/message_header.py +78 -0
  26. by_framework/core/protocol/responses.py +94 -0
  27. by_framework/core/protocol/results.py +149 -0
  28. by_framework/core/registry.py +1102 -0
  29. by_framework/core/runtime/__init__.py +27 -0
  30. by_framework/core/runtime/agent_config_manager.py +283 -0
  31. by_framework/core/runtime/agent_runtime_state.py +75 -0
  32. by_framework/core/runtime/file_manager.py +434 -0
  33. by_framework/core/runtime/file_paths.py +76 -0
  34. by_framework/core/runtime/file_permissions.py +71 -0
  35. by_framework/core/runtime/filestore/__init__.py +15 -0
  36. by_framework/core/runtime/filestore/base.py +140 -0
  37. by_framework/core/runtime/filestore/local.py +313 -0
  38. by_framework/core/runtime/history/__init__.py +10 -0
  39. by_framework/core/runtime/history/base.py +57 -0
  40. by_framework/core/runtime/history/history_manager.py +55 -0
  41. by_framework/core/runtime/history/in_memory.py +58 -0
  42. by_framework/core/runtime/session_manager.py +118 -0
  43. by_framework/core/wakeup_controller.py +149 -0
  44. by_framework/core/workspace.py +126 -0
  45. {by_framework-0.2.2.dev2.dist-info → by_framework-0.2.2.dev4.dist-info}/METADATA +1 -1
  46. by_framework-0.2.2.dev4.dist-info/RECORD +92 -0
  47. by_framework-0.2.2.dev2.dist-info/RECORD +0 -49
  48. {by_framework-0.2.2.dev2.dist-info → by_framework-0.2.2.dev4.dist-info}/WHEEL +0 -0
  49. {by_framework-0.2.2.dev2.dist-info → by_framework-0.2.2.dev4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,312 @@
1
+ """
2
+ Plugin system core definitions.
3
+
4
+ This module provides the Plugin abstract base class and supporting types
5
+ for the extensible plugin architecture of the Gateway SDK.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import inspect
11
+ from abc import ABC, abstractmethod
12
+ from dataclasses import dataclass, field
13
+ from string import Formatter
14
+ from typing import TYPE_CHECKING, Any, List, Type
15
+
16
+ from .agent_config import AgentConfig
17
+
18
+ if TYPE_CHECKING:
19
+ from by_framework.core.protocol.commands import (AskAgentCommand,
20
+ CancelTaskCommand,
21
+ ResumeCommand)
22
+ from by_framework.worker.context import AgentContext
23
+ from by_framework.worker.worker import GatewayWorker
24
+
25
+
26
+ @dataclass
27
+ class PromptTemplate:
28
+ """Prompt template utility type that supports variable placeholders.
29
+
30
+ Can be placed in AgentConfig.prompts.
31
+
32
+ Attributes:
33
+ content: Template content string, supports {variable} format placeholders
34
+ variables: List of automatically extracted variable names
35
+ """
36
+
37
+ content: str
38
+ variables: List[str] = field(default_factory=list)
39
+
40
+ def __post_init__(self) -> None:
41
+ if not self.variables:
42
+ self.variables = self._extract_variables(self.content)
43
+
44
+ @staticmethod
45
+ def _extract_variables(content: str) -> List[str]:
46
+ """Extract all variable names from template content."""
47
+ field_names: List[str] = []
48
+ for _, field_name, _, _ in Formatter().parse(content):
49
+ if field_name:
50
+ field_names.append(field_name)
51
+ return field_names
52
+
53
+ def render(self, **kwargs: Any) -> str:
54
+ """Render the template using the provided variable values.
55
+
56
+ Args:
57
+ **kwargs: Mapping of variable names to values
58
+
59
+ Returns:
60
+ Rendered string
61
+
62
+ Raises:
63
+ KeyError: If provided variables are incomplete
64
+ """
65
+ missing = [var for var in self.variables if var not in kwargs]
66
+ if missing:
67
+ raise KeyError(
68
+ f"Prompt missing variables: {missing}; "
69
+ f"provided keys: {sorted(kwargs.keys())}"
70
+ )
71
+ return self.content.format(**kwargs)
72
+
73
+
74
+ @dataclass
75
+ class PluginManifest:
76
+ """Plugin manifest information.
77
+
78
+ Attributes:
79
+ plugin_id: Plugin unique identifier
80
+ version: Plugin version number
81
+ priority: Plugin priority, higher number runs earlier
82
+ enabled: Whether the plugin is enabled
83
+ """
84
+
85
+ plugin_id: str
86
+ version: str = "1.0.0"
87
+ priority: int = 0
88
+ enabled: bool = True
89
+
90
+
91
+ @dataclass
92
+ class PluginBuildContext:
93
+ """Build context used during plugin registration phase (not runtime).
94
+
95
+ Provides read-only access and write capability to AgentConfig during
96
+ plugin registration.
97
+ """
98
+
99
+ agent_configs: list[AgentConfig] = field(default_factory=list)
100
+ _prev_agent_configs: tuple[AgentConfig, ...] = ()
101
+
102
+ def set_agent_configs(self, new_configs: list[AgentConfig]) -> None:
103
+ """Set new AgentConfig list."""
104
+ self.agent_configs = list(new_configs)
105
+
106
+ def list_agent_configs(self) -> list[AgentConfig]:
107
+ """Return a copy of the current AgentConfig list."""
108
+ return list(self.agent_configs)
109
+
110
+ def freeze_prev_agent_configs(self) -> None:
111
+ """Freeze current AgentConfigs as a read-only snapshot."""
112
+ self._prev_agent_configs = tuple(self.agent_configs)
113
+
114
+ def get_prev_agent_configs(self) -> tuple[AgentConfig, ...]:
115
+ """Get the read-only snapshot of the previous version of AgentConfigs."""
116
+ return self._prev_agent_configs
117
+
118
+
119
+ @dataclass(frozen=True)
120
+ class AgentConfigsSnapshot:
121
+ """Immutable view of a stable AgentConfig collection version."""
122
+
123
+ version: int
124
+ configs: tuple[AgentConfig, ...]
125
+
126
+
127
+ @dataclass(frozen=True)
128
+ class PluginReloadContext:
129
+ """Context passed to plugin reload hooks.
130
+
131
+ The current_agent_configs field represents the working config list for the
132
+ current reload stage. Plugins can transform that list and return the next
133
+ full config version.
134
+ """
135
+
136
+ plugin_id: str
137
+ reload_id: str
138
+ reason: str
139
+ current_agent_configs: tuple[AgentConfig, ...]
140
+ previous_stable_agent_configs: tuple[AgentConfig, ...]
141
+ current_version: int
142
+
143
+
144
+ @dataclass(frozen=True)
145
+ class PluginReloadResult:
146
+ """Optional structured result for reload workflows."""
147
+
148
+ agent_configs: tuple[AgentConfig, ...]
149
+
150
+
151
+ class Plugin(ABC):
152
+ """Plugin abstract base class.
153
+
154
+ Plugins are responsible for registering AgentConfig and optionally providing
155
+ lifecycle hooks. Create a plugin by inheriting from this class and implementing
156
+ the register_agent_configs method.
157
+ """
158
+
159
+ _registered_plugins: List[Type["Plugin"]] = []
160
+
161
+ def __init_subclass__(cls, **kwargs):
162
+ super().__init_subclass__(**kwargs)
163
+ if not inspect.isabstract(cls):
164
+ Plugin._registered_plugins.append(cls)
165
+
166
+ @classmethod
167
+ def get_registered_plugins(cls) -> List[Type["Plugin"]]:
168
+ """Get all registered plugin classes."""
169
+ return cls._registered_plugins
170
+
171
+ def __init__(
172
+ self, manifest: PluginManifest, hook_timeout_seconds: float | None = None
173
+ ):
174
+ self.manifest = manifest
175
+ self.name = manifest.plugin_id
176
+ self.plugin_id = manifest.plugin_id
177
+ self.version = manifest.version
178
+ self.hook_timeout_seconds = hook_timeout_seconds
179
+
180
+ @abstractmethod
181
+ async def register_agent_configs(
182
+ self, build_context: PluginBuildContext
183
+ ) -> list[AgentConfig] | None:
184
+ """Plugin registration entry method.
185
+
186
+ Plugin can read the read-only snapshot of build_context and return a new
187
+ agent_configs list.
188
+
189
+ Args:
190
+ build_context: Plugin build context
191
+
192
+ Returns:
193
+ New AgentConfig list, or None
194
+ """
195
+ raise NotImplementedError
196
+
197
+ async def reload(
198
+ self,
199
+ context: PluginReloadContext,
200
+ ) -> list[AgentConfig] | PluginReloadResult | None:
201
+ """Transform the current stable config chain into the next version.
202
+
203
+ Default behavior is a no-op so existing plugins remain compatible.
204
+ Plugins that support hot reload can override this method to return the
205
+ next full AgentConfig list for the current reload stage.
206
+ """
207
+ return list(context.current_agent_configs)
208
+
209
+ async def on_worker_startup(self, worker: "GatewayWorker") -> None:
210
+ """Hook called when Worker starts.
211
+
212
+ Args:
213
+ worker: GatewayWorker instance
214
+ """
215
+ pass
216
+
217
+ async def on_worker_shutdown(self, worker: "GatewayWorker") -> None:
218
+ """Hook called when Worker shuts down.
219
+
220
+ Args:
221
+ worker: GatewayWorker instance
222
+ """
223
+ pass
224
+
225
+ async def on_task_start(self, context: "AgentContext") -> None:
226
+ """Hook called when task starts.
227
+
228
+ Args:
229
+ context: AgentContext instance
230
+ """
231
+ pass
232
+
233
+ async def on_task_complete(self, context: "AgentContext", result: Any) -> None:
234
+ """Hook called when task completes.
235
+
236
+ Args:
237
+ context: AgentContext instance
238
+ result: Task execution result
239
+ """
240
+ pass
241
+
242
+ async def on_task_error(self, context: "AgentContext", error: Exception) -> None:
243
+ """Hook called when task encounters an error.
244
+
245
+ Args:
246
+ context: AgentContext instance
247
+ error: Exception object
248
+ """
249
+ pass
250
+
251
+ async def on_task_cancel(
252
+ self, context: "AgentContext", command: "CancelTaskCommand"
253
+ ) -> None:
254
+ """Hook called when task is cancelled.
255
+
256
+ Args:
257
+ context: AgentContext instance
258
+ command: Cancel task command
259
+ """
260
+ pass
261
+
262
+ async def on_call_agent_start(
263
+ self, context: "AgentContext", command: "AskAgentCommand"
264
+ ) -> None:
265
+ """Hook triggered before calling another Agent."""
266
+ pass
267
+
268
+ async def on_call_agent_complete(
269
+ self,
270
+ context: "AgentContext",
271
+ command: "AskAgentCommand",
272
+ result: Any,
273
+ ) -> None:
274
+ """Hook triggered after successfully enqueuing a call to another Agent."""
275
+ pass
276
+
277
+ async def on_call_agent_error(
278
+ self,
279
+ context: "AgentContext",
280
+ command: "AskAgentCommand",
281
+ error: Exception,
282
+ ) -> None:
283
+ """Hook triggered when calling another Agent fails."""
284
+ pass
285
+
286
+ async def on_agent_return_start(
287
+ self,
288
+ context: "AgentContext",
289
+ command: "AskAgentCommand",
290
+ callback_command: "ResumeCommand",
291
+ ) -> None:
292
+ """Hook triggered before enqueueing a ResumeCommand to the caller."""
293
+ pass
294
+
295
+ async def on_agent_return_complete(
296
+ self,
297
+ context: "AgentContext",
298
+ command: "AskAgentCommand",
299
+ callback_command: "ResumeCommand",
300
+ ) -> None:
301
+ """Hook triggered after successfully enqueueing a ResumeCommand."""
302
+ pass
303
+
304
+ async def on_agent_return_error(
305
+ self,
306
+ context: "AgentContext",
307
+ command: "AskAgentCommand",
308
+ callback_command: "ResumeCommand",
309
+ error: Exception,
310
+ ) -> None:
311
+ """Hook triggered when enqueueing a ResumeCommand fails."""
312
+ pass