Skip to content

fix(chat): pass the chat user instructions to the Context Agent - #709

Merged
marcelklehr merged 2 commits into
nextcloud:mainfrom
vyacheslavhulyaev-glitch:fix/338-agent-user-instructions
Oct 22, 2026
Merged

marcelklehr merged 2 commits into
nextcloud:mainfrom
vyacheslavhulyaev-glitch:fix/338-agent-user-instructions

Conversation

@vyacheslavhulyaev-glitch

@vyacheslavhulyaev-glitch vyacheslavhulyaev-glitch commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #338

The "Chat User Instructions for Chat Completions" admin setting was only used for classic chat. With the Context Agent the instructions were never sent, so agentic chat ignored them.

Requires nextcloud/context_agent#285, which adds the optional user_instructions input and appends it to the agent's own system prompt (it does not replace it, see @janepie's comment in #338).

Changes

  • ChatService: the classic, multimodal and audio agency tasks now get the session's system message as user_instructions, but only if the task type declares that optional input. That's the same check as for memories, so older Context Agent versions keep working unchanged. Reading the system message was moved into a helper shared with classic chat.
  • ContextAgentAudioInteractionProvider: declares the input as well and forwards it to the ContextAgentInteraction subtask.
  • Admin settings: when the Context Agent is available, the hint says the instructions are also added to the agent's instructions.
  • New ChatServiceAgencyTest: instructions are sent / not sent when the agent does not support them / not sent when the session has no system message.

Testing

Local Nextcloud 35.0.2 with Context Agent from nextcloud/context_agent#285 and OpenAI gpt-4.1-mini:

  • Admin setting: "Always answer like a pirate. Your name is Captain Cloud.", new chat, "What is your name?"
    • before: "I am your AI assistant. How can I help you today?"
    • after: "Arrr, I be Captain Cloud, yer trusty pirate AI assistant sailin' the digital seas…"
  • ChatServiceAgencyTest: 3/3 pass, and the first test fails without the fix
  • Full unit suite: all pass except AgentSkillsServiceTest::testExtractFrontmatterValid, which also fails on main locally (no files_external tables in my dev instance)
  • cs:check clean, Psalm no errors, frontend builds

Notes / questions

  • Sessions keep the instructions that were set when they were created, same as classic chat.
  • Assignment runs also go through scheduleAgencyTask, so they get the instructions too. Is that wanted?
  • The setting is reused rather than adding a separate "agent instructions" setting. The default text does not conflict with the agent prompt, but happy to split it if you prefer.

The "Chat User Instructions for Chat Completions" admin setting was only
used for classic chat. With the Context Agent the instructions were
never sent, so agentic chat ignored them.

Pass the session's system message as the optional `user_instructions`
input to the classic, multimodal and audio agency tasks, if the
provider declares it (Context Agent appends it to its own system
prompt). Older Context Agent versions keep working as before.

Fixes nextcloud#338

Signed-off-by: Viacheslav Huliaiev <vyacheslavhulyaev@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5f836c37-8da1-4100-ad58-6d02f56f61df
📥 Commits

Reviewing files that changed from the base of the PR and between fea8c03 and 3f84347.

📒 Files selected for processing: 4
  • lib/Service/ChatService.php
  • lib/TaskProcessing/ContextAgentAudioInteractionProvider.php
  • src/components/AdminSettings.vue
  • tests/unit/Service/ChatServiceAgencyTest.php
🚧 Files skipped from review as they are similar to previous changes: 1
  • src/components/AdminSettings.vue

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

ChatService retrieves the session system prompt through a shared helper. It adds non-empty user instructions to standard, multimodal, and audio agency tasks when their optional inputs support them. Assignment generation omits these instructions. The audio interaction provider declares and forwards the optional input when supported. The settings view conditionally displays Context Agent guidance. Unit tests cover supported and unsupported inputs, missing or unreadable system messages, and assignment runs.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 3f843

The instruction handoff appears to work as intended, with no identified issue requiring resolution before merge.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 3 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description check Passed The description clearly explains that the pull request forwards chat user instructions to supported Context Agent tasks and includes testing details.
Title check Passed The title clearly and concisely summarizes the main change: passing chat user instructions to the Context Agent.
Linked Issues check Passed Issue #338 requires the configured Chat User Instructions to reach Context Agent requests. ChatService passes the session system message as optional user_instructions for supported chat, multimoda…
Out of Scope Changes check Passed The changed files support #338. They implement instruction propagation, preserve compatibility with older Context Agent versions, update the related admin hint, and add focused tests. No unrelated cha…
Full details: Linked Issues check

