Skip to content

UN-3575 [FEAT] Lookup enrichment support for agentic-table prompts (OSS side)#2189

Open
pk-zipstack wants to merge 6 commits into
mainfrom
feat/agentic-table-lookup
Open

UN-3575 [FEAT] Lookup enrichment support for agentic-table prompts (OSS side)#2189
pk-zipstack wants to merge 6 commits into
mainfrom
feat/agentic-table-lookup

Conversation

@pk-zipstack

@pk-zipstack pk-zipstack commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What

  • Thread the per-prompt lookup_config into the agentic-table executor's agentic_params in structure_tool_task, so post-extraction lookup enrichment runs for agentic-table prompts on the deployment path.
  • Add a generic, length-preserving bounded-concurrency map at workers/shared/parallel_map.py, used by the agentic-table lookup per-row enrichment (and reusable by other LLM call sites).

Why

Ref UN-3575. The cloud repo enables lookups on agentic-table prompts; the enrichment runs inside the dedicated agentic_table executor. For that to fire on deployed pipelines (not just the IDE), the OSS structure_tool_task.py — which dispatches agentic-table prompts to the executor — must forward the lookup_config that is attached to the prompt output upstream at export.

The per-row enrichment mode needs bounded concurrency (N rows → N LLM calls, capped at K workers). parallel_map is generic OSS-side infrastructure (like the existing run_lookup_enrichment hook), so it lives in the OSS workers/shared and is imported from there by the cloud agentic executor at runtime.

How

  • workers/file_processing/structure_tool_task.py: after building the base agentic_params, forward at_output.get("lookup_config"). It is None when no lookup is assigned to the prompt, so the executor runs enrichment only when set.

    "lookup_config": at_output.get("lookup_config"),
  • workers/shared/parallel_map.py (new): parallel_map(items, worker, *, max_workers, on_error=None, label="") — a ThreadPoolExecutor map that returns results in input order and always the same length as the input (failed items hold the on_error fallback, never dropped), so callers realign results to inputs by index. max_workers=1 runs effectively sequentially, so one knob covers both sequential and bounded-parallel strategies. Retries/rate-limits are intentionally left to the SDK LLM client (which already backs off on 429/5xx and honours Retry-After), so concurrent callers self-throttle. No early-abort (documented).

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

No. Both changes are additive:

  • at_output.get("lookup_config") returns None for all current deployments (no lookup on agentic-table), so the executor's enrichment path is skipped and agentic_params is functionally unchanged.
  • workers/shared/parallel_map.py is a brand-new module with no existing importers in this repo; it introduces no behavioural change on its own.

Database Migrations

  • None (migrations for the per_row field live in the cloud repo).

Env Config

  • New optional env var LOOKUP_PER_ROW_MAX_WORKERS (default 8) is read by the cloud agentic-table worker for per-row concurrency; no OSS-side config change required.

Relevant Docs

Related Issues or PRs

  • Cloud companion PR: Zipstack/unstract-cloud#1662 — UN-3575 [FEAT] Lookup enrichment for agentic-table prompts (whole-output + per-row). Both must be merged/deployed together — the cloud agentic executor consumes the lookup_config param forwarded here and imports parallel_map from this repo's workers/shared.

Dependencies Versions

  • No new package dependencies.

Notes on Testing

  • Integration-tested via end-to-end pipeline runs (this function is not unit-tested).
  • Validated on a full local stack: a real agentic-table extraction with a per-row lookup logged parallel_map: N items across up to 8 workers and Per-row lookup enrichment complete: N/N rows enriched, 0 failed.
  • Backward-compat verified: agentic-table prompts without a lookup dispatch with lookup_config=None and behave exactly as before.

Screenshots

N/A — backend/worker-only change.

Checklist

I have read and understood the Contribution Guidelines.

pk-zipstack and others added 2 commits July 16, 2026 20:07
Pass the per-prompt lookup_config into the agentic_table executor's params
so post-extraction lookup enrichment runs for agentic-table prompts on the
deployment path. Sourced from the output dict (attached upstream at export);
None when no lookup is assigned, so it's a no-op otherwise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Length-preserving bounded-concurrency map used by per-row lookup enrichment
(and reusable by other LLM call sites). max_workers=1 == sequential.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 81acab15-f0f7-4f46-b6a6-44e7b68201db

