-
Notifications
You must be signed in to change notification settings - Fork 18
1706 chat attachments + enhanced chat UI #1712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
simcariou
merged 41 commits into
swift
from
1706-chat-04-chat-attachments-option-a-composer-upload-ux-scheduler-task-ui
Jun 15, 2026
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
a82e305
wip: rework chat attachments
simcariou 3676665
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou ba5d497
feat: Add drag n' drop in chat + xlsx, txt, image in fast ingest
simcariou ade8727
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou e9878a3
fix: make test
simcariou 18bb42b
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou bc6cfbc
fix: remove "synthia" from pyproject.toml
simcariou 09162de
fix: type-check
simcariou bae2af8
fix: kics on frontend Dockerfile
simcariou 72418fc
fix: add transparency on drag and drop page
simcariou 2033eed
impr: Overall design and use slices instead of hardcoded queries in f…
simcariou 65106bf
impr: scrollable attachment list
simcariou 62e5a62
wip: Add persisted attachments management
simcariou 01d3543
impr: fast/delete and various fixes
simcariou d9a521a
impr: Deleting a conversation deletes all associated attachments
simcariou 6e03295
impr: rework SearchConfig in chat
simcariou eb74424
impr: close SearchConfig when clicking away
simcariou bf4ae42
impr: Bind mcp chat options to managed chat
simcariou 75cd0e4
fix: code-quality
simcariou 401727f
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou feeb6be
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou 3b0757b
fix: jsons schema for cp & test
simcariou 26e5119
fix: kf json schema
simcariou 3e205f9
fix: make test cp
simcariou 22f9d96
fix: code-quality
simcariou e749865
fix: use the same library picker in the SearchConfig and in the agent…
simcariou c21056d
#1706 merged latest swift and improve migration strategy plans
fbe2019
impr: add translations and better chat ui
simcariou b77d2f6
#1706 setup specs for migration export import next features
a7cdcba
#1706 merged latest 1706
74e06e4
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou 81fa534
fix: update helm schemas
simcariou 112e630
impr: Allow document selection in library picker
simcariou f1fb72c
fix: Document scoping + deport library selection UI
simcariou 651d524
feat: Allow mixing documents and librairies in vector search filtered…
simcariou 488f9a5
fix: Better ui feedback
simcariou 3a9029a
fix: code quality
simcariou a5f4727
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou a9216ec
fix: code-quality
simcariou d7b6155
impr: variable documentpicker height depending on the place in the chat
simcariou f965a38
Merge branch 'swift' into 1706-chat-04-chat-attachments-option-a-comp…
simcariou File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
apps/control-plane-backend/alembic/versions/f2b3c4d5e6f7_add_session_attachments.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| """add session attachments | ||
|
|
||
| Revision ID: f2b3c4d5e6f7 | ||
| Revises: be753abe25d7 | ||
| Create Date: 2026-06-11 12:30:00.000000 | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import sqlalchemy as sa | ||
|
|
||
| from alembic import op | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision = "f2b3c4d5e6f7" # pragma: allowlist secret | ||
| down_revision = "b4c5d6e7f8a9" # pragma: allowlist secret | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| op.create_table( | ||
| "session_attachments", | ||
| sa.Column("session_id", sa.String(), nullable=False), | ||
| sa.Column("attachment_id", sa.String(), nullable=False), | ||
| sa.Column("name", sa.String(), nullable=False), | ||
| sa.Column("mime", sa.String(), nullable=True), | ||
| sa.Column("size_bytes", sa.Integer(), nullable=True), | ||
| sa.Column("summary_md", sa.Text(), nullable=False), | ||
| sa.Column("document_uid", sa.String(), nullable=True), | ||
| sa.Column("storage_key", sa.String(), nullable=True), | ||
| sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), | ||
| sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), | ||
| sa.PrimaryKeyConstraint("session_id", "attachment_id"), | ||
| ) | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| op.drop_table("session_attachments") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
apps/control-plane-backend/control_plane_backend/migration/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| """Kea→Swift platform import (MIGR-05). | ||
|
|
||
| See docs/swift/rfc/PLATFORM-IMPORT-RFC.md for the design. | ||
| """ |
108 changes: 108 additions & 0 deletions
108
apps/control-plane-backend/control_plane_backend/migration/agent_map.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| """Kea→Swift agent template mapping (MIGR-05). | ||
|
|
||
| Maps a kea-exported agent to its swift template, so the import can create the | ||
| equivalent managed `agent_instance`. See docs/swift/rfc/PLATFORM-IMPORT-RFC.md §7. | ||
|
|
||
| The mapping table is the single control point. Every exported agent is classified | ||
| into exactly one outcome: | ||
|
|
||
| - ``MAPPED`` — the kea template has a swift equivalent; create the agent_instance. | ||
| - ``IGNORED`` — a known kea built-in sample/demo; not user data, skipped on purpose. | ||
| - ``GAP`` — no mapping yet (or no resolvable template); the equivalent must be | ||
| built in fred-agents and added here. A real cutover requires zero gaps. | ||
|
|
||
| Scope is user-created agent instances; kea sample agents are intentionally not | ||
| migrated (swift provides its own catalog). | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| from collections.abc import Mapping | ||
| from dataclasses import dataclass | ||
| from enum import Enum | ||
| from typing import Any | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| # Kea template identity → swift template id (``{source_runtime_id}:{source_agent_id}``). | ||
| # Keys are a v2 ``definition_ref`` or a legacy v1 ``class_path``. Swift ids are | ||
| # validated at import time against the live fred-agents ``/agents/templates`` catalog. | ||
| KEA_TO_SWIFT_TEMPLATE: dict[str, str] = { | ||
| # Agents users actually create on kea: | ||
| "v2.react.basic": "fred-agents:fred.github.assistant", | ||
| "v2.production.sql_analyst": "fred-agents:fred.github.sql_expert", | ||
| # Equivalents available if a real user instance uses them: | ||
| "agentic_backend.agents.v1.production.prometheus.prometheus_expert.Spot": "fred-agents:fred.github.sentinel", | ||
| "agentic_backend.agents.v1.production.rags.rag_expert.Rico": "fred-agents:fred.github.rag_expert", | ||
| "agentic_backend.agents.v1.production.tabular.tabular_expert.Tessa": "fred-agents:fred.github.sql_expert", | ||
| } | ||
|
|
||
| # Kea built-in sample/demo templates that are intentionally NOT migrated. Listed so | ||
| # preflight treats them as expected rather than as gaps requiring a new fred-agents | ||
| # template. | ||
| IGNORED_KEA_TEMPLATES: frozenset[str] = frozenset( | ||
| { | ||
| "v2.sample.bank_transfer", | ||
| "v2.deep.corpus_investigator", | ||
| "v2.production.dva_risk_validator.graph", | ||
| "v2.production.dva_risk_validator.qa", | ||
| } | ||
| ) | ||
|
|
||
|
|
||
| class AgentMapOutcome(str, Enum): | ||
| """How an exported kea agent is treated by the import.""" | ||
|
|
||
| MAPPED = "mapped" | ||
| IGNORED = "ignored" | ||
| GAP = "gap" | ||
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class AgentMapResult: | ||
| """Result of classifying one exported kea agent. | ||
|
|
||
| ``kea_template`` is the resolved template identity (``None`` when neither a | ||
| ``definition_ref`` nor a ``class_path`` is present). ``swift_template_id`` is set | ||
| only when ``outcome`` is ``MAPPED``. | ||
| """ | ||
|
|
||
| outcome: AgentMapOutcome | ||
| kea_template: str | None | ||
| swift_template_id: str | None | ||
|
|
||
|
|
||
| def resolve_kea_template(payload: Mapping[str, Any]) -> str | None: | ||
| """Return the kea template identity from an exported agent ``payload_json``. | ||
|
|
||
| v2 agents carry a top-level ``definition_ref``; legacy v1 agents carry a | ||
| top-level ``class_path``. ``definition_ref`` takes precedence. Returns ``None`` | ||
| when neither is present (the agent is then a GAP). | ||
| """ | ||
| definition_ref = payload.get("definition_ref") | ||
| if isinstance(definition_ref, str) and definition_ref.strip(): | ||
| return definition_ref | ||
| class_path = payload.get("class_path") | ||
| if isinstance(class_path, str) and class_path.strip(): | ||
| return class_path | ||
| return None | ||
|
|
||
|
|
||
| def classify_agent(payload: Mapping[str, Any]) -> AgentMapResult: | ||
| """Classify one exported kea agent ``payload_json`` into mapped / ignored / gap. | ||
|
|
||
| The agent is MAPPED when its template is in ``KEA_TO_SWIFT_TEMPLATE``, IGNORED | ||
| when it is a known sample, and a GAP otherwise (including when no template can be | ||
| resolved). Each GAP is a fred-agents template to build before cutover. | ||
| """ | ||
| kea_template = resolve_kea_template(payload) | ||
| if kea_template is None: | ||
| return AgentMapResult(AgentMapOutcome.GAP, None, None) | ||
| swift_template_id = KEA_TO_SWIFT_TEMPLATE.get(kea_template) | ||
| if swift_template_id is not None: | ||
| return AgentMapResult(AgentMapOutcome.MAPPED, kea_template, swift_template_id) | ||
| if kea_template in IGNORED_KEA_TEMPLATES: | ||
| return AgentMapResult(AgentMapOutcome.IGNORED, kea_template, None) | ||
| return AgentMapResult(AgentMapOutcome.GAP, kea_template, None) |
32 changes: 32 additions & 0 deletions
32
apps/control-plane-backend/control_plane_backend/models/session_attachment_models.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from datetime import datetime | ||
|
|
||
| from sqlalchemy import DateTime, Integer, String, Text | ||
| from sqlalchemy.orm import Mapped, mapped_column | ||
|
|
||
| from control_plane_backend.models.base import Base, utcnow | ||
|
|
||
|
|
||
| class SessionAttachmentRow(Base): | ||
| """ORM model for the ``session_attachments`` table.""" | ||
|
|
||
| __tablename__ = "session_attachments" | ||
|
|
||
| session_id: Mapped[str] = mapped_column(String, primary_key=True) | ||
| attachment_id: Mapped[str] = mapped_column(String, primary_key=True) | ||
| name: Mapped[str] = mapped_column(String, nullable=False) | ||
| mime: Mapped[str | None] = mapped_column(String, nullable=True) | ||
| size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True) | ||
| summary_md: Mapped[str] = mapped_column(Text, nullable=False) | ||
| document_uid: Mapped[str | None] = mapped_column(String, nullable=True) | ||
| storage_key: Mapped[str | None] = mapped_column(String, nullable=True) | ||
| created_at: Mapped[datetime] = mapped_column( | ||
| DateTime(timezone=True), nullable=False, default=utcnow | ||
| ) | ||
| updated_at: Mapped[datetime] = mapped_column( | ||
| DateTime(timezone=True), | ||
| nullable=False, | ||
| default=utcnow, | ||
| onupdate=utcnow, | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.