Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ci/markdown-link-check-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
{
"pattern": "^https?://tavily\\.com/?$"
},
{
"pattern": "^https://exa\\.ai/?$"
},
{
"pattern": "^https?://modal\\.com/docs/reference/modal\\.config$"
},
Expand Down
4 changes: 4 additions & 0 deletions configs/config_domain_routing_and_skills.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ functions:
- pillow
- tabulate # required by pandas.DataFrame.to_markdown(), used by data-table-analysis skill
network: blocked
artifact_capture:
enabled: true
max_file_bytes: 50000000
allow_extensions: [.png, .jpg, .jpeg, .webp, .csv, .json, .md, .ipynb, .pdf]

# =========================================================================
# Agents
Expand Down
21 changes: 17 additions & 4 deletions docs/source/examples/skills-sandbox/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The example config enables:
- a fresh per-job Modal sandbox for Python execution
- Python packages useful for analysis, including `pandas`, `numpy`, `matplotlib`, and `pillow`
- virtual `/shared/` files for text artifacts that the orchestrator and subagents can read during the report workflow
- durable capture of supported charts and data files for async API jobs

The current built-in example skill is `data-table-analysis`. It is intended for quantitative research tasks where the agent must normalize researched facts and compute tabular outputs such as growth rates, rankings, summary statistics, CSV, JSON, or markdown tables.

Expand Down Expand Up @@ -79,6 +80,10 @@ functions:
- pandas
- pillow
network: blocked
artifact_capture:
enabled: true
max_file_bytes: 50000000
allow_extensions: [.png, .jpg, .jpeg, .webp, .csv, .json, .md, .ipynb, .pdf]

deep_research_agent:
_type: deep_research_agent
Expand All @@ -89,6 +94,13 @@ functions:

AI-Q validates the public skill collection names (`research`, `synthesis`) and resolves them to DeepAgents source paths internally. When skills are configured, AI-Q mounts the configured built-in skill collections into the DeepAgents virtual filesystem. When the sandbox ref is present, DeepAgents `execute` calls run in the configured provider. Modal creates a fresh sandbox named for the job.

In the reference async API flow, artifact capture uses the job database configured by
`general.front_end.db_url` (`NAT_JOB_STORE_DB_URL`) for metadata. Without that job-scoped database URL, as in a direct
`nat run`, Modal execution still works but durable capture remains inactive. Artifact bytes use SQL BLOB storage in the
job database by default. For production, use S3-compatible object storage by setting `AIQ_ARTIFACT_BLOB_PROVIDER=s3`,
`AIQ_ARTIFACT_S3_BUCKET`, and the standard AWS credentials; set `AIQ_ARTIFACT_S3_ENDPOINT_URL` for MinIO or another
compatible service. See [Production Artifact Storage](../../deployment/production.md#artifact-storage) for all options.

To evaluate OpenShell instead, use `configs/config_openshell.yml` after running `scripts/setup_openshell.sh`. That profile
is experimental: it attaches every job to one named, pre-provisioned sandbox. Per-job working directories avoid ordinary
filename collisions but are not an access-control or multi-tenant isolation boundary. Do not run mutually untrusted jobs
Expand Down Expand Up @@ -204,7 +216,8 @@ No config change is required for additional built-in skills inside an enabled co
- Text artifacts that need to survive for the report should be written through DeepAgents filesystem tools to `/shared/...`.
- `/shared/` is a virtual DeepAgents filesystem path. Use `ls`, `read_file`, `write_file`, and `edit_file` for `/shared/`; do not inspect `/shared/` with shell commands through `execute`.
- The sandbox is configured with `network: blocked`, so research should happen through AI-Q search tools, not from sandbox code.
- Durable sandbox artifact capture is opt-in (`artifact_capture.enabled: true`) and also requires an artifact store.
Successful `execute` calls checkpoint manifest-declared files, and success/failure terminal paths perform one final
best-effort scan. A busy cancellation skips that scan and preserves earlier checkpoints. Adding a sandbox alone does
not guarantee that every generated file is persisted or embedded in the report.
- The reference profile enables durable sandbox artifact capture, which requires the async API's job-scoped artifact
store. Successful `execute` calls checkpoint manifest-declared files, and success/failure terminal paths perform one
final best-effort scan. A busy cancellation skips that scan and preserves earlier checkpoints. Direct `nat run` does
not provide that store, and adding a sandbox alone does not guarantee that every generated file is persisted or
embedded in the report.
24 changes: 24 additions & 0 deletions tests/aiq_agent/agents/deep_researcher/test_deepagents_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,30 @@ def load(path: str) -> dict[str, Any]:
assert openshell["workflow"] == standard["workflow"]


def test_modal_reference_profile_enables_bounded_artifact_capture() -> None:
"""Keep the shipped Modal profile's capture policy validated."""
config = yaml.safe_load(Path("configs/config_domain_routing_and_skills.yml").read_text(encoding="utf-8"))
sandbox_data = config["functions"]["deep_research_sandbox"].copy()

assert sandbox_data.pop("_type") == "deep_research_sandbox"
sandbox = DeepResearchSandboxConfig.model_validate(sandbox_data)

assert sandbox.provider == "modal"
assert sandbox.artifact_capture.enabled is True
assert sandbox.artifact_capture.max_file_bytes == 50_000_000
assert sandbox.artifact_capture.allow_extensions == (
".png",
".jpg",
".jpeg",
".webp",
".csv",
".json",
".md",
".ipynb",
".pdf",
)


class TestSkillCollections:
"""Public skill config uses collection names, not DeepAgents virtual paths."""

Expand Down
Loading