Skip to content
Merged

Surface #1007

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
6 changes: 3 additions & 3 deletions bots/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ class SavedRunAdmin(GooeyModelAdmin):
"view_parent_published_run",
"run_time",
"price",
"is_api_call",
"surface",
"is_cancelled",
"created_at",
"updated_at",
Expand All @@ -459,7 +459,7 @@ class SavedRunAdmin(GooeyModelAdmin):
]
list_filter = [
"workflow",
"is_api_call",
"surface",
"is_cancelled",
"is_flagged",
("run_status", admin.EmptyFieldListFilter),
Expand All @@ -482,7 +482,7 @@ class SavedRunAdmin(GooeyModelAdmin):
"created_at",
"updated_at",
"run_time",
"is_api_call",
"surface",
"parent_builder_saved_run",
"view_bot_message",
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Generated by Django 5.1.3 on 2026-06-13 04:31

from django.db import migrations, models

from bots.models import SavedRun


def backfill_surface_from_is_api_call(apps, schema_editor):
SavedRunModel = apps.get_model("bots", "SavedRun")
db_alias = schema_editor.connection.alias
SavedRunModel.objects.using(db_alias).filter(is_api_call=True).update(
surface=SavedRun.Surface.api
)


class Migration(migrations.Migration):

dependencies = [
("bots", "0120_remove_savedrun_bots_savedr_workflo_47a100_idx_and_more"),
]

operations = [
migrations.AddField(
model_name="savedrun",
name="surface",
field=models.IntegerField(
choices=[
(0, "Run"),
(1, "API"),
(2, "Deployment"),
(3, "Builder Prompt"),
(4, "Builder Child"),
(5, "Tool Call"),
(6, "Internal"),
(7, "Analysis"),
(8, "Export"),
(9, "Bulk"),
],
default=0,
Comment thread
devxpy marked this conversation as resolved.
help_text="Where this run was created.<br><br>Run: A run created from the UI playground directly by the user.<br>API: Called by an API.<br>Deployment: Called by a bot integration.<br>Builder Prompt: A prompt submitted to the Gooey builder.<br>Builder Child: A child run created by the Gooey builder.<br>Tool Call: Any tool calls made by a workflow.<br>Internal: Any internal calls made by the app, e.g. QR code or icon generator.<br>Analysis: A run created from the bot integration analysis feature.<br>Export: A run created from the scheduled bot integration export feature.<br>Bulk: A run created from the bulk runner.",
),
),
migrations.RunPython(
backfill_surface_from_is_api_call,
migrations.RunPython.noop,
),
migrations.AlterField(
model_name="savedrun",
name="is_api_call",
field=models.BooleanField(
default=False, help_text="(Deprecated) Use surface instead."
),
),
]
2 changes: 2 additions & 0 deletions bots/models/published_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ def submit_api_call(
enable_rate_limits: bool = False,
deduct_credits: bool = True,
called_fn: CalledFunction | None = None,
**defaults,
) -> tuple[celery.result.AsyncResult, SavedRun]:
return self.saved_run.submit_api_call(
workspace=workspace,
Expand All @@ -324,6 +325,7 @@ def submit_api_call(
deduct_credits=deduct_credits,
parent_pr=self,
called_fn=called_fn,
**defaults,
)

@classmethod
Expand Down
32 changes: 31 additions & 1 deletion bots/models/saved_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,37 @@ class SavedRun(models.Model):
choices=RetentionPolicy.choices, default=RetentionPolicy.keep
)

is_api_call = models.BooleanField(default=False)
class Surface(IntegerChoices):
run = 0, "Run"
api = 1, "API"
deployment = 2, "Deployment"
builder_prompt = 3, "Builder Prompt"
builder_child = 4, "Builder Child"
tool_call = 5, "Tool Call"
internal = 6, "Internal"
analysis = 7, "Analysis"
export = 8, "Export"
bulk = 9, "Bulk"

surface = models.IntegerField(
choices=Surface.choices,
default=Surface.run,
help_text="Where this run was created.<br><br>"
f"{Surface.run.label}: A run created from the UI playground directly by the user.<br>"
f"{Surface.api.label}: Called by an API.<br>"
f"{Surface.deployment.label}: Called by a bot integration.<br>"
f"{Surface.builder_prompt.label}: A prompt submitted to the Gooey builder.<br>"
f"{Surface.builder_child.label}: A child run created by the Gooey builder.<br>"
f"{Surface.tool_call.label}: Any tool calls made by a workflow.<br>"
f"{Surface.internal.label}: Any internal calls made by the app, e.g. QR code or icon generator.<br>"
f"{Surface.analysis.label}: A run created from the bot integration analysis feature.<br>"
f"{Surface.export.label}: A run created from the scheduled bot integration export feature.<br>"
f"{Surface.bulk.label}: A run created from the bulk runner.",
)
is_api_call = models.BooleanField(
default=False,
help_text="(Deprecated) Use surface instead.",
)

# see signals.py:revoke_saved_run_task_on_cancel
is_cancelled = models.BooleanField(default=False)
Expand Down
2 changes: 2 additions & 0 deletions bots/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
Conversation,
Message,
Platform,
SavedRun,
)
from daras_ai_v2.bots import save_msg_pair_to_db
from daras_ai_v2.facebook_bots import WhatsappBot
Expand Down Expand Up @@ -95,6 +96,7 @@ def msg_analysis(self, msg_id: int, anal_id: int, countdown: int | None):
current_user=msg.conversation.bot_integration.created_by,
request_body=dict(variables=variables),
parent_pr=anal.published_run,
surface=SavedRun.Surface.analysis,
)

