Skip to content

fix(delegation): correct _adjust_thread_count worker args to match stdlib signature - #50077

Closed
indigokarasu wants to merge 1 commit into
NousResearch:mainfrom
indigokarasu:fix/delegation-executor-shutdown
Closed

fix(delegation): correct _adjust_thread_count worker args to match stdlib signature#50077
indigokarasu wants to merge 1 commit into
NousResearch:mainfrom
indigokarasu:fix/delegation-executor-shutdown

Conversation

@indigokarasu

Copy link
Copy Markdown
Contributor

Problem

_DaemonThreadPoolExecutor._adjust_thread_count passes (weakref, queue, initializer, initargs) to the stdlib _worker function, but the stdlib signature is (executor_ref, ctx, queue) where ctx is a worker context object from _create_worker_context().

initializer and initargs are not attributes of ThreadPoolExecutor — the stdlib never sets them. This causes AttributeError: '_DaemonThreadPoolExecutor' object has no attribute '_initializer' when _adjust_thread_count is called to spawn additional workers beyond the initial pool.

Trigger

The bug surfaces when background delegation dispatches more concurrent subagents than the initial worker pool size, triggering _adjust_thread_count to create new worker threads. The first N dispatches succeed; subsequent ones crash.

Fix

Replace the incorrect positional args with self._create_worker_context(), matching the pattern used by the stdlib's own _adjust_thread_count.

Testing

Verified that worker threads now spawn correctly beyond the initial pool size. Existing async delegation tests continue to pass.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have tool/delegate Subagent delegation labels Jun 21, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related: #47634 (open, fix/async-delegation-daemon-py314). Both correct _DaemonThreadPoolExecutor._adjust_thread_count worker args at the same site. Different mechanism: #47634 keeps the current-Python args and switches to _create_worker_context() only under a hasattr guard for Python 3.14 (plus registers _threads_queues), whereas this PR unconditionally replaces the args with self._create_worker_context(). Same goal, different approach -> related, not duplicate.

…dlib signature

The custom _DaemonThreadPoolExecutor._adjust_thread_count passed
(self._initializer, self._initargs) to _worker, but the stdlib
concurrent.futures.thread._worker signature is (executor_ref, ctx, queue)
where ctx is a worker context from _create_worker_context(). The
_initializer and _initargs attributes don't exist on ThreadPoolExecutor.

Replace with self._create_worker_context() to match the stdlib's own
_adjust_thread_count pattern.

This bug surfaces when dispatcher transactions exceed the initial
worker pool and _adjust_thread_count is called to spawn additional
workers — any background delegation after the first N concurrent
subagents would crash with AttributeError.
@indigokarasu
indigokarasu force-pushed the fix/delegation-executor-shutdown branch from 97ae562 to 4a2d4e9 Compare June 22, 2026 01:20
@indigokarasu

Copy link
Copy Markdown
Contributor Author

Force-pushed to fix commit authorship (was 'Fix Bot' from automated session, now correctly attributed to @indigokaraso). No code changes.

@indigokarasu

Copy link
Copy Markdown
Contributor Author

Closing as cannot-reproduce / implemented-on-main.

Verified against the repo's supported range (requires-python ">=3.11,<3.14"):

  • On both CPython 3.11.15 and 3.13.13, concurrent.futures.thread._worker has the 4-arg signature (executor_reference, work_queue, initializer, initargs), and ThreadPoolExecutor has NO _create_worker_context method.
  • Current main tools/daemon_pool.py already passes (weakref.ref(self, weakref_cb), self._work_queue, self._initializer, self._initargs), which matches the stdlib _worker exactly. I exercised the worker-spawn path directly and it succeeds on both 3.11 and 3.13 with no error.
  • The proposed change (self._create_worker_context()) raises AttributeError: 'DaemonThreadPoolExecutor' object has no attribute '_create_worker_context' on both versions — it would regress async delegation.
  • The PR's premise (that _initializer/_initargs aren't set on ThreadPoolExecutor) is incorrect; they are set in ThreadPoolExecutor.__init__, which is why the existing code works.

The merge conflict was a side effect of main refactoring the inline _DaemonThreadPoolExecutor out of tools/async_delegation.py into tools/daemon_pool.py, where the args are already correct. No code change is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have tool/delegate Subagent delegation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants