Skip to content

Feat/deep agent - #62

Draft
Hercilio1 wants to merge 5 commits into
mainfrom
feat/deep-agent
Draft

Feat/deep agent#62
Hercilio1 wants to merge 5 commits into
mainfrom
feat/deep-agent

Conversation

@Hercilio1

Copy link
Copy Markdown
Collaborator

No description provided.

ho-tsl added 5 commits August 12, 2026 16:17
A product-agnostic runtime for autonomous agents built on deepagents, in a new
top-level baseapp_ai_langkit/deep_agents package. Nothing else in langkit imports
it and it declares no models, so a project that does not install the extra is
unaffected. It sits outside base/ deliberately: base/ is imported by every
consumer and must stay installable without deepagents.

- builder.build_deep_agent: the single construction point. The limit governors
  are built here and cannot be removed by a caller. Structured output is
  optional, for a surface whose result is written by its tools rather than
  returned as one validated object.
- node.LangGraphDeepAgent: an LLMNodeInterface implementation, so a deep agent's
  behavioural prompt is admin-editable through the runner tables like any other
  node. It carries no tracing backend; run telemetry goes to an on_run_complete
  hook instead of being written to a run tree the runtime knows how to find.
- limits: soft and hard per-run caps on model calls, cumulative tokens and wall
  clock, plus the structured-output and planning-loop governors. The soft tier
  takes a finalize_tools set, so a surface with no answer tool can still be
  forced to finish: emptying the tool list only works when langchain re-appends
  an answer tool outside it.
- skills: conditional composition of SKILL.md playbooks from components, behind
  a SkillSource protocol. FilesystemSkillSource reads a directory on disk and
  re-reads it per run, so an edit lands without a restart.
- telemetry: which skills a run loaded, and prompt-cache accounting.
- testing.ScriptedChatModel: replays a fixed script so a whole graph run is
  deterministic, and records what it was bound with on each call.

103 tests, all DB-free.
Two independent bugs, either one enough to 500 the prompt editor. Both hit
every runner, so no runner's prompts were editable through the admin at all.

- LLMRunnerNodeUsagePromptInline.get_fields read `obj.usage_prompt`, but Django
  builds an inline's fieldsets once per formset rather than once per row, so
  `obj` is the change view's object: the root LLMRunner, not this inline's
  parent node. The attribute does not exist there and the `DoesNotExist` the
  code caught could never fire. It now asks whether a usage-prompt row exists
  under the object being edited, handling LLMRunner and LLMRunnerNode both, so
  a nested_admin that starts passing the immediate parent keeps working.

- LLMRunnerAdmin mixed unfold's ModelAdmin with nested_admin's. The two do not
  compose: rendering any nested inline raises `AttributeError:
  'InlineAdminFormSet' object has no attribute 'initial_forms'` out of
  django.contrib.admin.helpers, because unfold hands the nested formset where
  Django expects a plain one. Verified against unfold and django-nested-admin
  4.1.6 on Django 5.2 by removing unfold and nothing else: every runner change
  page went from 500 to 200. unfold.contrib.inlines does not help, being about
  nonrelated inlines. The page now renders with stock admin widgets inside
  unfold's site chrome, which is the trade: a prompt editor that works, styled
  less well.

The regression test lives in the consuming project (red-backend,
apps/parser/tests/test_langkit_runner_admin.py), because this repo's own test
settings need a database service and an app that is not installed here.
`build_deep_agent` has always accepted `extra_middleware` and appended it after the
governors, but the node never passed anything, so a subclass had no way to add its own.

That only matters for a surface with no `response_format`, whose result is written by
its tools rather than returned as one validated object: middleware is then the only
place a run can be inspected before it ends, since there is no answer to intercept.
Redstone's parser is the first such consumer, and it uses this to send a run that is
about to finish with work outstanding back to the model once.

Additive, defaulting to no middleware, so every existing surface builds the same agent.
@Hercilio1
Hercilio1 requested a review from lucas-caribe August 17, 2026 20:46
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