📥 Commits

Reviewing files that changed from the base of the PR and between c463404 and f2bf640.

📒 Files selected for processing (1)
  • workers/executor/executors/lookup_enrichment.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • workers/executor/executors/lookup_enrichment.py

Summary by CodeRabbit

  • New Features
    • Agentic-table processing now forwards optional lookup configuration to control when enrichment runs.
    • Lookup enrichment can reuse preloaded reference text content to avoid repeated remote reads.
    • Added a bounded-concurrency, order-preserving parallel mapper for independent, I/O-heavy work.
  • Bug Fixes
    • Parallel mapping now continues after individual failures, preserves result order/length, and improves error reporting; supports optional per-item fallback handling.

Walkthrough

Adds a bounded-concurrency, order-preserving parallel_map utility with per-item error handling, and extends lookup enrichment to preload reference texts while forwarding lookup_config through agentic-table parameters.

Changes

Parallel processing and agentic lookup

Layer / File(s) Summary
Lookup enrichment configuration and reference forwarding
workers/executor/executors/lookup_enrichment.py, workers/file_processing/structure_tool_task.py
Adds optional reference-text preloading, forwards preloaded texts to the lookup plugin, and passes lookup_config into agentic-table executor parameters.
Bounded concurrent mapping
workers/shared/parallel_map.py
Adds typed, order-preserving thread-pool mapping with bounded workers, per-item fallbacks, capped traceback logging, and failure summaries.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely matches the main change: lookup enrichment support for agentic-table prompts on the OSS side.
Description check ✅ Passed The description covers all required template sections and includes the main implementation, impact, testing, and dependency details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agentic-table-lookup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds lookup enrichment support for agentic-table prompts. The main changes are:

  • Forward lookup_config into the agentic-table executor parameters.
  • Add optional preloading for lookup reference texts.
  • Add a shared length-preserving thread-pool map helper for bounded parallel work.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
workers/shared/parallel_map.py Adds a shared helper for ordered, length-preserving bounded parallel mapping.
workers/file_processing/structure_tool_task.py Passes prompt-level lookup configuration into agentic-table execution.
workers/executor/executors/lookup_enrichment.py Adds optional lookup reference preloading and forwards preloaded references to the enrichment plugin.

Reviews (5): Last reviewed commit: "UN-3575 [FIX] Guard preload_reference_te..." | Re-trigger Greptile

Comment thread workers/shared/parallel_map.py
…okup

# Conflicts:
#	workers/file_processing/structure_tool_task.py
with backoff and honors ``Retry-After``, so ``max_workers`` concurrent callers
self-throttle without any extra coordination in this utility.

NOTE: there is no early-abort. All submitted work runs to completion even if the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@muhammad-ali-e do you have any thoughts on this behaviour?

Comment thread workers/file_processing/structure_tool_task.py Outdated

@chandrasekharan-zipstack chandrasekharan-zipstack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — UN-3575 OSS side

Reviewed together with the cloud companion Zipstack/unstract-cloud#1662.

Both changes are appropriately small and the structure_tool_task.py forwarding is exactly right. parallel_map's core design — length-preserving, index-realigned, max_workers=1 collapsing to sequential so one knob covers both strategies — is the correct shape for the per-row use case, and the no-early-abort NOTE is a genuinely good comment.

Main items inline. The one that matters most:

parallel_map.py:12-15 — the docstring's justification for omitting rate limiting doesn't hold up against the SDK. 529 (Anthropic overloaded_error) isn't in RETRYABLE_STATUS_CODES, retries are config-gated rather than unconditional, and "concurrent callers self-throttle" doesn't follow from retry-with-backoff. Since that paragraph is the entire stated reason this utility ships without rate limiting, it's worth either correcting or just scoping the claim down.

