@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.
- package/lib/chat.py +66 -0
- 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()
|