Skip to content

feat: support adding attachments in ramalama run and ramalama chat - #2627

Open
Christopher-Chianelli wants to merge 3 commits into
containers:mainfrom
Christopher-Chianelli:feat/2623
Open

feat: support adding attachments in ramalama run and ramalama chat#2627
Christopher-Chianelli wants to merge 3 commits into
containers:mainfrom
Christopher-Chianelli:feat/2623

Conversation

@Christopher-Chianelli

Copy link
Copy Markdown

Added a new repeatable --attach file argument to both ramalama run and ramalama chat. This argument attaches the given file to the initial request to the server. Additionally, in interactive mode, you can attach files to your next request using the /attach subcommand.

This is useful for a couple of things:

  • Analyzing log files: `ramalama run MODEL --attach server.log What errors occurred at 1pm?
  • Analyzing pictures on the command line: ramalama run MODEL --attach bird.jpg What kind of bird is this?
  • Doing an AI review before committing: ramalama run MODEL $(git diff --name-only | sed 's/^/--attach /') Do a review of these changes: $(git diff)

The existing file serialization options inside OpanAIChatAPIMessageBuilder and serialize_part were leveraged to implement this feature.

@coderabbitai

coderabbitai Bot commented Apr 12, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds file-attachment support: new repeatable --attach CLI option, an attachments arg field, chat shell /attach handling and validation, OpenAI provider serialization for attachments, and tests/docs to cover the end-to-end and unit behaviors.

Changes

Cohort / File(s) Summary
Docs
docs/ramalama-chat.1.md, docs/options/attach.md, docs/ramalama-run.1.md.in
Documented new --attach=file-path option and added placeholder in run manpage.
Argument Types
ramalama/arg_types.py
Added `attachments: List[PathStr]
CLI wiring
ramalama/cli.py, ramalama/plugins/runtimes/inference/common.py
Added repeatable --attach (type PathStr, action append) to chat and run command argument sets.
Chat shell
ramalama/chat.py
Initialize self.attachments, added _add_attachment() validation (readable & regular file), /attach command handling, /clear clears attachments, and attachments are loaded into conversation before API request.
Provider serialization
ramalama/chat_providers/openai.py
Added _handle_attachments() and updated message_to_completions_dict() to accept message.attachments; content can be text or a list of typed attachment dicts.
End-to-end tests
test/e2e/test_run.py
Added slow e2e test test_run_model_with_prompt_and_attachments exercising ramalama run --attach.
Unit & integration tests
test/unit/providers/test_openai_provider.py, test/unit/test_cli_args.py, test/unit/test_file_loader_integration.py, test/unit/...
Updated provider test to assert attachment serialization, expanded CLI-args tests to emit multiple --attach flags, and added/updated integration tests covering .txt, .jpg, and directory attachment behaviors.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as CLI/ArgParser
    participant Shell as RamaLamaShell
    participant History as ConversationHistory
    participant Provider as OpenAI Provider
    participant API as OpenAI API

    User->>CLI: ramalama chat --attach file.txt
    CLI->>Shell: args.attachments = [PathStr('file.txt')]
    User->>Shell: /attach file.jpg
    Shell->>Shell: _add_attachment(file.jpg) (isfile & readable)
    Shell->>Shell: self.attachments.append(file.jpg)
    User->>Shell: prompt about attachments
    Shell->>History: append user prompt
    Shell->>Shell: for each attachment: OpanAIChatAPIMessageBuilder.load(...)
    Shell->>History: append attachment message(s)
    Shell->>Shell: self.attachments.clear()
    Shell->>Provider: build_payload(conversation_history)
    Provider->>Provider: _handle_attachments() -> serialize parts
    Provider->>API: POST /chat/completions with mixed content (text + attachments)
    API-->>Provider: response
    Provider-->>Shell: assistant message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Suggested reviewers

  • jhjaggars
  • maxamillion
  • mikebonnet
  • engelmi

Poem

🐰 I found a file and gave it a tug,

Attachments now join every chat hug.
Text and images hop in a row,
Sent to the model — watch answers grow! 📎✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: support adding attachments in ramalama run and ramalama chat' accurately and concisely summarizes the main change: adding attachment support via a new --attach argument to both commands.
Description check ✅ Passed The description directly relates to the changeset, explaining the new --attach argument for both ramalama run and ramalama chat, including interactive /attach subcommand support and providing concrete use cases.

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

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

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.

@Christopher-Chianelli

Copy link
Copy Markdown
Author

Fixes #2623

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces the ability to attach files to chat and run commands via a new --attach CLI flag and a /attach command within the interactive chat session. The implementation includes updates to the OpenAI provider to support multi-part messages, documentation updates, and new E2E and unit tests. My feedback focuses on removing a redundant local import of perror, optimizing the OpanAIChatAPIMessageBuilder by instantiating it once in the constructor, and improving the robustness of file path parsing for the /attach command.

Comment thread ramalama/chat.py Outdated
Comment on lines +154 to +155
# Reload perror here so we can mock it in tests
from ramalama.common import perror

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.

medium

