Skip to content

Conversation

@etsien
Copy link
Collaborator

@etsien etsien commented Nov 6, 2025

Builds on top of prior PR APPENG-3801-B

  • Consolidate all prompts into src/vuln_analysis/utils/prompting.py
  • Order them by stage section
  • Add system prompt sections for all stages, /no_think added by default for stages not requiring thinking mode
  • Added prompt helper functions to assemble into LangChain PromptTemplate or ChatPromptTemplate objects, based on if it's a simple stage or a ReAct Agent stage.
  • Cleaned up examples
  • Standardized prompt formatting, tool definitions, updated tool selection strategy to include latest transitive search updates, standardized output definitions.
  • Transitioned all stages' output parsing to use Pydantic2 for structured outputs types.
  • Added custom "thinking-aware" output parsing for ReAct stages to make more robust to output issues
  • Add the beginning of more detailed logging for error/failure tracking

etsien added 30 commits October 2, 2025 16:13
…l descriptions to both checklist and agent prompts
adding in constants during the vdb generation check
etsien added 23 commits November 5, 2025 11:59
…l descriptions to both checklist and agent prompts
adding in constants during the vdb generation check
…cution-stages' of https://github.com/etsien/vulnerability-analysis into APPENG-3801-B-Agent-performance-fixes-checklist-and-execution-stages
@etsien
Copy link
Collaborator Author

etsien commented Nov 6, 2025

/retest vulnerability-analysis-on-pr

@tmihalac
Copy link

tmihalac commented Nov 10, 2025

Hi, I am running locally with your changes, I am getting this error:
KeyError: 'Input to ChatPromptTemplate is missing variables {\'\\n "scores"\'}. Expected: [\'\\n "scores"\', \'cve_data\'] Received: [\'cve_data\']\nNote: if you intended {\n "scores"} to be part of the string and not a variable, please escape it with double curly braces like: \'{{\n "scores"}}\'.\nFor troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/INVALID_PROMPT_INPUT ' During task with name 'calculate_intel_score_node' and id '92b3e313-3d0a-5350-bc2b-e4bd2a1bcf04'

When running on CVE-2024-26147
I am using config-http-openai.yml

