Skip to content

fix: preserve session start metadata#318

Open
Zavianx wants to merge 1 commit into
rohitg00:mainfrom
Zavianx:fix/session-start-metadata
Open

fix: preserve session start metadata#318
Zavianx wants to merge 1 commit into
rohitg00:mainfrom
Zavianx:fix/session-start-metadata

Conversation

@Zavianx
Copy link
Copy Markdown

@Zavianx Zavianx commented May 13, 2026

Summary

  • accept optional title, summary, and firstPrompt in POST /agentmemory/session/start
  • use title as the fallback session label/first prompt so OpenCode-created sessions do not surface as raw IDs when prompt submission races session creation
  • keep explicit summary and firstPrompt values distinct when clients provide both
  • document the optional session labels in the API table

Fixes #244

Related

Tests

  • npm run build
  • npm test
  • npm test -- test/api-session-start.test.ts

Signed-off-by: Zavian <36817799+Zavianx@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

@Zavianx is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

The PR extends the session creation endpoint to accept and persist optional human-readable labels (title, summary, firstPrompt) provided in the request body. A helper function normalizes and truncates these strings; summary and firstPrompt default to the title value when omitted. The endpoint behavior, test coverage, and API documentation are all updated together.

Changes

Session Label Initialization

Layer / File(s) Summary
Preview helper and request contract
src/triggers/api.ts
asSessionPreview(value, maxLength) normalizes whitespace and truncates strings; the api::session::start request body type now includes optional title, summary, and firstPrompt fields.
Session label computation and assignment
src/triggers/api.ts
When creating a session, each label is converted to a truncated preview. summary and firstPrompt fall back to the title preview when not explicitly provided; both are assigned to the session only if non-empty.
Documentation and test coverage
README.md, test/api-session-start.test.ts
README API table documents the three new optional fields; test suite verifies that omitting summary and firstPrompt causes them to inherit from title, and that explicit values are preserved in both response body and KV-persisted session.

🎯 2 (Simple) | ⏱️ ~12 minutes

🐰 Sessions now wear their names with pride,
No more IDs to hide or misguide,
From title springs summary and prompt so fine,
All three labels dance in perfect design!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: preserve session start metadata' is concise and directly relates to the main change: accepting and preserving optional session metadata (title, summary, firstPrompt) in the POST /agentmemory/session/start endpoint.
Linked Issues check ✅ Passed The pull request fully addresses issue #244: api::session::start now reads and stores body.title as both summary and firstPrompt, resolving the raw ID display issue and race condition mentioned in the issue.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #244: README documentation updates, API handler modifications to accept/process metadata fields, and comprehensive test coverage for the new functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/triggers/api.ts (1)

546-558: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix Unicode truncation in asSessionPreview to prevent data corruption.

The test reveals a real bug: truncating strings containing emojis or other non-BMP characters at certain boundaries creates invalid UTF-16 sequences. When the string contains an emoji (or similar 2-code-unit character) near the maxLength boundary, .slice(0, maxLength) splits the surrogate pair, leaving an orphaned surrogate that becomes a replacement character U+FFFD.

For example, asSessionPreview("a".repeat(199) + "👋", 200) produces a string ending with a replacement character instead of the emoji, corrupting the stored session metadata.