This local import is redundant because perror is already imported at the module level (line 33). Re-importing it inside __init__ to facilitate mocking is considered a bad practice. Instead, tests should patch ramalama.chat.perror directly. Furthermore, this local import only affects __init__, leaving other methods using the module-level reference, which leads to inconsistent behavior.

Comment thread ramalama/chat.py
self.initialize_mcp()

self.content: list[str] = []
self.attachments: list[PathStr] = []

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.

medium

Consider initializing the message builder once here and reusing it throughout the class instance, rather than instantiating it multiple times in different methods.

        self.attachments: list[PathStr] = []
        self.builder = OpanAIChatAPIMessageBuilder()

Comment thread ramalama/chat.py
# Handle attachments
if cmd.startswith("/attach "):
# capitalization matters for files, so use user_content
file = user_content.strip()[8:]

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.

medium

The extracted file path should be stripped to handle cases where multiple spaces are used between the command and the filename (e.g., /attach file.txt).

Suggested change
file = user_content.strip()[8:]
file = user_content.strip()[8:].strip()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Spaces are valid in the start of and end of files names.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

would the filename be in quotes if that were the case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Currently, no. Although that begs the question about if a custom parser should be written and what rules should be followed (ex: should multiple files be allowed to be attached in a single /attach subcommand? Should it follow bash/shell rules or something else? How to escape characters?). Attaching files from the command line doesn't have this problem since bash is the one handling the input, but for the /attach subcommand, we are inside an interactive session and are handling the raw input ourselves.

Comment thread ramalama/chat.py
Comment on lines +548 to +550
builder = OpanAIChatAPIMessageBuilder()
for attachment in self.attachments:
self.conversation_history.extend(builder.load(attachment))

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.

medium

Use the builder instance initialized in __init__ instead of creating a new one for every request.

Suggested change
builder = OpanAIChatAPIMessageBuilder()
for attachment in self.attachments:
self.conversation_history.extend(builder.load(attachment))
for attachment in self.attachments:
self.conversation_history.extend(self.builder.load(attachment))

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🧹 Nitpick comments (4)
test/unit/test_file_loader_integration.py (3)

45-47: Unused mock parameter mock_request.

The @patch('urllib.request.Request') decorator creates the mock_request parameter, but it's never used in this test. Either remove the patch if it's unnecessary, or document why it's needed (e.g., to prevent actual request construction).

🔧 Proposed fix: remove unused patch
     `@patch`('urllib.request.urlopen')
-    `@patch`('urllib.request.Request')
-    def test_chat_with_file_input_single_file_attachment(self, mock_request, mock_urlopen):
+    def test_chat_with_file_input_single_file_attachment(self, mock_urlopen):
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/test_file_loader_integration.py` around lines 45 - 47, The test
function test_chat_with_file_input_single_file_attachment currently receives an
unused mock parameter mock_request from the `@patch`('urllib.request.Request')
decorator; remove that unnecessary patch decorator (or replace it with a
dummy/ignored param if you must keep it) so the test signature no longer
includes mock_request, and ensure only `@patch`('urllib.request.urlopen') remains
(or, if preventing real Request construction is required, rename the parameter
to _mock_request and document why it is kept).

397-400: Unused mock parameter and incorrect docstring.

Same issues as above:

  1. mock_request is unused
  2. The docstring says "Test chat functionality with a single file input" but should describe image attachment testing
🔧 Proposed fix
     `@patch`('urllib.request.urlopen')
-    `@patch`('urllib.request.Request')
-    def test_chat_with_file_input_single_file_attachment(self, mock_request, mock_urlopen):
-        """Test chat functionality with a single file input."""
+    def test_chat_with_image_input_single_file_attachment(self, mock_urlopen):
+        """Test chat functionality with a single image file attachment."""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/test_file_loader_integration.py` around lines 397 - 400, The test
function test_chat_with_file_input_single_file_attachment has an unused mock
parameter mock_request and an incorrect docstring; remove the
`@patch`('urllib.request.Request') decorator and the mock_request parameter from
the function signature (leaving only mock_urlopen), and update the function
docstring to accurately describe that this is testing chat behavior with a
single image/file attachment rather than a generic "single file input".

94-98: Unused mock parameter and incorrect docstring.

Two issues here:

  1. mock_request is unused (same as above)
  2. The docstring says "Test chat functionality with a single file input" but this test is for directory upload error handling
🔧 Proposed fix
     `@patch`('urllib.request.urlopen')
-    `@patch`('urllib.request.Request')
     `@patch`('ramalama.common.perror')
