monkeybot 2.1.1__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 (178) hide show
  1. monkeybot/__init__.py +3 -0
  2. monkeybot/cli/__init__.py +3 -0
  3. monkeybot/cli/__main__.py +8 -0
  4. monkeybot/cli/audio_io.py +8 -0
  5. monkeybot/cli/gateway_manager.py +17 -0
  6. monkeybot/cli/main.py +22 -0
  7. monkeybot/cli/push_to_talk.py +12 -0
  8. monkeybot/cli/realtime_client.py +13 -0
  9. monkeybot/core/__init__.py +19 -0
  10. monkeybot/core/attachments/__init__.py +22 -0
  11. monkeybot/core/attachments/catalog.py +62 -0
  12. monkeybot/core/attachments/config.py +52 -0
  13. monkeybot/core/attachments/freeze.py +158 -0
  14. monkeybot/core/attachments/resolve.py +70 -0
  15. monkeybot/core/attachments/store.py +180 -0
  16. monkeybot/core/attachments/text.py +72 -0
  17. monkeybot/core/attachments/tools.py +54 -0
  18. monkeybot/core/bootstrap.py +242 -0
  19. monkeybot/core/config/__init__.py +71 -0
  20. monkeybot/core/config/realtime_config.py +150 -0
  21. monkeybot/core/config/runtime_env.py +262 -0
  22. monkeybot/core/config/settings.py +341 -0
  23. monkeybot/core/config/validation.py +249 -0
  24. monkeybot/core/config/yaml_loader.py +45 -0
  25. monkeybot/core/context/__init__.py +781 -0
  26. monkeybot/core/context/campaign_context.py +8 -0
  27. monkeybot/core/context/common.py +14 -0
  28. monkeybot/core/context/curator.py +255 -0
  29. monkeybot/core/context/epoch.py +226 -0
  30. monkeybot/core/context/memory_prompt.py +222 -0
  31. monkeybot/core/context/tool_output_policy.py +270 -0
  32. monkeybot/core/context/tool_result_ingress.py +290 -0
  33. monkeybot/core/context/tool_shapers.py +361 -0
  34. monkeybot/core/hooks/__init__.py +261 -0
  35. monkeybot/core/llm/__init__.py +4 -0
  36. monkeybot/core/llm/provider.py +296 -0
  37. monkeybot/core/llm/realtime_provider.py +203 -0
  38. monkeybot/core/llm/usage.py +57 -0
  39. monkeybot/core/logging_utils.py +24 -0
  40. monkeybot/core/mcp/__init__.py +1 -0
  41. monkeybot/core/mcp/mcp_client.py +1215 -0
  42. monkeybot/core/mcp/ports_mcp.py +109 -0
  43. monkeybot/core/memory/__init__.py +24 -0
  44. monkeybot/core/memory/hook.py +413 -0
  45. monkeybot/core/memory/index_format.py +104 -0
  46. monkeybot/core/memory/integrity.py +180 -0
  47. monkeybot/core/memory/organizer.py +270 -0
  48. monkeybot/core/memory/storage_ops.py +139 -0
  49. monkeybot/core/memory/subsystem.py +91 -0
  50. monkeybot/core/messages/__init__.py +16 -0
  51. monkeybot/core/messages/convert_provider.py +41 -0
  52. monkeybot/core/messages/tool_integrity.py +262 -0
  53. monkeybot/core/messages/transform_context.py +84 -0
  54. monkeybot/core/path_safety.py +11 -0
  55. monkeybot/core/persistence/__init__.py +17 -0
  56. monkeybot/core/persistence/backends.py +236 -0
  57. monkeybot/core/persistence/db.py +28 -0
  58. monkeybot/core/persistence/durable_runs.py +286 -0
  59. monkeybot/core/persistence/firestore.py +658 -0
  60. monkeybot/core/persistence/firestore_scheduled_loops.py +336 -0
  61. monkeybot/core/persistence/history.py +156 -0
  62. monkeybot/core/persistence/postgres.py +895 -0
  63. monkeybot/core/persistence/runs.py +76 -0
  64. monkeybot/core/persistence/scheduled_loops.py +435 -0
  65. monkeybot/core/persistence/session_turn_locks.py +94 -0
  66. monkeybot/core/persistence/sqlite.py +218 -0
  67. monkeybot/core/persistence/sqlite_backend.py +74 -0
  68. monkeybot/core/persistence/thread_summary.py +61 -0
  69. monkeybot/core/persistence/transcript.py +194 -0
  70. monkeybot/core/persistence/usage.py +149 -0
  71. monkeybot/core/prompts/__init__.py +1 -0
  72. monkeybot/core/prompts/harness_prompt.py +197 -0
  73. monkeybot/core/prompts/prompt.py +215 -0
  74. monkeybot/core/runtime/__init__.py +1 -0
  75. monkeybot/core/runtime/context_budget.py +267 -0
  76. monkeybot/core/runtime/events.py +819 -0
  77. monkeybot/core/runtime/input_admission.py +154 -0
  78. monkeybot/core/runtime/loop.py +2374 -0
  79. monkeybot/core/runtime/provider_stream_mapper.py +159 -0
  80. monkeybot/core/runtime/realtime_loop.py +654 -0
  81. monkeybot/core/runtime/utterance_buffer.py +179 -0
  82. monkeybot/core/subagents/__init__.py +1 -0
  83. monkeybot/core/subagents/subagent_proto.py +331 -0
  84. monkeybot/core/subagents/subagent_worker.py +441 -0
  85. monkeybot/core/subagents/worker_pool.py +403 -0
  86. monkeybot/core/testing/__init__.py +1 -0
  87. monkeybot/core/testing/mocks_provider.py +86 -0
  88. monkeybot/core/testing/mocks_realtime_provider.py +137 -0
  89. monkeybot/core/tools/__init__.py +1 -0
  90. monkeybot/core/tools/core_tool_executor.py +1548 -0
  91. monkeybot/core/tools/inspector.py +226 -0
  92. monkeybot/core/tools/loop_inspector.py +45 -0
  93. monkeybot/core/tools/patch.py +480 -0
  94. monkeybot/core/tools/permission.py +284 -0
  95. monkeybot/core/tools/sandbox_executor.py +255 -0
  96. monkeybot/core/tools/spill_inventory.py +35 -0
  97. monkeybot/core/tools/terminal.py +381 -0
  98. monkeybot/core/tools/text_normalize.py +25 -0
  99. monkeybot/core/tools/types.py +33 -0
  100. monkeybot/core/tools/workspace_service.py +710 -0
  101. monkeybot/core/tools/workspace_tools.py +116 -0
  102. monkeybot/core/types/__init__.py +1 -0
  103. monkeybot/core/types/content_blocks.py +644 -0
  104. monkeybot/core/types/interfaces.py +156 -0
  105. monkeybot/core/types/types_tools.py +29 -0
  106. monkeybot/core/workspace/__init__.py +8 -0
  107. monkeybot/core/workspace/factory.py +45 -0
  108. monkeybot/core/workspace/gcs.py +130 -0
  109. monkeybot/core/workspace/local.py +162 -0
  110. monkeybot/core/workspace/protocol.py +45 -0
  111. monkeybot/core/workspace/s3.py +151 -0
  112. monkeybot/core/workspace_layout.py +27 -0
  113. monkeybot/gateway/__init__.py +1 -0
  114. monkeybot/gateway/bootstrap.py +18 -0
  115. monkeybot/gateway/main.py +47 -0
  116. monkeybot/gateway/realtime/__init__.py +31 -0
  117. monkeybot/gateway/realtime/app.py +321 -0
  118. monkeybot/gateway/realtime/deps.py +52 -0
  119. monkeybot/gateway/realtime/errors.py +81 -0
  120. monkeybot/gateway/realtime/guardrails.py +88 -0
  121. monkeybot/gateway/realtime/manager.py +77 -0
  122. monkeybot/gateway/realtime/metrics.py +144 -0
  123. monkeybot/gateway/realtime/routes.py +864 -0
  124. monkeybot/gateway/realtime/session.py +232 -0
  125. monkeybot/gateway/realtime/wire.py +412 -0
  126. monkeybot/gateway/realtime_main.py +49 -0
  127. monkeybot/gateway/sse/__init__.py +1 -0
  128. monkeybot/gateway/sse/app.py +733 -0
  129. monkeybot/gateway/sse/loop_port.py +31 -0
  130. monkeybot/gateway/sse/models.py +177 -0
  131. monkeybot/gateway/sse/reply_body.py +91 -0
  132. monkeybot/gateway/sse/routes.py +1101 -0
  133. monkeybot/gateway/sse/scheduler_routes.py +200 -0
  134. monkeybot/gateway/sse/scheduler_wiring.py +96 -0
  135. monkeybot/gateway/sse/session_bus.py +226 -0
  136. monkeybot/gateway/sse/sse.py +46 -0
  137. monkeybot/gateway/sse/workspace_layout.py +7 -0
  138. monkeybot/observability/__init__.py +220 -0
  139. monkeybot/observability/_state.py +10 -0
  140. monkeybot/observability/instrumentation.py +153 -0
  141. monkeybot/observability/propagation.py +65 -0
  142. monkeybot/observability/spans.py +455 -0
  143. monkeybot/providers/__init__.py +19 -0
  144. monkeybot/providers/_openai_compat.py +450 -0
  145. monkeybot/providers/_utils.py +473 -0
  146. monkeybot/providers/bedrock.py +145 -0
  147. monkeybot/providers/claude.py +125 -0
  148. monkeybot/providers/gemini.py +677 -0
  149. monkeybot/providers/gemini_live.py +398 -0
  150. monkeybot/providers/huggingface.py +129 -0
  151. monkeybot/providers/nvidia.py +104 -0
  152. monkeybot/providers/ollama.py +152 -0
  153. monkeybot/providers/openai.py +127 -0
  154. monkeybot/providers/pricing.py +60 -0
  155. monkeybot/providers/sampling.py +44 -0
  156. monkeybot/providers/vertex_claude.py +148 -0
  157. monkeybot/scaffold/__init__.py +33 -0
  158. monkeybot/scheduler/__init__.py +13 -0
  159. monkeybot/scheduler/__main__.py +4 -0
  160. monkeybot/scheduler/engine.py +333 -0
  161. monkeybot/scheduler/http_invoker.py +61 -0
  162. monkeybot/scheduler/interval.py +77 -0
  163. monkeybot/scheduler/tick_result.py +34 -0
  164. monkeybot/scheduler/worker.py +87 -0
  165. monkeybot/subagents/__init__.py +1 -0
  166. monkeybot/subagents/worker/__init__.py +1 -0
  167. monkeybot/subagents/worker/__main__.py +22 -0
  168. monkeybot/web_search/__init__.py +82 -0
  169. monkeybot/web_search/backends/__init__.py +5 -0
  170. monkeybot/web_search/backends/duckduckgo.py +32 -0
  171. monkeybot/web_search/backends/firecrawl.py +43 -0
  172. monkeybot/web_search/backends/tavily.py +45 -0
  173. monkeybot/web_search/protocol.py +25 -0
  174. monkeybot/web_search/tool.py +56 -0
  175. monkeybot-2.1.1.dist-info/METADATA +318 -0
  176. monkeybot-2.1.1.dist-info/RECORD +178 -0
  177. monkeybot-2.1.1.dist-info/WHEEL +4 -0
  178. monkeybot-2.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,154 @@
