Skip to content

[GSoC 2026] Add analyzer/playbook LLM tools to the chatbot agent (refs #3732)#3740

Open
berardifra wants to merge 2 commits into
gsoc-2026/llm-chatbotfrom
gsoc-2026/llm-chatbot-w5-analyzer-tools
Open

[GSoC 2026] Add analyzer/playbook LLM tools to the chatbot agent (refs #3732)#3740
berardifra wants to merge 2 commits into
gsoc-2026/llm-chatbotfrom
gsoc-2026/llm-chatbot-w5-analyzer-tools

Conversation

@berardifra
Copy link
Copy Markdown
Contributor

Refs #3732. (Targets the gsoc-2026/llm-chatbot umbrella, not develop. Using Refs (not Closes) on purpose — the umbrella isn't develop, so the issue is closed manually after merge.)

Description

Adds two read-only tools to the chatbot LangChain ReAct agent (W5 — analyzer/playbook domain):

  • list_analyzers(observable_type="", limit=50) — lists the analyzers enabled for the requesting user
    (globally not disabled, and not disabled for the user's organization), optionally filtered to those
    supporting a given observable type. observable_type is validated against the Classification enum; an
    unknown value is reported in errors instead of silently returning an empty list.
  • recommend_playbook(observable_name="", classification="", limit=50) — suggests directly-launchable
    (starting=True, non-disabled) playbooks applicable to an observable's classification, scoped to the
    playbooks visible to the user (visible_for_user — owned + organization-shared). The classification is
    derived from the observable via Classification.calculate_observable when not supplied; an explicitly
    provided one is validated against the enum.

Both follow the existing tool pattern (a make_*_tool(user) factory that closes over the user, so
multi-tenancy is enforced at build time and the LLM can't widen the scope) and return the standard
{"errors": [...], "<payload>": ...} envelope via ToolResultSerializer.to_json(). Output uses
purpose-built light serializers (AnalyzerConfigToolSerializer, PlaybookConfigToolSerializer) rather than
the heavy config serializers, to keep the LLM prompt small. Both cap their result list at 50
(_MAX_RESULTS) and clamp the LLM-supplied limit into [1, 50], so a single call can't flood the prompt.

These tools are read-only — no analysis is triggered. The analysis-launching tool analyze_observable
(with its safety guardrails) follows in a separate PR.

Type of change

  • New feature (non-breaking change which adds functionality).

Checklist

  • I have read and understood the rules about how to Contribute to this project
  • The pull request is for the branch develop (targets the gsoc-2026/llm-chatbot umbrella)
  • I have inserted the copyright banner at the start of the file
  • Please avoid adding new libraries as requirements whenever it is possible (no new dependencies added)
  • If external libraries/packages with restrictive licenses were added, they were added in the Legal Notice section (N/A — no new libraries added)
  • Linters (Ruff) gave 0 errors
  • I have added tests for the feature I solved (see tests folder); all tests (new and old) gave 0 errors (run locally against a rebuilt test image — the "Build & Tests" CI workflow does not run on umbrella-targeting PRs)
  • After submitting the PR, if DeepSource, Django Doctors or other third-party linters triggered alerts during CI, I have solved those alerts
  • I have addressed raised Copilot issues
  • I have reviewed and verified any LLM-generated code included in this PR. I used an LLM coding assistant while developing this PR, and reviewed all of its output.

@mlodic
Copy link
Copy Markdown
Member

mlodic commented Jun 5, 2026

I think the issues in the conflicts are due to the 2 parallels PRs that change the same code.

I merged the previous one without any change so it should be easy to fix the conflict.

@mlodic
Copy link
Copy Markdown
Member

mlodic commented Jun 5, 2026

This can happen from time to time considering that I can't review the changes as soon as they are published and some parallel PRs are normal in such environments.

Try to consider this while doing the changes to avoid having to fix conflicts every time. Isolate the content as soon as possible, abuse creation of additional files (like serializers.py and test_tools.py could become folders and contain isolated tests in separated files). This should reduce the issues

…#3732)

Add two read-only tools to the chatbot ReAct agent:
  - list_analyzers: lists the enabled observable analyzers, each annotated with a per-user
    'runnable' readiness flag (no hard runnable filter, so key-based analyzers stay visible).
  - recommend_playbook: suggests launchable (starting=True, enabled) playbooks matching an
    observable's classification, scoped with visible_for_user.

  Both follow the make_*_tool(user) factory pattern and return the standard {errors, payload}
  envelope via purpose-built light serializers. Tests cover filtering, enum validation, the
  result cap, and org/visibility isolation.
@berardifra berardifra force-pushed the gsoc-2026/llm-chatbot-w5-analyzer-tools branch from 8eff4cc to b2a7dbc Compare June 5, 2026 14:55

# Observable analyzers never apply to the `file` classification (that's the file-analysis path),
# so the accepted/advertised observable types are all classifications except FILE.
_VALID_OBSERVABLE_TYPES = [c for c in Classification.values if c != Classification.FILE.value]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this information is an IntelOwl core info and should stay logically in the core part.
Please modify the Classification class and add an helper that generates this list and then import it here so it can be reused.

For instance, I noticed that in other parts of the code (see aggregate_observable_classification) we use the same list so it should be nice if you could modify that too while we are here.

# near-empty lists and flaky tests. We list the enabled analyzers and surface readiness as a
# per-row flag instead, so the LLM can still say "this analyzer applies but isn't configured
# for you". `runnable` is False when the analyzer is disabled for the user's organization OR
# not fully configured/healthy.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks for the thorough explanation, that's really useful

errors.append(f"Unknown observable_type '{observable_type}'; valid values are: {valid}.")

# Clamp the LLM-supplied limit into [1, _MAX_RESULTS] (treat tool args as untrusted).
limit = max(1, min(int(limit), _MAX_RESULTS))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we explicitly raise that a clamp has been done here? I mean, with a comment, a "warning" or whatever

@berardifra
Copy link
Copy Markdown
Contributor Author

This can happen from time to time considering that I can't review the changes as soon as they are published and some parallel PRs are normal in such environments.

Try to consider this while doing the changes to avoid having to fix conflicts every time. Isolate the content as soon as possible, abuse creation of additional files (like serializers.py and test_tools.py could become folders and contain isolated tests in separated files). This should reduce the issues

Yeah, I was expecting this one: two PRs touching the same files was a known risk on my side, so the rebase onto the umbrella was already part of the plan. Done now: additive conflicts only, kept both sides, 31/31 tests + Ruff green, mergeable again.
Good point on the isolation though -> I'll split serializers.py and test_tools.py into packages (one module per tool) so parallel PRs stop colliding.

…s + surface limit clamp (refs #3732)

  - Add Classification.observable_classifications() as the single source of truth
    for 'every classification except FILE'; reuse it in aggregate_observable_classification
  - Surface the limit clamp in the tool 'errors' (list_analyzers + recommend_playbook)
    so a truncated list is never silent
  - Tests for both clamp warnings
@berardifra
Copy link
Copy Markdown
Contributor Author

berardifra commented Jun 5, 2026

Addressed in 761950b, thanks

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

Labels

gsoc-2026 GSoC 2026 - LLM Chatbot project (Francesco Berardi)

Development

Successfully merging this pull request may close these issues.

2 participants