# save the run before the result is ready
Expand Down
2 changes: 1 addition & 1 deletion celeryapp/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def is_task_cancelled(e: BaseException | None) -> bool:
def post_runner_tasks(saved_run_id: int):
sr = SavedRun.objects.get(id=saved_run_id)

if not sr.is_api_call:
if sr.surface == SavedRun.Surface.run:
send_email_on_completion(sr)

if should_attempt_auto_recharge(sr.workspace):
Expand Down
10 changes: 5 additions & 5 deletions daras_ai_v2/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2350,17 +2350,15 @@ def _saved_tab(self):
paginate_button(url=self.request.url, cursor=cursor)

def _history_tab(self):
from daras_ai_v2.gooey_builder import get_default_builder_pr

self.ensure_authentication(anon_ok=True)

# Filter by workspace
qs = SavedRun.objects.filter(
workflow=self.workflow, workspace=self.current_workspace
)

if settings.GOOEY_BUILDER_INTEGRATION_ID and not self.is_current_user_admin():
qs = qs.exclude(parent_version__published_run=get_default_builder_pr())
if not self.is_current_user_admin():
qs = qs.exclude(surface=SavedRun.Surface.builder_prompt)

# Apply user filter if specified
for_param = self.request.query_params.get("for", "me")
Expand All @@ -2369,7 +2367,9 @@ def _history_tab(self):
and self.request.user
and not self.current_workspace.is_personal
):
qs = qs.filter(uid=self.request.user.uid, is_api_call=False)
qs = qs.filter(uid=self.request.user.uid).exclude(
surface=SavedRun.Surface.deployment
)

run_history, cursor = paginate_queryset(
qs=qs, ordering=["-updated_at"], cursor=self.request.query_params
Expand Down
2 changes: 2 additions & 0 deletions daras_ai_v2/bot_integration_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
BotIntegration,
BotIntegrationAnalysisRun,
Platform,
SavedRun,
)
from daras_ai_v2 import icons, settings
from daras_ai_v2.api_examples_widget import bot_api_example_generator
Expand Down Expand Up @@ -576,6 +577,7 @@ def integration_details_generator(bi: BotIntegration, user: AppUser | None):
workspace=bi.workspace,
current_user=user,
request_body=dict(variables=variables),
surface=SavedRun.Surface.internal,
)
sr.wait_for_celery_result(result)
# if failed, show error and abort
Expand Down
1 change: 1 addition & 0 deletions daras_ai_v2/bots.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ def _process_and_send_msg(
workspace=workspace,
current_user=current_user,
request_body=body,
surface=SavedRun.Surface.deployment,
)
bot.on_run_created(sr)