1
+ """Steer and follow-up input queues for mid-turn and idle admission.
2
+
3
+ Two queues, intentionally separate from HITL ``ToolConfirmationRequest``:
4
+
5
+ * **Steer** — inject user text at the next safe loop boundary (after the current
6
+ tool batch / before the next provider call) while a turn is in flight.
7
+ * **Follow-up** — FIFO prompts drained when the session would otherwise go idle
8
+ (after ``TurnComplete`` / lock release).
9
+
10
+ Gateway routes enqueue; the agent loop and gateway drain.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import os
16
+ from collections import deque
17
+ from dataclasses import dataclass
18
+
19
+ from monkeybot.core.types.content_blocks import ContentBlock, Text
20
+
21
+
22
+ class AdmissionQueueFullError(Exception):
23
+ """Raised when a steer or follow-up queue is at capacity."""
24
+
25
+ def __init__(self, queue: str, max_size: int) -> None:
26
+ super().__init__(f"{queue} queue is full (max {max_size})")
27
+ self.queue = queue
28
+ self.max_size = max_size
29
+
30
+
31
+ def _queue_limit(env_name: str, default: int) -> int:
32
+ raw = os.environ.get(env_name)
33
+ if raw is None or raw.strip() == "":
34
+ return default
35
+ try:
36
+ return max(1, int(raw))
37
+ except ValueError:
38
+ return default
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class FollowUpItem:
43
+ """One queued prompt waiting for an idle session.
44
+
45
+ ``first_lock_fail_at_ms`` is set when a drain attempt fails to acquire the
46
+ durable session turn lock; used to bound how long we retry before dropping.
47
+ """
48
+
49
+ request_id: str
50
+ content: list[ContentBlock]
51
+ first_lock_fail_at_ms: int | None = None
52
+
53
+
54
+ class InputAdmission:
55
+ """Per-session steer + follow-up queues."""
56
+
57
+ def __init__(
58
+ self,
59
+ *,
60
+ max_steer: int | None = None,
61
+ max_follow_up: int | None = None,
62
+ ) -> None:
63
+ self.max_steer = (
64
+ max_steer
65
+ if max_steer is not None
66
+ else _queue_limit("MONKEYBOT_STEER_QUEUE_MAX", 8)
67
+ )
68
+ self.max_follow_up = (
69
+ max_follow_up
70
+ if max_follow_up is not None
71
+ else _queue_limit("MONKEYBOT_FOLLOW_UP_QUEUE_MAX", 16)
72
+ )
73
+ self._steer: deque[list[ContentBlock]] = deque()
74
+ self._follow_up: deque[FollowUpItem] = deque()
75
+
76
+ @property
77
+ def steer_depth(self) -> int:
78
+ return len(self._steer)
79
+
80
+ @property
81
+ def follow_up_depth(self) -> int:
82
+ return len(self._follow_up)
83
+
84
+ def enqueue_steer(self, content: list[ContentBlock]) -> int:
85
+ """Append steer content; return 0-based queue position.
86
+
87
+ Raises:
88
+ AdmissionQueueFullError: when at capacity.
89
+ ValueError: when ``content`` is empty.
90
+ """
91
+ if not content:
92
+ raise ValueError("steer content must be non-empty")
93
+ if len(self._steer) >= self.max_steer:
94
+ raise AdmissionQueueFullError("steer", self.max_steer)
95
+ self._steer.append(list(content))
96
+ return len(self._steer) - 1
97
+
98
+ def enqueue_follow_up(
99
+ self, request_id: str, content: list[ContentBlock]
100
+ ) -> int:
101
+ """Append a follow-up prompt; return 0-based queue position."""
102
+ if not request_id.strip():
103
+ raise ValueError("follow-up request_id must be non-empty")
104
+ if not content:
105
+ raise ValueError("follow-up content must be non-empty")
106
+ if len(self._follow_up) >= self.max_follow_up:
107
+ raise AdmissionQueueFullError("follow_up", self.max_follow_up)
108
+ self._follow_up.append(FollowUpItem(request_id=request_id, content=list(content)))
109
+ return len(self._follow_up) - 1
110
+
111
+ def pop_steer(self) -> list[ContentBlock] | None:
112
+ """Take the oldest steer message, or ``None`` if empty."""
113
+ if not self._steer:
114
+ return None
115
+ return self._steer.popleft()
116
+
117
+ def pop_follow_up(self) -> FollowUpItem | None:
118
+ """Take the oldest follow-up, or ``None`` if empty."""
119
+ if not self._follow_up:
120
+ return None
121
+ return self._follow_up.popleft()
122
+
123
+ def requeue_follow_up_front(self, item: FollowUpItem) -> None:
124
+ """Put a follow-up back at the front (failed lock acquire)."""
125
+ self._follow_up.appendleft(item)
126
+
127
+ def clear_steer(self) -> None:
128
+ """Drop pending steer injections (e.g. on cancel)."""
129
+ self._steer.clear()
130
+
131
+ def clear_all(self) -> None:
132
+ """Drop steer and follow-up queues (session teardown)."""
133
+ self._steer.clear()
134
+ self._follow_up.clear()
135
+
136
+
137
+ def preview_text(content: list[ContentBlock], *, limit: int = 200) -> str:
138
+ """Short plain-text preview for observability events."""
139
+ parts: list[str] = []
140
+ for block in content:
141
+ if isinstance(block, Text) and block.text.strip():
142
+ parts.append(block.text.strip())
143
+ joined = " ".join(parts).strip()
144
+ if len(joined) <= limit:
145
+ return joined
146
+ return joined[: limit - 1] + "…"
147
+
148
+
149
+ __all__ = [
150
+ "AdmissionQueueFullError",
151
+ "FollowUpItem",
152
+ "InputAdmission",
153
+ "preview_text",
154
+ ]