Skip to content

feat: Set up backend for in-component config assistant#3955

Open
re-pixel wants to merge 9 commits intosuperplanehq:mainfrom
re-pixel:feat/config-assist
Open

feat: Set up backend for in-component config assistant#3955
re-pixel wants to merge 9 commits intosuperplanehq:mainfrom
re-pixel:feat/config-assist

Conversation

@re-pixel
Copy link
Copy Markdown
Collaborator

@re-pixel re-pixel commented Apr 4, 2026

Inline config assistant — backend

Summary

This PR implements the backend for the inline configuration assistant described in docs/prd/inline-config-assistant.md: a stateless, one-shot suggest API that forwards to a dedicated Python path (no AI Builder tool loop, no shared agent.py orchestration for this route).

Scope: Go public API + gRPC service, authorization, scoped JWT minting, HTTP forward to the agent, and the agent-side FastAPI route + PydanticAI suggest flow. No workflow UI in this PR (PRD client wiring in lib/configAssistantSuggest.ts / useConfigAssistantSuggest remains a follow-up).


End-to-end flow (updated)

  1. Client calls POST /api/v1/agents/config/prepare-suggest with session auth (or user API token) and org context (x-organization-id), same as other org APIs. Body: canvasId only.
  2. grpc-gateway maps to Agents.PrepareConfigAssistantSuggest.
  3. AuthZ (pkg/authorization/interceptor.go): user must have canvases:update on the canvas referenced by canvas_id (same bar as editing the workflow).
  4. Handler (pkg/grpc/actions/configassistant/prepare.go):
    • Validates canvas_id, resolves org/canvas.
    • Resolves scoped JWT permissions (org read, integrations read, canvases:read:<canvas_id>) so the agent can validate the token without builder-only semantics.
    • Mints a short-lived scoped JWT with purpose: config-assistant (distinct from agent-builder).
    • Returns token and suggestUrl = {AGENT_HTTP_URL}/config-assistant/suggest (no server-side forward).
  5. Client **POST**s to suggestUrl with Authorization: Bearer <token> and JSON body canvas_id, node_id, instruction, field_context_json (snake_case; matches Python SuggestHTTPRequest).
  6. Agent (agent/src/config_assistant/router.py): unchanged behavior — validate JWT purpose, validate canvas scope, one-shot PydanticAI, structured value + optional explanation.

From the product perspective the UI can still expose one “Generate” action; under the hood that is two HTTP requests, encapsulated by runConfigAssistantSuggest in web_src/src/lib/configAssistantSuggest.ts.

sequenceDiagram
  autonumber
  participant Browser
  participant GoAPI
  participant AgentHTTP
  participant LLM
  Browser->>GoAPI: POST prepare-suggest
  Note over GoAPI: Session auth, canvases update permission
  Note over GoAPI: Mint scoped JWT, purpose config-assistant
  GoAPI-->>Browser: token and suggestUrl
  Browser->>AgentHTTP: POST suggestUrl with Bearer and JSON body
  Note over AgentHTTP: Validate JWT and canvas scope
  AgentHTTP->>LLM: PydanticAI one-shot
  LLM-->>AgentHTTP: value, explanation
  AgentHTTP-->>Browser: JSON response
Loading

JWT purposes

  • config-assistant and agent-builder are both allowed by the shared Python validator (agent/src/ai/jwt.py), but the config-assistant route requires purpose == config-assistant so tokens are not interchangeable (PRD acceptance criteria).

Alignment with AI Builder (org “AI off”)

  • The PRD states org-level AI off should yield 403 for suggest, aligned with AI Builder (Decisions §1 in the PRD).
  • Today, AI Builder chat creation in Go does not check org agent settings, while the UI mainly gates the repl via env. To avoid a worse UX where Builder works from the browser but suggest fails from the same org, this PR does not enforce AgentModeEnabled on suggest. We can add a shared server-side gate for both Builder and suggest in a follow-up if product wants strict PRD alignment.

Configuration

Variable Role
AGENT_HTTP_URL Required for prepare: used to build suggestUrl returned to the client (e.g. http://localhost:8090 when the agent port is published on the host).
JWT_SECRET Shared between app and agent for scoped tokens.
CONFIG_ASSISTANT_AI_MODEL / AI_MODEL / ANTHROPIC_API_KEY Agent-side model and provider (see PRD and agent/.env.example).

Removed: CONFIG_ASSISTANT_HTTP_URL (no longer used).


Testing

  • make test.agent.unit — JWT and config-assistant agent tests (unchanged).
  • go test ./pkg/grpc/actions/configassistant/... — URL builder unit tests (prepare_test.go).
  • Manual: (1) authenticated POST …/prepare-suggest with { "canvasId": "…" }; (2) POST returned suggestUrl with Authorization: Bearer <token> and snake_case suggest body.

re-pixel added 2 commits April 4, 2026 19:44
…llm assistance

Signed-off-by: re-pixel <relja.brdar@gmail.com>
Signed-off-by: re-pixel <relja.brdar@gmail.com>
@superplanehq-integration
Copy link
Copy Markdown

👋 Commands for maintainers:

  • /sp start - Start an ephemeral machine (takes ~30s)
  • /sp stop - Stop a running machine (auto-executed on pr close)

Comment thread agent/src/ai/jwt.py
Comment thread protos/config_assistant.proto Outdated
produces: "application/json";
};

service ConfigAssistant {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This shouldn't be a separate proto. It should be in agents.proto.

Maybe we can have an API like this:

/api/v1/agents/builder/* => the existing API in agents.proto
/api/v1/agents/config/* => new API for configuration suggestions

re-pixel added 2 commits April 4, 2026 23:27
…ig assistant scopedJWTs

Signed-off-by: re-pixel <relja.brdar@gmail.com>
…r chats moved from /api/v1/agents/chats to /api/v1/agents/builder/chats, new endpoint for config assistant is /api/v1/agents/config/suggest-field

Signed-off-by: re-pixel <relja.brdar@gmail.com>
@superplane-policy-bot superplane-policy-bot bot requested a review from lucaspin April 4, 2026 22:05
Comment thread agent/src/config_assistant/router.py
re-pixel added 3 commits April 5, 2026 00:23
Signed-off-by: re-pixel <relja.brdar@gmail.com>
…imilar to the builder agent browser -> go API -> browser -> agent HTTP -> browser

Signed-off-by: re-pixel <relja.brdar@gmail.com>
Comment thread agent/src/config_assistant/router.py Outdated
Signed-off-by: re-pixel <relja.brdar@gmail.com>
Comment thread agent/src/config_assistant/router.py Outdated
Signed-off-by: re-pixel <relja.brdar@gmail.com>
@lucaspin
Copy link
Copy Markdown
Contributor

lucaspin commented Apr 7, 2026

@re-pixel @shiroyasha am I reading this right that there's no SSE streaming here? If that's the case, I don't think we need the "generate token and redirect to agent HTTP endpoint", right? We could have an internal agent gRPC endpoint that the public agent API calls for this

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 224a5eb. Configure here.

node_id=payload.node_id.strip(),
)

agent = build_config_assistant_agent(model=model_name)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agent and prompt rebuilt from disk every request

Low Severity

build_config_assistant_agent is called on every request, which internally calls load_system_prompt() that reads system_prompt.txt from disk each time. The model name and system prompt are stable across requests, so the agent could be constructed once at router-build time (or lazily cached) rather than re-created per request.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 224a5eb. Configure here.

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