From 1862adb7e38fac9cd5df3285665f8c301be97764 Mon Sep 17 00:00:00 2001 From: Diwank Singh Tomer Date: Tue, 20 May 2025 20:22:37 +0530 Subject: [PATCH] feat: add julep file url resolver --- CHANGELOG.md | 4 ++++ agents-api/agents_api/clients/async_s3.py | 11 +++++++++++ agents-api/agents_api/clients/sync_s3.py | 11 +++++++++++ agents-api/agents_api/common/utils/evaluator.py | 12 ++++++++++++ documentation/concepts/files.mdx | 16 +++++++++++++++- 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c50cb3d81..b39ecd09b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,10 @@ +# **Julep AI Changelog for 12 May 2025** ✨ + +- **Minor Feature**: Added `julep://` file URL resolution in workflows ✨ + # **Julep AI Changelog for 9 May 2025** ✨ - **Minor Docs**: Added links to cookbooks for Quick, Community, and Industry pages. diff --git a/agents-api/agents_api/clients/async_s3.py b/agents-api/agents_api/clients/async_s3.py index 2d3f027d6..cc0461351 100644 --- a/agents-api/agents_api/clients/async_s3.py +++ b/agents-api/agents_api/clients/async_s3.py @@ -85,3 +85,14 @@ async def add_object_with_hash(body: bytes, replace: bool = False) -> str: await add_object(key, body, replace=replace) return key + + +@beartype +async def generate_presigned_url(key: str, expires: int = 3600) -> str: + """Generate a temporary signed URL for a stored object.""" + client = await setup() + return await client.generate_presigned_url( + "get_object", + Params={"Bucket": blob_store_bucket, "Key": key}, + ExpiresIn=expires, + ) diff --git a/agents-api/agents_api/clients/sync_s3.py b/agents-api/agents_api/clients/sync_s3.py index d90ad8061..b86335d76 100644 --- a/agents-api/agents_api/clients/sync_s3.py +++ b/agents-api/agents_api/clients/sync_s3.py @@ -93,3 +93,14 @@ def add_object_with_hash(body: bytes, replace: bool = False) -> str: add_object(key, body, replace=replace) return key + + +@beartype +def generate_presigned_url(key: str, expires: int = 3600) -> str: + """Generate a temporary signed URL for a stored object.""" + client = setup() + return client.generate_presigned_url( + "get_object", + Params={"Bucket": blob_store_bucket, "Key": key}, + ExpiresIn=expires, + ) diff --git a/agents-api/agents_api/common/utils/evaluator.py b/agents-api/agents_api/common/utils/evaluator.py index 35d4079ef..f8ff9259e 100644 --- a/agents-api/agents_api/common/utils/evaluator.py +++ b/agents-api/agents_api/common/utils/evaluator.py @@ -315,6 +315,17 @@ def html_to_markdown(html_text: str) -> str: return markdownify.markdownify(html_text) +# AIDEV-NOTE: Exposes Julep file URLs during expression evaluation +def resolve_url(url: str, expires: int = 3600) -> str: + """Return a signed URL if the input uses the julep scheme.""" + if url.startswith("julep://"): + file_id = url.split("julep://", 1)[1] + from ...clients import sync_s3 + + return sync_s3.generate_presigned_url(file_id, expires) + return url + + # Restricted set of allowed functions ALLOWED_FUNCTIONS = { # Basic Python builtins @@ -354,6 +365,7 @@ def html_to_markdown(html_text: str) -> str: "humanize_text_alpha": humanize_text, "markdown_to_html": markdown_to_html, "html_to_markdown": html_to_markdown, + "resolve_url": resolve_url, } diff --git a/documentation/concepts/files.mdx b/documentation/concepts/files.mdx index effa97468..81469dca6 100644 --- a/documentation/concepts/files.mdx +++ b/documentation/concepts/files.mdx @@ -218,8 +218,22 @@ const execution = await client.tasks.executions.create({ +## Accessing Files in Workflows + +Files can be referenced inside task steps using the `julep://` scheme. When an +expression contains a URL like `julep://`, Julep automatically resolves +it to a temporary signed URL that is valid for one hour by default. + +```yaml +main: + - evaluate: + url: julep://{file_id} +``` + +This allows workflows to access file contents without exposing permanent links. + ## Next Steps - [Projects](/concepts/projects) - Learn about organizing resources with projects - [Agents](/concepts/agents) - Learn how agents can work with files -- [Tasks](/concepts/tasks) - Learn how to use files in task workflows \ No newline at end of file +- [Tasks](/concepts/tasks) - Learn how to use files in task workflows