@tjamescouch/agentchat 0.12.0 → 0.13.0

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 (2) hide show
  1. package/lib/chat.py +66 -0
  2. package/package.json +1 -1
package/lib/chat.py CHANGED
@@ -103,6 +103,62 @@ def poll_new(paths: dict):
103
103
  return messages
104
104
 
105
105
 
106
+ def wait_for_messages(paths: dict, interval: float = 2.0, timeout: float = 300.0):
107
+ """Block until new messages arrive. Returns messages or empty list on timeout."""
108
+ import signal
109
+ import time
110
+
111
+ stop_file = paths["inbox"].parent.parent.parent / "stop"
112
+
113
+ # Handle interrupts gracefully
114
+ interrupted = False
115
+ def handle_signal(signum, frame):
116
+ nonlocal interrupted
117
+ interrupted = True
118
+
119
+ old_handler = signal.signal(signal.SIGINT, handle_signal)
120
+
121
+ try:
122
+ start = time.time()
123
+ while not interrupted and (time.time() - start) < timeout:
124
+ # Check stop file
125
+ if stop_file.exists():
126
+ try:
127
+ stop_file.unlink()
128
+ except FileNotFoundError:
129
+ pass
130
+ return [] # Signal to stop
131
+
132
+ # Check semaphore
133
+ if paths["newdata"].exists():
134
+ messages = read_inbox(paths)
135
+ # Filter out @server messages
136
+ messages = [m for m in messages if m.get("from") != "@server"]
137
+
138
+ if messages:
139
+ # Update timestamp
140
+ max_ts = max(m.get("ts", 0) for m in messages)
141
+ set_last_ts(paths, max_ts)
142
+ # Clear semaphore
143
+ try:
144
+ paths["newdata"].unlink()
145
+ except FileNotFoundError:
146
+ pass
147
+ return messages
148
+
149
+ # Semaphore but no messages after filtering - clear and continue
150
+ try:
151
+ paths["newdata"].unlink()
152
+ except FileNotFoundError:
153
+ pass
154
+
155
+ time.sleep(interval)
156
+
157
+ return [] # Timeout
158
+ finally:
159
+ signal.signal(signal.SIGINT, old_handler)
160
+
161
+
106
162
  def main():
107
163
  parser = argparse.ArgumentParser(description="AgentChat daemon helper")
108
164
  parser.add_argument("--daemon-dir", type=Path, default=DEFAULT_DAEMON_DIR,
@@ -133,6 +189,11 @@ def main():
133
189
  # poll command - efficient check using semaphore
134
190
  poll_p = subparsers.add_parser("poll", help="Poll for new messages (uses semaphore, silent if none)")
135
191
 
192
+ # wait command - block until messages arrive
193
+ wait_p = subparsers.add_parser("wait", help="Block until new messages arrive")
194
+ wait_p.add_argument("--interval", type=float, default=2.0, help="Poll interval in seconds")
195
+ wait_p.add_argument("--timeout", type=float, default=300.0, help="Max wait time in seconds")
196
+
136
197
  args = parser.parse_args()
137
198
  paths = get_paths(args.daemon_dir)
138
199
 
@@ -170,6 +231,11 @@ def main():
170
231
  print(json.dumps(msg))
171
232
  # Empty list = semaphore existed but no new messages after filtering
172
233
 
234
+ elif args.command == "wait":
235
+ messages = wait_for_messages(paths, interval=args.interval, timeout=args.timeout)
236
+ for msg in messages:
237
+ print(json.dumps(msg))
238
+
173
239
 
174
240
  if __name__ == "__main__":
175
241
  main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tjamescouch/agentchat",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Real-time IRC-like communication protocol for AI agents",
5
5
  "main": "lib/client.js",
6
6
  "files": [