Expand Down
6 changes: 1 addition & 5 deletions daras_ai_v2/breadcrumbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ def get_title_breadcrumbs(
is_root = pr and pr.saved_run == sr and pr.is_root()
is_example = not is_root and pr and pr.saved_run == sr
is_run = not is_root and not is_example
is_api_call = sr.is_api_call and tab == RecipeTabs.run

metadata = page_cls.workflow.get_or_create_metadata()
root_title = TitleUrl(
f"{metadata.emoji} {metadata.short_title}", page_cls.app_url()
Expand Down Expand Up @@ -97,10 +95,8 @@ def get_title_breadcrumbs(
case _ if is_run:
if tab and tab.label:
prefix = "Deployments" if tab == RecipeTabs.integrations else tab.label
elif is_api_call:
prefix = "API Run"
else:
prefix = "Run"
prefix = sr.get_surface_display()

prompt_title = page_cls.get_prompt_title(sr)
if pr and not pr.is_root():
Expand Down
41 changes: 3 additions & 38 deletions daras_ai_v2/gooey_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from bots.models import (
BotIntegration,
SavedRun,
db_msgs_to_api_json,
PublishedRun,
)
from daras_ai_v2 import settings
Expand Down Expand Up @@ -162,42 +161,6 @@ def can_launch_gooey_builder(
# return current_workspace and current_workspace.enable_bot_builder


def get_conversation_data_for_saved_run(
bot_builder_integration: BotIntegration, sr: SavedRun
) -> dict | None:
"""
Returns conversation_data for the builder conversation associated with the given
SavedRun (messages up to gooey_builder_last_message_id), or None if not found.
"""
if not sr.parent_builder_saved_run:
return None

from bots.models.convo_msg import Message
from routers.bots_api import api_hashids

try:
last_message = Message.objects.get(saved_run=sr.parent_builder_saved_run)
except Message.DoesNotExist:
return None

conversation = last_message.conversation
msgs_qs = conversation.messages.filter(created_at__lte=last_message.created_at)
messages = list(
db_msgs_to_api_json(msgs_qs.last_n_msgs(reset_at=conversation.reset_at))
)
data = dict(
bot_id=api_hashids.encode(bot_builder_integration.id),
user_id=conversation.web_user_id,
timestamp=conversation.created_at.isoformat(),
messages=messages,
)
# only send the conversation id for a full conversation,
# for partial messages start a new conversation
if last_message == conversation.messages.latest():
data["id"] = api_hashids.encode(conversation.id)
return data


router = CustomAPIRouter()


Expand All @@ -223,6 +186,7 @@ def gooey_builder_send_message(request: fastapi.Request, body: GooeyBuilderSendM
parent_pr=workflow_pr,
uid=request.user.uid,
workspace_id=workspace.id,
surface=SavedRun.Surface.builder_child,
)
workflow_sr.state.update(body.workflow_state)
workflow_sr.save()
Expand All @@ -239,6 +203,7 @@ def gooey_builder_send_message(request: fastapi.Request, body: GooeyBuilderSendM
current_user=request.user,
workspace=workspace,
request_body=request_body,
surface=SavedRun.Surface.builder_prompt,
)[1]
workflow_sr.save(update_fields=["parent_builder_saved_run"])

Expand Down Expand Up @@ -272,7 +237,7 @@ def fetch_builder_conversations(
workflow=Workflow.VIDEO_BOTS,
workspace=get_current_workspace(request.user, request.session),
uid=request.user.uid,
parent_builder_saved_run__isnull=False,
surface=SavedRun.Surface.builder_child,
)
.annotate(title=F("parent_builder_saved_run__state__input_prompt"))
.order_by("-updated_at")[: body.limit]
Expand Down
2 changes: 2 additions & 0 deletions daras_ai_v2/safety_checker.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from contextlib import contextmanager

from app_users.models import AppUser
from bots.models import SavedRun
from daras_ai_v2 import settings
from daras_ai_v2.azure_image_moderation import is_image_nsfw
from daras_ai_v2.exceptions import UserError
Expand Down Expand Up @@ -35,6 +36,7 @@ def safety_checker_text(text_input: str):
current_user=billing_account,
request_body=dict(variables=dict(input=text_input)),
deduct_credits=False,
surface=SavedRun.Surface.internal,
)
)

Expand Down
2 changes: 2 additions & 0 deletions functions/gooey_builder_workflow_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def call(
parent_pr=pr,
uid=self.builder_sr.uid,
workspace_id=self.builder_sr.workspace_id,
surface=SavedRun.Surface.builder_child,
)

# update the state
Expand Down Expand Up @@ -221,6 +222,7 @@ def call(self, run_url: str | None = None, background: bool = False) -> typing.A
enable_rate_limits=True,
parent_builder_saved_run=self.builder_sr,
parent_pr=pr,
surface=SavedRun.Surface.builder_child,
)
else:
page = page_cls(user=user)
Expand Down
3 changes: 2 additions & 1 deletion functions/workflow_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.utils.text import slugify

from app_users.models import AppUser
from bots.models import SavedRun
from daras_ai_v2.exceptions import UserError
from functions.models import CalledFunction, FunctionTrigger
from functions.base_llm_tool import (
Expand All @@ -17,7 +18,6 @@


if typing.TYPE_CHECKING:
from bots.models import SavedRun
from daras_ai_v2.base import BasePage
from workspaces.models import Workspace

Expand Down Expand Up @@ -120,6 +120,7 @@ def call(self, **kwargs):
request_body=request_body,
deduct_credits=False,
called_fn=called_fn,
surface=SavedRun.Surface.tool_call,
)
self.fn_sr = fn_sr

Expand Down
1 change: 1 addition & 0 deletions livekit_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ def create_run(bot: LivekitVoice):
current_user=bot.bi.created_by,
workspace=bot.bi.workspace,
request_body=body,
surface=SavedRun.Surface.deployment,
)

sr.transaction, sr.price = page.deduct_credits(sr.state)
Expand Down
2 changes: 2 additions & 0 deletions recipes/BulkRunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ def run_v2(
current_user=self.request.user,
request_body=request_body,
parent_pr=pr,
surface=SavedRun.Surface.bulk,
)
sr.wait_for_celery_result(result)

Expand Down Expand Up @@ -390,6 +391,7 @@ def run_v2(
current_user=self.request.user,
request_body=request_body,
parent_pr=pr,
surface=SavedRun.Surface.bulk,
)
sr.wait_for_celery_result(result)
response.eval_runs.append(sr.get_app_url())
Expand Down
Loading
Loading