-    def test_chat_with_directory_upload(self, mock_err, mock_request, mock_urlopen):
-        """Test chat functionality with a single file input."""
+    def test_chat_with_directory_upload(self, mock_err, mock_urlopen):
+        """Test chat gracefully handles directory attachments with an error message."""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/test_file_loader_integration.py` around lines 94 - 98, The
test_chat_with_directory_upload test has an unused patched parameter and a
misleading docstring; either remove the unused patch for urllib.request.Request
or use the mock_request parameter in the test body, and update the docstring to
describe directory upload error handling. Specifically, adjust the `@patch`
decorators or the function signature so mock_request is not injected if unused
(or reference mock_request in assertions), and change the docstring to something
like "Test directory upload error handling" to match the test's purpose
(referencing test_chat_with_directory_upload, mock_request, mock_urlopen,
mock_err).
ramalama/chat.py (1)

512-518: Inconsistent error output: print() vs perror().

Line 517 uses print() for the error message, but line 183 uses perror() for a similar validation error. Using perror() consistently would ensure error messages go to stderr.

🔧 Proposed fix
         # Handle attachments
         if cmd.startswith("/attach "):
             # capitalization matters for files, so use user_content
             file = user_content.strip()[8:]
             if not self._add_attachment(file):
-                print(f'The file {file} does not exist or cannot be accessed.')
+                perror(f'The file {file} does not exist or cannot be accessed.')
             return False
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ramalama/chat.py` around lines 512 - 518, The attachment handler uses
print(...) for error output which is inconsistent with the rest of the module;
replace the print call in the "/attach " branch so that when
self._add_attachment(file) returns False you call perror(...) (the same error
helper used elsewhere) with the same or matching message (e.g., "The file {file}
does not exist or cannot be accessed.") to send the error to stderr and keep
logging consistent; update the handler around cmd.startswith("/attach ") and the
file variable passed to self._add_attachment accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/ramalama-chat.1.md`:
- Around line 26-27: Update the second sentence in the docs entry so the
fragment becomes a complete sentence: replace "Can be specified multiple times
to attach multiple files." with "It can be specified multiple times to attach
multiple files." so the two-line description reads as two grammatically complete
sentences.

In `@docs/ramalama-run.1.md`:
- Around line 39-40: Replace the fragment "Can be specified multiple times to
attach multiple files." with a complete sentence for the option description that
follows "Attaches the given file to the initial request.", e.g. "It can be
specified multiple times to attach multiple files." Update the option
description text where the option's help string appears (the line containing
"Can be specified multiple times to attach multiple files.") so the two
sentences read as complete, grammatically correct sentences.

In `@ramalama/chat_providers/openai.py`:
- Around line 55-59: The current construction of content always prepends a text
block ({"type":"text","text":...}) even when message.text is empty; update the
logic in the block that builds content (the content variable and the branch that
calls _handle_attachments for message.attachments) so that you only add the text
part when message.text is truthy, otherwise start content as the attachments
list from _handle_attachments(message.attachments); apply the same change to the
analogous branch that handles content building elsewhere in this file so that
empty text parts are never included in the final returned dict
{**message.metadata, 'content': content, 'role': message.role}.

In `@test/e2e/test_run.py`:
- Around line 300-303: The test currently reopens a tempfile while it's still
open (tempfile.NamedTemporaryFile as temp_file then open(temp_file.name, "w")),
which fails on Windows; change the creation to use
tempfile.NamedTemporaryFile(suffix=".txt", delete=False) so the file can be
reopened, close temp_file before reopening (or create/write directly to
temp_file.name after closing), and ensure you explicitly remove the file
afterward (os.unlink(temp_file.name)) to avoid leaving temp artifacts; update
references to temp_file.name and run_cmd accordingly.

---

Nitpick comments:
In `@ramalama/chat.py`:
- Around line 512-518: The attachment handler uses print(...) for error output
which is inconsistent with the rest of the module; replace the print call in the
"/attach " branch so that when self._add_attachment(file) returns False you call
perror(...) (the same error helper used elsewhere) with the same or matching
message (e.g., "The file {file} does not exist or cannot be accessed.") to send
the error to stderr and keep logging consistent; update the handler around
cmd.startswith("/attach ") and the file variable passed to self._add_attachment
accordingly.

In `@test/unit/test_file_loader_integration.py`:
- Around line 45-47: The test function
test_chat_with_file_input_single_file_attachment currently receives an unused
mock parameter mock_request from the `@patch`('urllib.request.Request') decorator;
remove that unnecessary patch decorator (or replace it with a dummy/ignored
param if you must keep it) so the test signature no longer includes
mock_request, and ensure only `@patch`('urllib.request.urlopen') remains (or, if
preventing real Request construction is required, rename the parameter to
_mock_request and document why it is kept).
- Around line 397-400: The test function
test_chat_with_file_input_single_file_attachment has an unused mock parameter
mock_request and an incorrect docstring; remove the
`@patch`('urllib.request.Request') decorator and the mock_request parameter from
the function signature (leaving only mock_urlopen), and update the function
docstring to accurately describe that this is testing chat behavior with a
single image/file attachment rather than a generic "single file input".
- Around line 94-98: The test_chat_with_directory_upload test has an unused
patched parameter and a misleading docstring; either remove the unused patch for
urllib.request.Request or use the mock_request parameter in the test body, and
update the docstring to describe directory upload error handling. Specifically,
adjust the `@patch` decorators or the function signature so mock_request is not
injected if unused (or reference mock_request in assertions), and change the
docstring to something like "Test directory upload error handling" to match the
test's purpose (referencing test_chat_with_directory_upload, mock_request,
mock_urlopen, mock_err).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5599ecca-4d95-426d-a068-868d73cd7d1a

📥 Commits

Reviewing files that changed from the base of the PR and between 9c499f1 and 0ecdc8b.

📒 Files selected for processing (11)
  • docs/ramalama-chat.1.md
  • docs/ramalama-run.1.md
  • ramalama/arg_types.py
  • ramalama/chat.py
  • ramalama/chat_providers/openai.py
  • ramalama/cli.py
  • ramalama/plugins/runtimes/inference/common.py
  • test/e2e/test_run.py
  • test/unit/providers/test_openai_provider.py
  • test/unit/test_cli_args.py
  • test/unit/test_file_loader_integration.py

Comment thread docs/ramalama-chat.1.md
Comment on lines +26 to +27
Attaches the given file to the initial request.
Can be specified multiple times to attach multiple files.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tighten wording for grammatical completeness.

Line 27 is a fragment. Consider: “It can be specified multiple times to attach multiple files.”

🧰 Tools
🪛 LanguageTool

[style] ~26-~26: To form a complete sentence, be sure to include a subject.
Context: ... the given file to the initial request. Can be specified multiple times to attach m...

(MISSING_IT_THERE)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-chat.1.md` around lines 26 - 27, Update the second sentence in
the docs entry so the fragment becomes a complete sentence: replace "Can be
specified multiple times to attach multiple files." with "It can be specified
multiple times to attach multiple files." so the two-line description reads as
two grammatically complete sentences.

Comment thread docs/ramalama-run.1.md Outdated
Comment on lines +39 to +40
Attaches the given file to the initial request.
Can be specified multiple times to attach multiple files.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use a complete sentence in the option description.

Line 40 reads as a fragment. Suggest: “It can be specified multiple times to attach multiple files.”

🧰 Tools
🪛 LanguageTool

[style] ~39-~39: To form a complete sentence, be sure to include a subject.
Context: ... the given file to the initial request. Can be specified multiple times to attach m...

(MISSING_IT_THERE)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-run.1.md` around lines 39 - 40, Replace the fragment "Can be
specified multiple times to attach multiple files." with a complete sentence for
the option description that follows "Attaches the given file to the initial
request.", e.g. "It can be specified multiple times to attach multiple files."
Update the option description text where the option's help string appears (the
line containing "Can be specified multiple times to attach multiple files.") so
the two sentences read as complete, grammatically correct sentences.

Comment thread ramalama/chat_providers/openai.py
Comment thread test/e2e/test_run.py Outdated
mock_urlopen.return_value = mock_response

with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp_file:
with open(tmp_file.name, "wb") as f:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

again why open the same file twice?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

To ensure the contents is written to dish before it is read. Admittedly I forgot NamedTemporaryFile is a file-like itself and not a data descriptor. You could use flush() to get the same effect, although I do like the clean seperation of when file writes are done gotten by using a with.

@olliewalsh olliewalsh Apr 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does that work on windows? Generally can't open the same file twice but I think it works from within the same process.

IIRC this is already done elsewhere, something along the lines of:

from ramalama.compat import NamedTemporaryFile

with NamedTemporaryFile(delete_on_close=False) as tmp_file:
    tmp_file.write("foobar")
    tmp_file.close()
    # Do stuff that reads the file

(the compat version is necessary to work on python 3.10 with does not have delete_on_close)

@rhatdan

rhatdan commented Apr 16, 2026

Copy link
Copy Markdown
Member

This PR requires a rebase.

@coderabbitai coderabbitai 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.

Caution

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

⚠️ Outside diff range comments (2)
docs/ramalama-chat.1.md (1)

75-97: ⚠️ Potential issue | 🟡 Minor

Document /attach in interactive commands for ramalama chat.

The new option is documented, but the interactive /attach command is not listed, which can hide core functionality from users.

📘 Suggested doc addition
 #### **/clear**
 Clear the conversation history without exiting the chat session. This resets the context
 and allows starting a fresh conversation without restarting the container or connection.
 A confirmation message will be displayed when the history is cleared.
 
+#### **/attach** *file-path*
+Attach a file to the next request. This command can be used multiple times before sending a prompt.
+
 #### **/bye**, **exit**
 Exit the chat session and close the connection.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-chat.1.md` around lines 75 - 97, The interactive command list
under INTERACTIVE COMMANDS for ramalama chat is missing documentation for the
/attach command; add an entry for "/attach" under INTERACTIVE COMMANDS that
shows the command syntax (e.g., /attach <path|url>), a brief description of what
it does (attach/upload a file to the current conversation/context), note
case-insensitivity and any prerequisites or flags required to enable it, and
include a short example of usage so users can discover the feature.
docs/ramalama-run.1.md (1)

286-307: ⚠️ Potential issue | 🟡 Minor

Document /attach in interactive commands for ramalama run.

This man page documents --attach, but the interactive /attach command is not listed in ## INTERACTIVE COMMANDS, which leaves the new interactive workflow undiscoverable.

📘 Suggested doc addition
 #### **/clear**
 Clear the conversation history without exiting the chat session. This resets the context
 and allows starting a fresh conversation without restarting the container or connection.
 A confirmation message will be displayed when the history is cleared.
 
+#### **/attach** *file-path*
+Attach a file to the next request. This command can be used multiple times before sending a prompt.
+
 #### **/bye**, **exit**
 Exit the chat session and close the connection.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-run.1.md` around lines 286 - 307, Add a new interactive command
entry for "/attach" under the INTERACTIVE COMMANDS section to document the
interactive attach workflow missing from the man page: describe the command
syntax (e.g., "/attach [TARGET]"), what it does (attach the running session to a
container/session started with --attach), behavior/limitations
(case-insensitivity, required flags like --attach or --mcp if applicable), and
the expected response or confirmation shown to the user; reference the existing
"--attach" option in the description and ensure the entry matches the style of
other commands like "/tool" and "/clear".
♻️ Duplicate comments (2)
docs/ramalama-chat.1.md (1)

26-27: ⚠️ Potential issue | 🟡 Minor

Use a complete sentence in the option description.

Please make the second sentence grammatically complete.

✏️ Suggested doc fix
-Can be specified multiple times to attach multiple files.
+It can be specified multiple times to attach multiple files.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-chat.1.md` around lines 26 - 27, The second sentence "Can be
specified multiple times to attach multiple files." is a sentence fragment;
update the option description containing "Attaches the given file to the initial
request." and the following fragment so the second sentence is grammatically
complete — e.g., change it to "It can be specified multiple times to attach
multiple files." or merge into one sentence "Attaches the given file to the
initial request and can be specified multiple times to attach multiple files."
Make the edit where those exact phrases appear.
docs/ramalama-run.1.md (1)

39-40: ⚠️ Potential issue | 🟡 Minor

Use a complete sentence in the option description.

Please change the fragment to a full sentence.

✏️ Suggested doc fix
-Can be specified multiple times to attach multiple files.
+It can be specified multiple times to attach multiple files.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-run.1.md` around lines 39 - 40, Replace the fragment "Can be
specified multiple times to attach multiple files." with a full sentence such as
"This option can be specified multiple times to attach multiple files." so the
option description reads as complete sentences (e.g., keep "Attaches the given
file to the initial request." and update the following line to the suggested
full sentence).
🧹 Nitpick comments (1)
test/unit/test_cli_args.py (1)

144-149: Add value-level assertions for attachments round-trip.

Current assertions only check attribute presence, so regressions in attachment parsing can still pass.

✅ Suggested test hardening
 def test_chat_endpoint(chatargs):
     cli_args = args_to_cli_args(chatargs, 'chat', special_cases)
     args = parser.parse_args(cli_args)
 
     for field in ChatSubArgs.__dataclass_fields__:
         assert hasattr(args, field), f"Missing attribute: {field}"
+
+    if chatargs.attachments:
+        assert args.attachments == chatargs.attachments
+    else:
+        assert args.attachments is None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/test_cli_args.py` around lines 144 - 149, The test_chat_endpoint
currently only asserts attribute presence; add a concrete value-level assertion
that the attachments round-trip is preserved by asserting args.attachments
equals the expected value from the chatargs fixture (or the normalized
representation produced by args_to_cli_args), e.g. after computing args =
parser.parse_args(cli_args) add an assertion comparing args.attachments to
chatargs.attachments (or to the CLI-serialized form if normalization occurs) so
regressions in attachment parsing fail; update test_chat_endpoint and use the
existing variables/functions (test_chat_endpoint, chatargs, args_to_cli_args,
parser.parse_args, args, ChatSubArgs) to locate and implement the assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@docs/ramalama-chat.1.md`:
- Around line 75-97: The interactive command list under INTERACTIVE COMMANDS for
ramalama chat is missing documentation for the /attach command; add an entry for
"/attach" under INTERACTIVE COMMANDS that shows the command syntax (e.g.,
/attach <path|url>), a brief description of what it does (attach/upload a file
to the current conversation/context), note case-insensitivity and any
prerequisites or flags required to enable it, and include a short example of
usage so users can discover the feature.

In `@docs/ramalama-run.1.md`:
- Around line 286-307: Add a new interactive command entry for "/attach" under
the INTERACTIVE COMMANDS section to document the interactive attach workflow
missing from the man page: describe the command syntax (e.g., "/attach
[TARGET]"), what it does (attach the running session to a container/session
started with --attach), behavior/limitations (case-insensitivity, required flags
like --attach or --mcp if applicable), and the expected response or confirmation
shown to the user; reference the existing "--attach" option in the description
and ensure the entry matches the style of other commands like "/tool" and
"/clear".

---

Duplicate comments:
In `@docs/ramalama-chat.1.md`:
- Around line 26-27: The second sentence "Can be specified multiple times to
attach multiple files." is a sentence fragment; update the option description
containing "Attaches the given file to the initial request." and the following
fragment so the second sentence is grammatically complete — e.g., change it to
"It can be specified multiple times to attach multiple files." or merge into one
sentence "Attaches the given file to the initial request and can be specified
multiple times to attach multiple files." Make the edit where those exact
phrases appear.

In `@docs/ramalama-run.1.md`:
- Around line 39-40: Replace the fragment "Can be specified multiple times to
attach multiple files." with a full sentence such as "This option can be
specified multiple times to attach multiple files." so the option description
reads as complete sentences (e.g., keep "Attaches the given file to the initial
request." and update the following line to the suggested full sentence).

---

Nitpick comments:
In `@test/unit/test_cli_args.py`:
- Around line 144-149: The test_chat_endpoint currently only asserts attribute
presence; add a concrete value-level assertion that the attachments round-trip
is preserved by asserting args.attachments equals the expected value from the
chatargs fixture (or the normalized representation produced by
args_to_cli_args), e.g. after computing args = parser.parse_args(cli_args) add
an assertion comparing args.attachments to chatargs.attachments (or to the
CLI-serialized form if normalization occurs) so regressions in attachment
parsing fail; update test_chat_endpoint and use the existing variables/functions
(test_chat_endpoint, chatargs, args_to_cli_args, parser.parse_args, args,
ChatSubArgs) to locate and implement the assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e5560d19-5038-41d0-bdbd-466eface083b

📥 Commits

Reviewing files that changed from the base of the PR and between 0ecdc8b and 8aade94.

📒 Files selected for processing (11)
  • docs/ramalama-chat.1.md
  • docs/ramalama-run.1.md
  • ramalama/arg_types.py
  • ramalama/chat.py
  • ramalama/chat_providers/openai.py
  • ramalama/cli.py
  • ramalama/plugins/runtimes/inference/common.py
  • test/e2e/test_run.py
  • test/unit/providers/test_openai_provider.py
  • test/unit/test_cli_args.py
  • test/unit/test_file_loader_integration.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • ramalama/arg_types.py
  • ramalama/plugins/runtimes/inference/common.py
  • test/unit/providers/test_openai_provider.py
  • test/e2e/test_run.py
  • ramalama/chat_providers/openai.py
  • test/unit/test_file_loader_integration.py
  • ramalama/chat.py

@Christopher-Chianelli

Copy link
Copy Markdown
Author

Question: is OpanAIChatAPIMessageBuilder referring to an actual API called OpanAIChatAPI or is it a typo of OpenAIChatAPIMessageBuilder? I am tempted to rename it although I don't know if it considered external API or not.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
test/unit/test_file_loader_integration.py (1)

27-30: ⚠️ Potential issue | 🟠 Major

Use the repo’s temp-file compatibility pattern consistently in these blocks.

These tests still reopen the same temp file path while the original handle is open, without delete_on_close=False. This can be flaky across Python/OS combinations (notably Windows).

Suggested pattern to apply in these blocks
-with NamedTemporaryFile(suffix=".txt") as tmp_file:
-    with open(tmp_file.name, "w") as f:
-        f.write("This is test content for chat input")
+with NamedTemporaryFile(suffix=".txt", delete_on_close=False) as tmp_file:
+    tmp_file.write(b"This is test content for chat input")
+    tmp_file.close()

Please verify all occurrences with:

#!/bin/bash
# Find NamedTemporaryFile blocks and check for reopen-by-path patterns.
rg -n "with NamedTemporaryFile\\(" test/unit/test_file_loader_integration.py -A6 -B1
rg -n "with open\\(tmp_file\\.name" test/unit/test_file_loader_integration.py -A2 -B1

Expected result: every case requiring path-based reuse should use delete_on_close=False and close/write via tmp_file before reading via path.
Based on learnings: "In this repo’s Python 3.10+ compatibility layer, always import NamedTemporaryFile from ramalama.compat ... pass delete_on_close=False when the file must remain accessible by path within the with block."

Also applies to: 55-58, 209-211, 236-239, 323-325, 344-346

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/test_file_loader_integration.py` around lines 27 - 30, The test
reopens the same temp file path while the original NamedTemporaryFile handle is
still open (using with NamedTemporaryFile(...) as tmp_file and then
open(tmp_file.name,...)), which is flaky on Windows; update each occurrence
(e.g., the tmp_file/tmp_file.name blocks at lines referenced) to use the repo
pattern: import NamedTemporaryFile from ramalama.compat, create it with
delete_on_close=False, write/flush/close via the tmp_file handle before
reopening by path, and ensure any reopen uses tmp_file.name only after tmp_file
is closed so the file is reliably accessible by path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ramalama/chat.py`:
- Around line 546-550: The attachment loading can raise and leave
self.conversation_history partially mutated; to fix, instantiate
OpanAIChatAPIMessageBuilder and for each attachment call builder.load inside a
try/except, collecting loaded messages into a temporary list (e.g., temp_msgs)
and only extend self.conversation_history with temp_msgs on success; on
exception log the error (or record it) and skip that attachment, and ensure
self.attachments is cleared after processing (use finally or clear at end) so a
failed load doesn't abort default() leaving inconsistent state; reference
OpanAIChatAPIMessageBuilder, builder.load, self.conversation_history, and
self.attachments.

---

Duplicate comments:
In `@test/unit/test_file_loader_integration.py`:
- Around line 27-30: The test reopens the same temp file path while the original
NamedTemporaryFile handle is still open (using with NamedTemporaryFile(...) as
tmp_file and then open(tmp_file.name,...)), which is flaky on Windows; update
each occurrence (e.g., the tmp_file/tmp_file.name blocks at lines referenced) to
use the repo pattern: import NamedTemporaryFile from ramalama.compat, create it
with delete_on_close=False, write/flush/close via the tmp_file handle before
reopening by path, and ensure any reopen uses tmp_file.name only after tmp_file
is closed so the file is reliably accessible by path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 58ecf316-960d-487d-b2ba-8ef75efaaf42

📥 Commits

Reviewing files that changed from the base of the PR and between 8aade94 and e5997b2.

📒 Files selected for processing (4)
  • ramalama/chat.py
  • ramalama/chat_providers/openai.py
  • test/e2e/test_run.py
  • test/unit/test_file_loader_integration.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/e2e/test_run.py
  • ramalama/chat_providers/openai.py

Comment thread ramalama/chat.py
Comment on lines +546 to +550
if self.attachments:
builder = OpanAIChatAPIMessageBuilder()
for attachment in self.attachments:
self.conversation_history.extend(builder.load(attachment))
self.attachments = []

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle attachment load failures to avoid request-time crashes.

At Line [549], builder.load(attachment) can raise (e.g., file deleted after /attach or between startup and first prompt). Right now that aborts default() and can leave partially-mutated history.

Suggested hardening
         if self.attachments:
             builder = OpanAIChatAPIMessageBuilder()
-            for attachment in self.attachments:
-                self.conversation_history.extend(builder.load(attachment))
-            self.attachments = []
+            loaded_messages: list[ChatMessageType] = []
+            for attachment in self.attachments:
+                try:
+                    loaded_messages.extend(builder.load(attachment))
+                except (OSError, ValueError) as e:
+                    perror(f"Failed to load attachment {attachment}: {e}")
+            self.conversation_history.extend(loaded_messages)
+            self.attachments = []
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ramalama/chat.py` around lines 546 - 550, The attachment loading can raise
and leave self.conversation_history partially mutated; to fix, instantiate
OpanAIChatAPIMessageBuilder and for each attachment call builder.load inside a
try/except, collecting loaded messages into a temporary list (e.g., temp_msgs)
and only extend self.conversation_history with temp_msgs on success; on
exception log the error (or record it) and skip that attachment, and ensure
self.attachments is cleared after processing (use finally or clear at end) so a
failed load doesn't abort default() leaving inconsistent state; reference
OpanAIChatAPIMessageBuilder, builder.load, self.conversation_history, and
self.attachments.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/ramalama-chat.1.md`:
- Around line 25-27: Update the --attach option documentation to mention the
interactive /attach command as an alternative entry point: in the block
describing **--attach**=**file-path** (and its "Can be specified multiple times"
note) add a short sentence like "Files can also be attached during an
interactive chat session using the /attach command" or a cross-reference to the
interactive command section so users know both the initial-request flag and the
interactive `/attach` path are available.

In `@test/unit/test_file_loader_integration.py`:
- Around line 27-29: Change each NamedTemporaryFile usage that reopens
tmp_file.name to create the temp file with delete=False and explicitly close it
before calling open(tmp_file.name, ...) — e.g., replace
NamedTemporaryFile(suffix=".txt") as tmp_file with
NamedTemporaryFile(suffix=".txt", delete=False) as tmp_file: tmp_path =
tmp_file.name; tmp_file.close(); then use open(tmp_path, "w") to write and later
remove the file when done. Apply this pattern to the blocks that reference
tmp_file.name (the occurrences around the tmp_file variable at lines showing
tmp_file usage).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bdab4cd2-3fbe-4b06-8044-e8134ab886fb

📥 Commits

Reviewing files that changed from the base of the PR and between e5997b2 and 07b922f.

📒 Files selected for processing (10)
  • docs/ramalama-chat.1.md
  • ramalama/arg_types.py
  • ramalama/chat.py
  • ramalama/chat_providers/openai.py
  • ramalama/cli.py
  • ramalama/plugins/runtimes/inference/common.py
  • test/e2e/test_run.py
  • test/unit/providers/test_openai_provider.py
  • test/unit/test_cli_args.py
  • test/unit/test_file_loader_integration.py
✅ Files skipped from review due to trivial changes (1)
  • ramalama/plugins/runtimes/inference/common.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • ramalama/arg_types.py
  • test/unit/providers/test_openai_provider.py
  • test/unit/test_cli_args.py
  • ramalama/chat.py
  • test/e2e/test_run.py

Comment thread docs/ramalama-chat.1.md
Comment on lines +25 to +27
#### **--attach**=**file-path**
Attaches the given file to the initial request.
Can be specified multiple times to attach multiple files.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document the interactive /attach path in this option block.

The feature includes attaching files during interactive chat, but this section only describes initial-request behavior. Please add a short note here (or cross-reference the interactive command section) so users discover both entry points.

📝 Suggested doc tweak
 #### **--attach**=**file-path**
 Attaches the given file to the initial request.
 Can be specified multiple times to attach multiple files.
+In interactive mode, use `/attach <file-path>` to attach files to the next request.
🧰 Tools
🪛 LanguageTool

[style] ~26-~26: To form a complete sentence, be sure to include a subject.
Context: ... the given file to the initial request. Can be specified multiple times to attach m...

(MISSING_IT_THERE)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/ramalama-chat.1.md` around lines 25 - 27, Update the --attach option
documentation to mention the interactive /attach command as an alternative entry
point: in the block describing **--attach**=**file-path** (and its "Can be
specified multiple times" note) add a short sentence like "Files can also be
attached during an interactive chat session using the /attach command" or a
cross-reference to the interactive command section so users know both the
initial-request flag and the interactive `/attach` path are available.

Comment thread test/unit/test_file_loader_integration.py
@Christopher-Chianelli

Copy link
Copy Markdown
Author

Question: why doesn't ramalama chat docs use the manfile.1.md.in system?

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (2)
docs/options/attach.md (2)

7-7: Optional: Add subject for grammatical completeness.

The static analysis tool suggests adding a subject (e.g., "It can be specified...") for grammatical completeness, though the current phrasing is acceptable in technical documentation.

✍️ Optional style improvement
-Can be specified multiple times to attach multiple files.
+It can be specified multiple times to attach multiple files.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/options/attach.md` at line 7, Replace the sentence "Can be specified
multiple times to attach multiple files." with a grammatically complete version
such as "It can be specified multiple times to attach multiple files." — update
the phrase in the docs/attach documentation where that exact sentence appears to
include the subject "It" for completeness.

6-7: Consider mentioning the /attach interactive subcommand.

The documentation accurately describes the --attach CLI option, but the PR description states: "In interactive mode, files can be attached to the next request using the /attach subcommand." Consider adding a note about this interactive feature for completeness, as users might benefit from knowing both methods.

📝 Suggested enhancement to mention interactive mode
 Attaches the given file to the initial request.
-Can be specified multiple times to attach multiple files.
+Can be specified multiple times to attach multiple files.
+In interactive mode, use the `/attach` subcommand to attach files to subsequent requests.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/options/attach.md` around lines 6 - 7, The docs currently explain the
CLI --attach option but omit the interactive-mode counterpart; update the attach
documentation to briefly mention the interactive /attach subcommand (referencing
the CLI flag --attach and the interactive command /attach) and add one short
sentence explaining that in interactive sessions files can be attached to the
next request using /attach, including any usage example or note that it can be
invoked multiple times similar to --attach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/options/attach.md`:
- Line 7: Replace the sentence "Can be specified multiple times to attach
multiple files." with a grammatically complete version such as "It can be
specified multiple times to attach multiple files." — update the phrase in the
docs/attach documentation where that exact sentence appears to include the
subject "It" for completeness.
- Around line 6-7: The docs currently explain the CLI --attach option but omit
the interactive-mode counterpart; update the attach documentation to briefly
mention the interactive /attach subcommand (referencing the CLI flag --attach
and the interactive command /attach) and add one short sentence explaining that
in interactive sessions files can be attached to the next request using /attach,
including any usage example or note that it can be invoked multiple times
similar to --attach.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6615a036-8e8d-430e-b3fb-67bb6002879a

📥 Commits

Reviewing files that changed from the base of the PR and between 07b922f and 703d8a4.

📒 Files selected for processing (2)
  • docs/options/attach.md
  • docs/ramalama-run.1.md.in
✅ Files skipped from review due to trivial changes (1)
  • docs/ramalama-run.1.md.in

Added a new repeatable `--attach file` argument to both `ramalama run`
and `ramalama chat`. This argument attaches the given file to the
initial request to the server. Additionally, in interactive mode,
you can attach files to your next request using the `/attach`
subcommand.

This is useful for a couple of things:

- Analyzing log files: `ramalama run MODEL --attach server.log What errors occurred at 1pm?
- Analyzing pictures on the command line: `ramalama run MODEL --attach bird.jpg What kind of bird is this?`
- Doing an AI review before committing: `ramalama run MODEL $(git diff --name-only | sed 's/^/--attach /') Do a review of these changes: $(git diff)`

The existing file serialization options inside OpanAIChatAPIMessageBuilder
and serialize_part were leveraged to implement this feature.

Signed-off-by: Christopher Chianelli <christopher@timefold.ai>
Signed-off-by: Christopher Chianelli <christopher@timefold.ai>
Signed-off-by: Christopher Chianelli <christopher@timefold.ai>
@rhatdan

rhatdan commented Apr 29, 2026

Copy link
Copy Markdown
Member

We only use the .in format, if a man page is using a shared option with other man pages. If you see an option that is in the ramana-chat man page, then we should move it to the .in format.

@github-actions

Copy link
Copy Markdown

A friendly reminder that this PR had no activity for 30 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants