E530 Feat/session title generation by riturajFi · Pull Request #294 · memodb-io/Acontext · GitHub
[go: up one dir, main page]

Skip to content

Feat/session title generation#294

Open
riturajFi wants to merge 13 commits intomemodb-io:devfrom
riturajFi:feat/session_title_generation
Open

Feat/session title generation#294
riturajFi wants to merge 13 commits intomemodb-io:devfrom
riturajFi:feat/session_title_generation

Conversation

@riturajFi
Copy link
Contributor
@riturajFi riturajFi commented Feb 16, 2026

Why we need this PR?

This PR introduces automatic session title generation from the first meaningful user message so session lists are easier to scan and manage.

Today, sessions can remain untitled/opaque in UI/API consumers, especially when many sessions exist. This change adds a nullable display_title field and populates it once, non-blockingly, during pending-message processing.

This should close Issue (#118)

Describe your solution

What changed

  1. Added display_title to Session models in both services (API + CORE ORM sync):
  • src/server/api/go/internal/modules/model/session.go
  • src/server/core/acontext_core/schema/orm/session.py
  1. Added data-layer helpers in CORE:
  • update_session_display_title(...): persists generated title
  • should_generate_session_display_title(...): one-time gate (skip if already set)
  • Renamed ORM entity variable usage to session_record for clarity
  • File: src/server/core/acontext_core/service/data/session.py
  1. Implemented title generation flow in message controller:
  • Extract first user text from pending session messages
  • Normalize and quality-gate input (min length, skip low-signal inputs like hi, test, etc.)
  • Generate title via llm_complete(...) with dedicated prompt id: session.display_title.first_user
  • Sanitize output (strip quotes/newlines, trim length, require alphanumeric content)
  • Fallback to first-user-message words if model output is unusable
  • Persist title only when valid
  • Entire flow is non-blocking: all failures are caught and logged; task extraction continues
  • Title generation runs before task_agent_curd (description aligned with code)
  • Renamed DB context vars to db_session to avoid shadowing
  • File: src/server/core/acontext_core/service/controller/message.py
  1. Added CORE runtime schema patch organization for existing deployments:
  • Extracted runtime schema patch logic into:
    • src/server/core/acontext_core/infra/schema_migrations.py
  • Wired db.py to call patch application after create_all:
    • src/server/core/acontext_core/infra/db.py
  • Patch includes:
    • ALTER TABLE sessions ADD COLUMN IF NOT EXISTS display_title TEXT;
  1. Updated SDK types for session response shape:
  • Python SDK Session type includes nullable display_title:
    • src/client/acontext-py/src/acontext/types/session.py
  • TypeScript SDK SessionSchema includes nullable display_title:
    • src/client/acontext-ts/src/types/session.ts
  • Added parsing tests:
    • src/client/acontext-py/tests/test_client.py
    • src/client/acontext-py/tests/test_async_client.py
    • src/client/acontext-ts/tests/mocks.ts
    • src/client/acontext-ts/tests/client.test.ts

Behavioral guarantees

  • Title generation is best-effort and never blocks main message processing.
  • Title is generated once per session unless empty/missing.
  • Output is constrained to short, readable titles.

Non-functional notes

  • Removed local/editor artifact from PR scope:
    • .vscode/settings.json (removed)
  • src/server/.env.local-api is not part of this PR change set.

Implementation Tasks

Please ensure your pull request meets the following requirements:

  • Add nullable display_title to API session model (src/server/api/go/internal/modules/model/session.go)
  • Add nullable display_title to CORE ORM session model (src/server/core/acontext_core/schema/orm/session.py)
  • Add CORE data helpers to gate and persist display titles (src/server/core/acontext_core/service/data/session.py)
  • Add first-user-message extraction, quality checks, LLM title generation, sanitization, and persistence in message controller (src/server/core/acontext_core/service/controller/message.py)
  • Ensure title generation path is non-blocking with defensive error handling and logging
  • Organize runtime schema patch query logic in dedicated infra migration helper (src/server/core/acontext_core/infra/schema_migrations.py)
  • Update SDK session types for display_title (Python + TypeScript)
  • Remove .vscode/settings.json from PR scope

Impact Areas

Which part of Acontext would this feature affect?

  • Client SDK (Python)
  • Client SDK (TypeScript)
  • Core Service
  • API Server
  • Dashboard
  • CLI Tool
  • Documentation
  • Other

Checklist

  • Open your pull request against the dev branch.
  • All tests pass in available continuous integration systems (e.g., GitHub Actions).
  • Tests are added or modified as needed to cover code changes.

@GenerQAQ
Copy link
Contributor

Hi @riturajFi, thanks for the PR! The overall approach looks reasonable. I have a few comments before we can move forward:

Issues to address:

  1. Remove .vscode/settings.json — This is a local IDE config file (chatgpt.openOnStartup) and should not be committed. Please remove it from the PR.

  2. Missing DB migration — The display_title column was added to the ORM model, but I don't see a corresponding Alembic migration. We need a migration script to add the column to the sessions table.

  3. Missing SDK updates — Your description mentions Python and TypeScript SDK type updates, but the diff doesn't include changes to either SDK. Please add the display_title field to both SDK session types.

  4. Title generation ordering — In your description you mentioned title generation happens after task_agent_curd, but in the code it actually runs before task_agent_curd. Please either reorder the code or update the description to match.

  5. Variable shadowing — In message.py, the variable name session is used for both the SQLAlchemy AsyncSession (DB context) and the Session ORM object. This is confusing and could lead to bugs. Please rename one of them (e.g., use db_session for the database session context).

Looking forward to the updated PR!

@riturajFi riturajFi force-pushed the feat/session_title_generation branch from 0726a75 to f79adc2 Compare February 17, 2026 17:10
@riturajFi
Copy link
Contributor Author

Hi @GenerQAQ, thanks for the detailed review. Addressed all items:

  1. Removed .vscode/settings.json from the PR.

  2. Added migration handling for sessions.display_title on CORE startup:

  • src/server/core/acontext_core/infra/schema_migrations.py
  • src/server/core/acontext_core/infra/db.py
    This applies:
    ALTER TABLE sessions ADD COLUMN IF NOT EXISTS display_title TEXT;
    after create_all, so existing deployments are patched safely and idempotently.
  1. Added SDK updates for display_title:
  • Python: src/client/acontext-py/src/acontext/types/session.py
  • TypeScript: src/client/acontext-ts/src/types/session.ts
    Also added parsing tests:
  • src/client/acontext-py/tests/test_client.py
  • src/client/acontext-py/tests/test_async_client.py
  • src/client/acontext-ts/tests/client.test.ts
  • src/client/acontext-ts/tests/mocks.ts
  1. Kept code behavior as-is (title generation runs before task_agent_curd) and updated PR description to match exactly.

  2. Removed variable shadowing:

  • Renamed DB context vars to db_session in src/server/core/acontext_core/service/controller/message.py
  • Renamed ORM entity vars to session_record in src/server/core/acontext_core/service/data/session.py

Please take another look when you get a chance.

@riturajFi riturajFi marked this pull request as ready for review February 17, 2026 17:13
@riturajFi riturajFi requested a review from a team as a code owner February 17, 2026 17:13
@riturajFi riturajFi force-pushed the feat/session_title_generation branch from f79adc2 to 417358f Compare February 20, 2026 18:09
@riturajFi
Copy link
Contributor Author

@GenerQAQ kindly review the changes

Copy link
Contributor
@GenerQAQ GenerQAQ left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! The overall approach — non-blocking, best-effort session title generation with a one-time gate — is solid. There are several items to address before this can be merged.


Must Fix

1. Rebase on latest dev
The branch is 1 commit behind dev — missing c953a28 feat(session): add copy session functionality with SDK support (#280). Since that commit also touches session-related code and SDKs, please rebase to ensure compatibility.

2. Too many plan files
This PR includes 22 plan markdown files (one per milestone/sub-task). These are intermediate development artifacts and shouldn't be committed to the repository — they add significant noise to plans/. Please remove all milestone-level plans and keep only one summary plan (e.g., ai-session-display-title-first-message.md).

3. Replace runtime schema patch with proper migration
schema_migrations.py applies raw SQL (ALTER TABLE ... ADD COLUMN IF NOT EXISTS) at application startup. This bypasses the project's migration management — it can't be tracked, versioned, or rolled back. Please use the standard database migration approach instead. See inline comment.

4. Add CORE unit tests
The pure helper functions (normalize_title_input_text, check_title_input_quality, extract_first_user_message_text, sanitize_generated_title) have zero test coverage. These are ideal candidates for unit testing — they are pure functions with well-defined inputs and outputs. Please add tests for edge cases (empty input, Unicode, CJK text, very long input, boundary lengths, etc.).

5. Incomplete variable renaming (sessiondb_session)
The PR description says all DB context variables were renamed from session to db_session to avoid shadowing, but the learning_space query block still uses session. See inline comment at line 258.


Suggestions

See inline comments for:

  • TITLE_GENERATION_MAX_TOKENS may be too small for non-English languages
  • TITLE_INPUT_MIN_CHARS may be too strict
  • Redundant normalize_title_input_text call in check_title_input_quality

)


async def apply_runtime_schema_patches(db_session: AsyncSession) -> list[str]:
Copy link
Contributor

Choose a reason for hiding this comment

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

This runtime schema-patch approach (raw SQL at startup) bypasses the project's migration management. It can't be tracked, versioned, or rolled back, and may conflict with future migrations that touch the same table.

Please use a proper database migration (e.g., Alembic) to add the display_title column. This file and the _apply_schema_migrations call in db.py should be removed in favor of a migration script.


TITLE_INPUT_MAX_CHARS = 512
TITLE_INPUT_MIN_CHARS = 12
TITLE_GENERATION_MAX_TOKENS = 24
Copy link
Contributor

Choose a reason for hiding this comment

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

24 max tokens works for English titles (3-8 words), but CJK and other non-English languages often use 2-3 tokens per character. A Chinese title of 8 characters could easily require 16-24 tokens, leaving no margin.

Consider increasing to 48-64 to support multilingual title generation.

from ..data import session as SD

TITLE_INPUT_MAX_CHARS = 512
TITLE_INPUT_MIN_CHARS = 12
Copy link
Contributor

Choose a reason for hiding this comment

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

12 characters may be too strict as a minimum. Reasonable first messages like "Fix this bug" (12 chars) are borderline, and shorter but meaningful inputs like "Debug my app" (12 chars) barely pass.

Consider lowering to 8-10 characters.

def check_title_input_quality(text: str | None) -> tuple[bool, str]:
if text is None:
return False, "empty"
normalized = normalize_title_input_text(text)
Copy link
Contributor

Choose a reason for hiding this comment

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

Redundant normalization: extract_first_user_message_text already calls normalize_title_input_text on the extracted text before returning it (line 75). Calling normalize_title_input_text again here is a no-op on already-normalized input.

Consider removing this call and operating directly on text, or document why the double normalization is intentional.

)

ls_session = None
async with DB_CLIENT.get_session_context() as session:
Copy link
Contributor

Choose a reason for hiding this comment

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

This session variable was not renamed to db_session, inconsistent with the rest of the function. The PR description says all DB context variables were renamed to avoid shadowing.

Suggested change
async with DB_CLIENT.get_session_context() as session:
async with DB_CLIENT.get_session_context() as db_session:

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

0