Explanation

Issue #338 requires the configured Chat User Instructions to reach Context Agent requests. ChatService passes the session system message as optional user_instructions for supported chat, multimodal, and audio agency tasks. Assignment runs omit the input. The audio provider forwards supported instructions and requests speech output. ChatServiceAgencyTest covers supported, unsupported, missing, unreadable, and assignment cases.

Full details: Out of Scope Changes check

Explanation

The changed files support #338. They implement instruction propagation, preserve compatibility with older Context Agent versions, update the related admin hint, and add focused tests. No unrelated change is demonstrated.

Full details: Docstring Coverage

Explanation

Docstring coverage is 36.84% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 3 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 PHPStan (2.3.0)

PHPStan reported 1 non-file analysis error(s); analysis is incomplete

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.

@marcelklehr

Copy link
Copy Markdown
Member

Hey @vyacheslavhulyaev-glitch
Thank you for implementing this!
I think as it is, this sends the default system prompt to context_agent even, when the admin hasn't set anything and thus changes behavior of the system. Not sure if that is desireable, defering to @julien-nc on that. Especially for assignments, Assignment runs go through scheduleAgencyTask, so they will be told to "ask for clarification" when no user is there to answer. Additionally, audio replies are now pushed toward markdown, and ContextAgentAudioInteractionProvider sends that text to TTS, which might read out the formatting, haven't tested this.