Fix: Use a function that respects grapheme boundaries when truncating (e.g., by counting Unicode code points or using a proper grapheme library), or document the limitation. This affects session.summary and session.firstPrompt which are persisted and used throughout the application.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/triggers/api.ts` around lines 546 - 558, The asSessionPreview truncation
is splitting UTF-16 surrogate pairs and corrupting emojis stored in
session.summary and session.firstPrompt; update asSessionPreview to truncate by
Unicode grapheme/code points (not by string index) — e.g., use
Array.from(string) or Intl.Segmenter to count/slice user-perceived characters or
integrate a grapheme library, then return the joined slice ensuring you preserve
full code points; keep callers (where session.summary and session.firstPrompt
are set) unchanged.
🧹 Nitpick comments (1)
test/api-session-start.test.ts (1)

33-55: ⚡ Quick win

Consider adding test coverage for edge cases.

The current tests validate the core fallback and explicit-field behavior, but several edge cases are not covered:

  • Empty or whitespace-only strings (should return sessions without summary/firstPrompt)
  • Strings exceeding maxLength (200 for title/firstPrompt, 300 for summary)
  • Multi-line strings with various whitespace patterns
  • Unicode characters including surrogate pairs at truncation boundaries

These edge cases would increase confidence that asSessionPreview handles all inputs correctly.

📋 Example additional test cases
+  it("handles empty and whitespace-only inputs", async () => {
+    const { sdk, kv } = setupApi();
+
+    await sdk.trigger("api::session::start", {
+      body: {
+        sessionId: "ses_empty",
+        project: "/tmp/project",
+        cwd: "/tmp/project",
+        title: "   ",
+        summary: "",
+      },
+    });
+
+    const session = await kv.get<Session>(KV.sessions, "ses_empty");
+    expect(session?.summary).toBeUndefined();
+    expect(session?.firstPrompt).toBeUndefined();
+  });
+
+  it("truncates long strings to maxLength", async () => {
+    const { sdk, kv } = setupApi();
+    const longTitle = "a".repeat(250);
+    const longSummary = "b".repeat(350);
+
+    await sdk.trigger("api::session::start", {
+      body: {
+        sessionId: "ses_long",
+        project: "/tmp/project",
+        cwd: "/tmp/project",
+        title: longTitle,
+        summary: longSummary,
+      },
+    });
+
+    const session = await kv.get<Session>(KV.sessions, "ses_long");
+    expect(session?.summary?.length).toBe(300);
+    expect(session?.firstPrompt?.length).toBe(200);
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/api-session-start.test.ts` around lines 33 - 55, Add unit tests
exercising asSessionPreview edge cases: (1) submit empty and whitespace-only
title/summary/firstPrompt via sdk.trigger (using setupApi and KV.sessions) and
assert stored session has no summary/firstPrompt; (2) submit strings exceeding
the max lengths (title/firstPrompt 200, summary 300) and assert the persisted
session fields are truncated to those limits; (3) supply multi-line strings with
varied whitespace and assert trimming/normalization behavior matches
asSessionPreview; (4) include Unicode surrogate-pair boundaries (e.g., emoji at
truncation edge) and assert truncation does not split surrogate pairs. Use the
same test harness patterns in the existing test (sdk.trigger, KV.sessions,
Session) and add separate it() cases for each edge scenario.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/triggers/api.ts`:
- Around line 546-558: The asSessionPreview truncation is splitting UTF-16
surrogate pairs and corrupting emojis stored in session.summary and
session.firstPrompt; update asSessionPreview to truncate by Unicode
grapheme/code points (not by string index) — e.g., use Array.from(string) or
Intl.Segmenter to count/slice user-perceived characters or integrate a grapheme
library, then return the joined slice ensuring you preserve full code points;
keep callers (where session.summary and session.firstPrompt are set) unchanged.

---

Nitpick comments:
In `@test/api-session-start.test.ts`:
- Around line 33-55: Add unit tests exercising asSessionPreview edge cases: (1)
submit empty and whitespace-only title/summary/firstPrompt via sdk.trigger
(using setupApi and KV.sessions) and assert stored session has no
summary/firstPrompt; (2) submit strings exceeding the max lengths
(title/firstPrompt 200, summary 300) and assert the persisted session fields are
truncated to those limits; (3) supply multi-line strings with varied whitespace
and assert trimming/normalization behavior matches asSessionPreview; (4) include
Unicode surrogate-pair boundaries (e.g., emoji at truncation edge) and assert
truncation does not split surrogate pairs. Use the same test harness patterns in
the existing test (sdk.trigger, KV.sessions, Session) and add separate it()
cases for each edge scenario.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 18710b31-39d6-48db-9f43-3c30791ff8b0

📥 Commits

Reviewing files that changed from the base of the PR and between 25dddc4 and 1934214.

📒 Files selected for processing (3)
  • README.md
  • src/triggers/api.ts
  • test/api-session-start.test.ts

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.

fix: OpenCode sessions show raw IDs instead of human-readable names

1 participant