When I disable calculate cve score feature, I am getting a different error:
ERROR: Exception in ASGI application

  • Exception Group Traceback (most recent call last):
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 76, in collapse_excgroups
    | yield
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 177, in call
    | async with anyio.create_task_group() as task_group:
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/anyio/_backends/_asyncio.py", line 772, in aexit
    | raise BaseExceptionGroup(
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 409, in run_asgi
    | result = await app( # type: ignore[func-returns-value]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in call
    | return await self.app(scope, receive, send)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in call
    | await super().call(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/applications.py", line 112, in call
    | await self.middleware_stack(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 187, in call
    | raise exc
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 165, in call
    | await self.app(scope, receive, _send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 176, in call
    | with recv_stream, send_stream, collapse_excgroups():
    | ^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/contextlib.py", line 158, in exit
    | self.gen.throw(value)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/_utils.py", line 82, in collapse_excgroups
    | raise exc
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 178, in call
    | response = await self.dispatch_func(request, call_next)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py", line 133, in authentication_log_filter
    | return await self._suppress_authentication_logs(request, call_next)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py", line 183, in _suppress_authentication_logs
    | response = await call_next(request)
    | ^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 156, in call_next
    | raise app_exc
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/base.py", line 141, in coro
    | await self.app(scope, receive_or_disconnect, send_no_error)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 85, in call
    | await self.app(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in call
    | await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    | raise exc
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    | await app(scope, receive, sender)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 714, in call
    | await self.middleware_stack(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 734, in app
    | await route.handle(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 288, in handle
    | await self.app(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 76, in app
    | await wrap_app_handling_exceptions(app, request)(scope, receive, send)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    | raise exc
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    | await app(scope, receive, sender)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/starlette/routing.py", line 73, in app
    | response = await f(request)
    | ^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 301, in app
    | raw_response = await run_endpoint_function(
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 212, in run_endpoint_function
    | return await dependant.call(**values)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py", line 624, in post_single
    | return await generate_single_response(payload, session_manager, result_type=result_type)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/front_ends/fastapi/response_helpers.py", line 117, in generate_single_response
    | return await runner.result(to_type=result_type)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/runtime/runner.py", line 141, in result
    | result = await self._entry_fn.ainvoke(self._input_message, to_type=to_type)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/builder/function.py", line 159, in ainvoke
    | raise e
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/builder/function.py", line 149, in ainvoke
    | result = await self._ainvoke(converted_input)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/builder/function.py", line 325, in _ainvoke
    | return await self._ainvoke_fn(value)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/register.py", line 257, in _response_fn
    | results = await graph.ainvoke(input_message)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/init.py", line 2389, in ainvoke
    | async for chunk in self.astream(
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/init.py", line 2274, in astream
    | async for _ in runner.atick(
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/runner.py", line 444, in atick
    | await arun_with_retry(
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/retry.py", line 128, in arun_with_retry
    | return await task.proc.ainvoke(task.input, config)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/utils/runnable.py", line 583, in ainvoke
    | input = await step.ainvoke(input, config, **kwargs)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/utils/runnable.py", line 371, in ainvoke
    | ret = await asyncio.create_task(coro, context=context)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/futures.py", line 289, in await
    | yield self # This tells Task to wait for completion.
    | ^^^^^^^^^^
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/tasks.py", line 385, in __wakeup
    | future.result()
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/futures.py", line 202, in result
    | raise self._exception.with_traceback(self._exception_tb)
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/tasks.py", line 314, in __step_run_and_handle_result
    | result = coro.send(None)
    | ^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/utils/error_handling_decorator.py", line 18, in catch_errors
    | return await func(self, args, **kwargs)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/register.py", line 198, in call_llm_engine_subgraph_node
    | results = await subgraph.ainvoke(subgraph_input)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/init.py", line 2389, in ainvoke
    | async for chunk in self.astream(
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/init.py", line 2274, in astream
    | async for _ in runner.atick(
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/runner.py", line 444, in atick
    | await arun_with_retry(
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/pregel/retry.py", line 128, in arun_with_retry
    | return await task.proc.ainvoke(task.input, config)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/utils/runnable.py", line 583, in ainvoke
    | input = await step.ainvoke(input, config, **kwargs)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langgraph/utils/runnable.py", line 371, in ainvoke
    | ret = await asyncio.create_task(coro, context=context)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/futures.py", line 289, in await
    | yield self # This tells Task to wait for completion.
    | ^^^^^^^^^^
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/tasks.py", line 385, in __wakeup
    | future.result()
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/futures.py", line 202, in result
    | raise self._exception.with_traceback(self._exception_tb)
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/tasks.py", line 316, in __step_run_and_handle_result
    | result = coro.throw(exc)
    | ^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/register.py", line 141, in checklist_node
    | return await cve_checklist_fn.ainvoke(state.model_dump())
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/builder/function.py", line 159, in ainvoke
    | raise e
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/builder/function.py", line 149, in ainvoke
    | result = await self._ainvoke(converted_input)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/nat/builder/function.py", line 325, in _ainvoke
    | return await self._ainvoke_fn(value)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/functions/cve_checklist.py", line 79, in _arun
    | results = await asyncio.gather(
    (generate_checklist_for_cve(cve_intel) for cve_intel in workflow_cve_intel))
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/tasks.py", line 385, in __wakeup
    | future.result()
    | File "/home/tmihalac/.local/share/uv/python/cpython-3.12.11-linux-x86_64-gnu/lib/python3.12/asyncio/tasks.py", line 314, in __step_run_and_handle_result
    | result = coro.send(None)
    | ^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/functions/cve_checklist.py", line 64, in generate_checklist_for_cve
    | checklist = await generate_checklist(prompt=config.prompt,
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/src/vuln_analysis/utils/checklist_prompt_generator.py", line 170, in generate_checklist
    | chat_prompt = ChatPromptTemplate.from_messages([
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/chat.py", line 1170, in from_messages
    | return cls(messages, template_format=template_format)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/chat.py", line 952, in init
    | _convert_to_message_template(message, template_format)
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/chat.py", line 1447, in convert_to_message_template
    | message
    = _create_template_from_message_type(
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/chat.py", line 1346, in _create_template_from_message_type
    | message: BaseMessagePromptTemplate = HumanMessagePromptTemplate.from_template(
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/chat.py", line 437, in from_template
    | prompt: Union[StringPromptTemplate, list] = PromptTemplate.from_template(
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/prompt.py", line 290, in from_template
    | input_variables = get_template_variables(template, template_format)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/home/tmihalac/IdeaProjects/vulnerability-analysis/.venv/lib/python3.12/site-packages/langchain_core/prompts/string.py", line 255, in get_template_variables
    | v for _, v, _, _ in Formatter().parse(template) if v is not None
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | ValueError: unmatched '{' in format spec
    | During task with name 'checklist' and id '2f786271-fd7b-f583-427e-dc30e993125f'
    | During task with name 'llm_engine' and id '3a61e2d2-cd4d-7ce3-1479-ae906e1939a8'

@etsien etsien requested a review from zvigrinberg November 10, 2025 19:29
@etsien
Copy link
Collaborator Author

etsien commented Nov 11, 2025

/retest vulnerability-analysis-on-pr

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