Also worth a thought, though not blocking: parallel_map is a near-verbatim copy of the pre-existing workers/plugins/agentic_table/src/utils/parallel_map.py in the cloud repo (same ThreadPoolExecutor + as_completed + index-map structure), and today the only consumer is that same cloud plugin. Generalizing the plugin's own utility would avoid both the duplication and the new cross-repo import dependency. The OSS placement is defensible if other call sites are planned — just flagging the trade-off.

Tests

Not asking for full coverage, but parallel_map is pure, dependency-free and trivially testable, and it lands in a CI-gated path (unit-workers, coverage_source: shared). Four asserts would pin the whole contract: order preserved under reversed completion, length preserved on failure with on_error=None, on_error fallback lands at the failed index, and max_workers <= 1. The middle one is the single behaviour that differs from parallel_page_map (which ends with [r for r in results if r is not None]) and therefore the module's entire reason to exist. workers/plugins/agentic_table/tests/test_parallel_map.py in the cloud repo already covers all of these for the predecessor and ports almost directly.

Comments

Could you keep the new comments concise and generic? A few here narrate the PR's own context or reference symbols in the other repo, which won't read correctly to an OSS-only reader and will go stale as the code moves. Flagged inline.

Comment thread workers/shared/parallel_map.py Outdated
Comment thread workers/shared/parallel_map.py Outdated
Comment thread workers/shared/parallel_map.py
Comment thread workers/shared/parallel_map.py
Comment thread workers/shared/parallel_map.py
Comment thread workers/shared/parallel_map.py Outdated
Comment thread workers/shared/parallel_map.py Outdated
Comment thread workers/shared/parallel_map.py
Comment thread workers/file_processing/structure_tool_task.py
pk-zipstack and others added 2 commits July 21, 2026 20:02
parallel_map: return type is now list[R | None] (matches the None-on-omitted-
on_error contract); drop the needless log lock (loop body is single-threaded);
cap per-item tracebacks and add a failure summary so a systemic failure can't
flood logs; guard on_error so a raising fallback can't hang the pool. Docstring
corrected (drop cloud-only symbol reference; don't overstate SDK retry coverage).

structure_tool_task: collapse the lookup_config comment and name the source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d hoist)

Add preload_reference_texts() and a reference_texts passthrough on
run_lookup_enrichment so per-row enrichment can read the reference file(s) once
instead of once per row. None => each call loads its own (unchanged path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@workers/executor/executors/lookup_enrichment.py`:
- Around line 35-50: The preload_reference_texts function must return None when
the plugin preload operation fails instead of propagating exceptions. In
preload_reference_texts, verify the retrieved preload hook is callable before
invoking it, and catch preload/read failures to return None so
run_lookup_enrichment can fall back to per-call loading.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ee0c4dd5-9331-4b5f-8634-7697d83ccf47

📥 Commits

Reviewing files that changed from the base of the PR and between e2c922f and c463404.

📒 Files selected for processing (1)
  • workers/executor/executors/lookup_enrichment.py

Comment thread workers/executor/executors/lookup_enrichment.py Outdated
Honour the documented None-on-failure contract: wrap the plugin's preload call
in try/except (and use callable()) so a raising plugin hook falls back to
per-call reference loading instead of aborting enrichment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
e2e-api-deployment e2e 3 0 0 0 20.7
e2e-coowners e2e 1 0 0 0 1.6
e2e-etl e2e 1 0 0 0 8.4
e2e-login e2e 2 0 0 0 1.2
e2e-prompt-studio e2e 1 0 0 0 4.5
e2e-smoke e2e 2 0 0 0 1.3
e2e-workflow e2e 1 0 0 0 16.3
integration-backend integration 161 0 0 27 70.7
integration-connectors integration 1 0 0 7 8.0
integration-workers integration 0 0 0 141 140.1
unit-backend unit 277 0 0 1 23.0
unit-connectors unit 63 0 0 0 9.5
unit-core unit 27 0 0 0 1.3
unit-platform-service unit 15 0 0 0 2.5
unit-rig unit 86 0 0 0 4.3
unit-sdk1 unit 480 0 0 0 23.6
unit-workers unit 1312 0 0 0 118.0
TOTAL 2433 0 0 176 455.0

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants