thinkpool-pair 0.7.256 → 0.7.257

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.
@@ -145,6 +145,57 @@ def constrained_expand(toolsets_arg=None, mcp_server_names=None):
145
145
  acp_adapter.session._expand_acp_enabled_toolsets = constrained_expand
146
146
 
147
147
  import acp_adapter.server
148
+
149
+ # Hermes 0.18.2 emits the real result through ``tool.completed`` immediately,
150
+ # but its ACP callback ignores that event and waits for the next model-step
151
+ # summary. Parallel Read/search calls are not always present in that summary,
152
+ # leaving clients with a ToolCallStart and no ToolCallUpdate forever. Complete
153
+ # from the authoritative execution callback and consume the same per-name FIFO;
154
+ # the later step callback then sees an empty queue and cannot double-emit. If a
155
+ # future Hermes release handles completion itself, it consumes the queue before
156
+ # this wrapper runs and this compatibility branch becomes a no-op.
157
+ from collections import deque
158
+ import acp_adapter.events
159
+ import acp_adapter.tools
160
+
161
+ _tool_progress_factory = acp_adapter.server.make_tool_progress_cb
162
+ def completion_aware_tool_progress_factory(
163
+ conn, session_id, loop, tool_call_ids, tool_call_meta,
164
+ edit_approval_policy_getter=None,
165
+ ):
166
+ upstream = _tool_progress_factory(
167
+ conn, session_id, loop, tool_call_ids, tool_call_meta,
168
+ edit_approval_policy_getter=edit_approval_policy_getter,
169
+ )
170
+
171
+ def progress(event_type, name=None, preview=None, args=None, **kwargs):
172
+ upstream(event_type, name, preview, args, **kwargs)
173
+ if event_type != "tool.completed" or not name:
174
+ return
175
+ queue = tool_call_ids.get(name)
176
+ if isinstance(queue, str):
177
+ queue = deque([queue])
178
+ tool_call_ids[name] = queue
179
+ if not queue:
180
+ return
181
+ tool_call_id = queue.popleft()
182
+ meta = tool_call_meta.pop(tool_call_id, {})
183
+ result = kwargs.get("result")
184
+ update = acp_adapter.tools.build_tool_complete(
185
+ tool_call_id,
186
+ name,
187
+ result=str(result) if result is not None else None,
188
+ function_args=meta.get("args"),
189
+ snapshot=meta.get("snapshot"),
190
+ )
191
+ acp_adapter.events._send_update(conn, session_id, loop, update)
192
+ if not queue:
193
+ tool_call_ids.pop(name, None)
194
+
195
+ return progress
196
+
197
+ acp_adapter.server.make_tool_progress_cb = completion_aware_tool_progress_factory
198
+
148
199
  _register = acp_adapter.server.HermesACPAgent._register_session_mcp_servers
149
200
  async def constrained_register(self, state, mcp_servers):
150
201
  if any(getattr(server, "name", None) != "thinkpool" for server in (mcp_servers or [])):
@@ -128,16 +128,17 @@ export class HermesEventMapper {
128
128
  }
129
129
 
130
130
  finishTurn({ stopReason = 'end_turn', usage = null } = {}) {
131
- if (stopReason === 'cancelled') {
132
- for (const [toolCallId, tool] of this.tools) {
133
- this._emit({
134
- kind: 'tool_result', toolUseId: toolCallId,
135
- content: [{ type: 'text', text: '[cancelled]' }],
136
- isError: false,
137
- durationMs: tool.startedAt ? Date.now() - tool.startedAt : undefined,
138
- parentToolUseId: null,
139
- })
140
- }
131
+ for (const [toolCallId, tool] of this.tools) {
132
+ const cancelled = stopReason === 'cancelled'
133
+ this._emit({
134
+ kind: 'tool_result', toolUseId: toolCallId,
135
+ content: [{ type: 'text', text: cancelled ? '[cancelled]' : 'Hermes ended the turn without reporting this tool result.' }],
136
+ toolInput: tool.input || undefined,
137
+ isError: !cancelled && stopReason !== 'end_turn',
138
+ missing: !cancelled,
139
+ durationMs: tool.startedAt ? Date.now() - tool.startedAt : undefined,
140
+ parentToolUseId: null,
141
+ })
141
142
  }
142
143
  this.tools.clear()
143
144
  const blocks = []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.256",
3
+ "version": "0.7.257",
4
4
  "description": "Share a local coding-agent CLI (Claude Code, Codex, Gemini, Aider, …) into a ThinkPool Code room, live.",
5
5
  "type": "module",
6
6
  "bin": {