if ($userInstructions !== '') {
$taskInput['user_instructions'] = $userInstructions;
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a nice unintrusive method 👍

Comment thread lib/Service/ChatService.php Outdated
if (!isset($this->taskProcessingManager->getAvailableTaskTypes()[$taskTypeId]['optionalInputShape']['user_instructions'])) {
return;
}
$userInstructions = $this->getSessionSystemPrompt($sessionId);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We might want to catch InternalException here

@julien-nc

Copy link
Copy Markdown
Member

@vyacheslavhulyaev-glitch Thanks a lot, very nice PR.

I think as it is, this sends the default system prompt to context_agent even, when the admin hasn't set anything and thus changes behavior of the system. Not sure if that is desireable, defering to @julien-nc on that

@marcelklehr I think it's fine to send the default system prompt. The previous behaviour was kind of unexpected, now it's consistent between classic and agentic chat.

@vyacheslavhulyaev-glitch Wdyt?

Especially for assignments, Assignment runs go through scheduleAgencyTask, so they will be told to "ask for clarification" when no user is there to answer.

Does it make sense to prevent injecting this admin-defined system prompt in Assignment runs? There's a sort of safeguard for that in context_agent: the admin-defined system prompt is prefixed with The administrator of this Nextcloud instance has provided the following additional instructions. Follow them, unless they conflict with the instructions above:. So if the hardcoded system prompt of assignments explicitly mentions to not ask for clarifications, the model will ignore the ask for clarification part of the admin-defined system prompt.

@marcelklehr @vyacheslavhulyaev-glitch wdyt?

Additionally, audio replies are now pushed toward markdown, and ContextAgentAudioInteractionProvider sends that text to TTS, which might read out the formatting, haven't tested this.

Ouch, nice catch. Can we also try to prevent markdown formatting in the main system prompt in this case so the admin-defined part about that would be ignored?

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

thanks for the PR!

Comment on lines +139 to +145
if (isset($input['memories'], $this->taskProcessingManager->getAvailableTaskTypes()[ContextAgentAudioInteraction::ID]['optionalInputShape']['memories'])) {
$contextAgentTaskInput['memories'] = $input['memories'];
}
/** @psalm-suppress UndefinedClass */
if (isset($input['user_instructions'], $this->taskProcessingManager->getAvailableTaskTypes()[ContextAgentInteraction::ID]['optionalInputShape']['user_instructions'])) {
$contextAgentTaskInput['user_instructions'] = $input['user_instructions'];
}

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.

it might be efficient to get the task types only once from the taskprocessing manager, even though the task types are cached since they are fetched from the distributed cache.
https://github.com/nextcloud/server/blob/fecc0bd985996b31f760369075fec09ee73e4b69/lib/private/TaskProcessing/Manager.php#L950

Comment thread src/components/AdminSettings.vue Outdated
{{ t('assistant', '"{user}" is a placeholder for the user\'s display name.') }}
<template v-if="state.context_agent_available">
<br>
{{ t('assistant', 'When chatting through the Context Agent, these instructions are added to the agent\'s own instructions (requires a Context Agent version that supports it).') }}

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.

could be worth mentioning the context agent version since it would be available. It will be visible to the admin only so should be fine.
I think the next version would be v2.10.0
cc @marcelklehr

Comment thread lib/Service/ChatService.php Outdated
Comment on lines +1011 to +1016
@@ -983,6 +1012,8 @@ private function scheduleAgencyAudioTask(
$taskInput['memories'] = $this->sessionSummaryService->getMemories($userId);
}
/** @psalm-suppress UndefinedClass */
$this->addAgencyUserInstructions($taskInput, \OCP\TaskProcessing\TaskTypes\ContextAgentAudioInteraction::ID, $sessionId);
/** @psalm-suppress UndefinedClass */

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.

nit: the same applies here and in scheduleAgencyTask too since addAgencyUserInstructions() calls gets the task types internally but it could be fine for code readability.
wdyt?

@kyteinsky

Copy link
Copy Markdown
Contributor

Additionally, audio replies are now pushed toward markdown, and ContextAgentAudioInteractionProvider sends that text to TTS, which might read out the formatting, haven't tested this.

Ouch, nice catch. Can we also try to prevent markdown formatting in the main system prompt in this case so the admin-defined part about that would be ignored?

we could try to remove this line from the context agent's prompt: Follow them, unless they conflict with the instructions above: since the admin should be able to modify the agent, and the instructions are poured into the system prompt as opposed to a user message so they have the same "rank" anyway.

in addition, Assistant could append the user instructions with something specifying that it's an audio chat so output text accordingly in the scheduleAgencyAudioTask() call.

just my two cents.

- Do not pass the chat user instructions to assignment runs, they run
  unattended
- Ask the Context Agent for plain text in audio interactions
  (output_mode=speech), the reply goes to text-to-speech
- Run the agent without instructions if they cannot be read
- Fetch the available task types only once
- Mention the required Context Agent version in the admin hint

Signed-off-by: Viacheslav Huliaiev <vyacheslavhulyaev@gmail.com>
@vyacheslavhulyaev-glitch

Copy link
Copy Markdown
Contributor Author

Thanks for the reviews! I pushed the changes here and in nextcloud/context_agent#285.

Default prompt: I agree with Julien, I think it's better if classic and agentic chat behave the same, so I didn't change that.

Assignments: I don't think the "unless they conflict" part helps much here. The assignment prompt is sent as a normal user message and there is no assignment specific system prompt, so nothing would override "ask for clarification". So I just don't pass the user instructions for assignment runs now. If you'd rather keep them there, it's a one line change.

Audio: I added an optional output_mode input to context_agent. The audio provider sets it to speech, and then the agent's own prompt says to answer in plain text without Markdown. Since that's in the main prompt, it wins over the admin instructions. I tried it locally with admin instructions saying "always use Markdown headings and bullet lists". With output_mode=speech I got plain text, without it I got headings and bold text.

@marcelklehr InternalException is caught now, it logs a warning and the agent just runs without the instructions.

@kyteinsky the task types are fetched only once now (ChatService and the audio provider), and the hint mentions Context Agent 2.10.0.

About removing the "unless they conflict" line and adding an audio note in scheduleAgencyAudioTask(): I thought about it, but I'd keep it like this for now. In #338 the idea was that admins can add to the agent prompt but not override it, so the tool calling instructions don't get broken. That line is also the reason the "no Markdown" rule wins over the admin text. And scheduleAgencyAudioTask() is only the chat, audio from the Assistant UI goes directly through the provider, so setting it in the provider covers both. But I'm fine either way. @julien-nc @janepie what do you think?

@marcelklehr marcelklehr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good to me, now.

@marcelklehr

Copy link
Copy Markdown
Member

Instead of withUserInstructions: false for assignments we could also add a specific assignments prompt in the admin settings, but might be overkill.

@julien-nc julien-nc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

About removing the "unless they conflict" line and adding an audio note in scheduleAgencyAudioTask()

It's fine like it is now.

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

🚀

@marcelklehr
marcelklehr merged commit d69ffeb into nextcloud:main Oct 22, 2026
16 checks passed
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.

Chat User Instructions for Chat Completions Not Being Sent to LLM with context_agent enabled

4 participants