spike: Nexus Service support (workflow-backed Operations) - #9
Draft
tyler5673 wants to merge 3 commits into
Draft
Conversation
tyler5673
force-pushed
the
feat/nexus-service
branch
5 times, most recently
from
August 21, 2026 20:54
6dd3504 to
503ba91
Compare
Rebased onto main with PR #15 (SDK 3.1.2 + attribution header) and PR #16 (extraction parameter) merged. Squashes the nexus spike into one clean commit. - YouDotComService exposes all six Activities as async Nexus Operations - contract.py holds the Nexus contract with SDK response models - workflows.py ships six thin backing Workflows with per-Activity ceilings - Idempotency key support for deduplication of Nexus StartOperation retries - Unit tests covering contract, handler, and sandbox registration - Integration tests for live Nexus round-trip (gated behind -m integration) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…orrect timeout_s comment - contract.py, nexus.py: SDK 3.1.2 shipped lazy imports (PEP 562), so the imports_passed_through() wrapper is belt-and-braces rather than load-bearing. Updated comments that referenced DX-776 as future work. - workflows.py: comment claimed the Activity forwards timeout_s untouched but activities.py substitutes 120s when timeout_s is None, preventing the SDK effort-based deadline derivation. Corrected to describe actual behavior. - plugin.py: re-added annotated_types to _PASSTHROUGH_MODULES, eliminating 13 UserWarning messages about late import under the workflow sandbox. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
tyler5673
force-pushed
the
feat/nexus-service
branch
from
August 21, 2026 21:55
365739c to
a6d2dec
Compare
The Activity now forwards timeout_s as-is (PR #17 merged), so the SDK derives the effort-based deadline itself. Updated the comment that described the old 120s substitution behavior. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Linear: DX-745
A design spike and reference implementation for Temporal Nexus support, exposing the six You.com Activities as cross-Namespace Operations on top of the existing Activity layer.
This is a spike, not a merge candidate. It works and it is tested, but it freezes a public cross-Namespace contract that no caller has yet exercised across a real Namespace boundary, and one open question below will change that contract. Opening it for a routing decision: does Nexus belong in the partner submission, or in a follow-up v2? See Open questions.
Activity-only users are unaffected either way —
youdotcom_temporal.nexusis a separate import.Why every Operation is async (workflow-backed)
Nexus synchronous Operations must finish within the 10-second handler deadline. Several You.com calls routinely exceed it:
searchwith full-page extraction (crawl_timeoutup to 60s)contentswith multiple URLs and a high per-URLcrawl_timeoutresearchandfinance_research(minutes)research_background(up to 4 hours forfrontiereffort)Temporal's guidance is explicit — use a sync Operation "only when its complete execution path is highly reliable, has predictably low latency, and finishes well within the 10-second handler deadline." A sync handler that blows the deadline is killed as a retryable error, and the circuit breaker "trips after 5 consecutive retryable errors, blocking all Operations from the caller to that Endpoint." That failure is shared-fate across the Endpoint, so every Operation here is asynchronous and backed by a thin Workflow.
The tradeoff worth naming: this makes a fast
searchcost a full Workflow Execution rather than a couple of Actions. We are buying blast-radius safety with per-call cost.What's here
src/youdotcom_temporal/nexus.pyYouDotComServicecontract (6 Operations) +YouDotComServiceHandler+you_nexus_service_handler()src/youdotcom_temporal/workflows.pyyou_nexus_workflows(), each with a per-Activitystart_to_close_timeoutsrc/youdotcom_temporal/__init__.pytests/test_nexus.py,tests/_caller_workflow.pyexamples/run_nexus_worker.pyREADME.md,CHANGELOG.mdBug fix worth landing regardless of the routing decision
youdotcom_temporal/__init__.pyimported the Activity layer eagerly, which imports the You.com SDK andurllib.request. Python imports a parent package before a submodule body runs, so a submodule's ownworkflow.unsafe.imports_passed_through()block never got the chance to cover it. Verified againstSandboxedWorkflowRunner.prepare_workflow— the pathWorker.__init__takes for every registered Workflow:YouPluginwas also passed, because the plugin's passthrough list was silently doing the block's job.The public names now resolve through a module
__getattr__, so the SDK loads on first attribute access — after any passthrough block has been entered. Public imports are unchanged. This is a latent sharp edge in the Activity layer that the Nexus work exposed; it is not specific to Nexus.Other fixes found while reviewing this
research_background's 4-hour ceiling was unreachable. The Activity hardcodestimeout_s=120.0when unset, overriding the SDK's effort-based default (600s, 14400s forfrontier). A defaultfrontiercall failed after two minutes and, under the original retry policy, submitted three billable research tasks. The Workflow now fillstimeout_sfromresearch_effort.research_and_wait_asyncissues a final GET after its internal wait expires, so an exact match let Temporal kill the attempt before the Activity could report anything. The ceiling is now derived from the waits plus a margin.search/answer/contents.Open questions
Known limits
nexusrpcis imported but not declared. It arrives transitively viatemporalio, which pinsnexus-rpc==1.4.0. Declare it under the distribution namenexus-rpcbefore release —nexusrpcis the import name and not a valid requirement. A range like>=1.4,<2would conflict when temporalio bumps its pin.Verification
uv run ruff check— cleanuv run mypy src— clean (strict)uv run pytest— 87 passed, 1 skipped (replay-safety, needs thetemporalCLI), 8 deselected (integration)Out of scope
YouPlugin, or error mapping.pyproject.tomldependency changes (deliberately deferred, see limits).