Skip to content

fix(cli): import ChatGPT conversations that have no title - #1790

Merged
phernandez merged 2 commits into
mainfrom
chatgpt-import-untitled
Oct 20, 2026
Merged

phernandez merged 2 commits into
mainfrom
chatgpt-import-untitled

Conversation

@phernandez

Copy link
Copy Markdown
Member

Problem

bm import chatgpt failed with KeyError: 'title' when a conversation in the export had no title field. One such conversation failed the whole import. Basic Memory Cloud saw 6 of these failures from one user who kept retrying (cloud Logfire issue #3129, tracked in basic-memory-cloud#2610).

Design

_resolve_title returns the conversation's title when it is a non-empty string. Otherwise it builds Untitled conversation <first 8 chars of the conversation id>.

The title names the output file, just like the date in _resolve_timestamps (#1276). So the fallback must not change between exports. The conversation id never changes, while import order does. With no id at all, a fixed Untitled conversation is the last resort.

The resolved title is used for the file name, the # heading and the frontmatter title.

Tests

test_import_chatgpt_untitled_conversation_uses_its_id covers a missing, null and blank title. Each case imports twice and asserts:

  • exactly one file exists;
  • it is named from the id;
  • its frontmatter carries the fallback title.

Load-bearing: with the importer change reverted, all three cases fail. With it restored, they pass. All 10 tests in tests/cli/test_import_chatgpt.py pass, and lint is clean.

just typecheck reports 4 unresolved pymilvus imports in this worktree. Those also appear on main, so they are not from this change.

🤖 Generated with Claude Code

https://claude.ai/code/session_016N9c6ouiT4Wid3arGR41Dv

A conversation exported without a title, or with a null or blank one,
raised KeyError and failed the whole import. The importer now names it
from the conversation id, which stays the same across re-exports, so a
later import updates the same note instead of writing a duplicate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N9c6ouiT4Wid3arGR41Dv
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez phernandez added the cost-review-2026-10 October 2026 COGS review: cost leaks, heavy tenants, and production error triage label Oct 20, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T06:48:00.118609Z 1d3c1eb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@phernandez phernandez changed the title fix(import): import ChatGPT conversations that have no title fix(cli): import ChatGPT conversations that have no title Oct 20, 2026
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 73050ea5ca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +161 to +164
conversation_id = conversation.get("conversation_id") or conversation.get("id")
if conversation_id:
return f"Untitled conversation {str(conversation_id)[:8]}"
return "Untitled conversation"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve uniqueness in generated fallback titles

When two titleless conversations created on the same day either lack identifiers or have identifiers sharing the first eight characters, this fallback generates the same output path for both. write_entity then replaces the first markdown file while the importer still reports both conversations as imported, silently losing canonical note content. Use the full stable identifier, and explicitly reject or deterministically disambiguate conversations without one.

AGENTS.md reference: AGENTS.md:L157-L161

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 1d3c1eb. The fallback now uses the full conversation id, then the root message id, which is also fixed when the conversation starts and survives re-exports. A conversation with neither is rejected with a ValueError instead of falling back to a fixed name. test_import_chatgpt_untitled_conversations_without_ids_stay_distinct imports two id-less, untitled conversations from the same day and asserts two files. It fails on the previous head.

Use the full conversation id, then the root message id, so two untitled
conversations can never write the same file. A conversation with neither is
rejected instead of overwriting another note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N9c6ouiT4Wid3arGR41Dv
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez
phernandez merged commit 72fba3f into main Oct 20, 2026
34 checks passed
@phernandez
phernandez deleted the chatgpt-import-untitled branch October 20, 2026 15:55
phernandez added a commit that referenced this pull request Oct 23, 2026
The read cache imports fastapi.dependencies.utils.get_flat_dependant, which
FastAPI removed in 0.140.7. The >=0.136.1 floor let fresh installs resolve
0.140.13+, so bm status failed with "cannot import name 'get_flat_dependant'".
Pin the exact version CI tests. Adds the v0.24.1 changelog entry and applies a
ruff format rewrap left on main by #1790.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CoZ3jWnMJsyQsik4tPySk
Signed-off-by: phernandez <paul@basicmachines.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cost-review-2026-10 October 2026 COGS review: cost leaks, heavy tenants, and production error triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant