Skip to content

Add support for extra headers - #439

Open
julien-nc wants to merge 10 commits into
mainfrom
enh/noid/extra-headers
Open

julien-nc wants to merge 10 commits into
mainfrom
enh/noid/extra-headers

Conversation

@julien-nc

Copy link
Copy Markdown
Member

closes #436
refs #430

Some services might require extra headers like a non-standard authentication header.

  • Add the ability to define service-specific extra headers that are sent with all network requests
  • Add support for one variable ({$conversation_id) in the header value. This variable is only resolved in chat providers. It resolves to the conversation_id optional input that is sent by the assistant (see Let the chat providers know about the conversation/session ID assistant#674 ). This header will only be sent for chat requests.
image

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI (N/A)

@julien-nc julien-nc added enhancement New feature or request 3. to review labels Sep 29, 2026
@kyteinsky
kyteinsky requested a review from edward-ly October 6, 2026 18:36
@edward-ly

edward-ly commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Besides OpenCode Go, are there any other services that might be able to take advantage of or require this? Perhaps it would be safer to limit which headers can be sent, or do you think this approach is still fine?

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

maybe Summary, Translate, etc. tasks also need the conversation id injection since they use the same chat completion endpoint.
for opencode, they wouldn't work without the conversation id header.

Comment thread src/components/ServiceForm.vue Outdated
Comment on lines +693 to +694
return header.name !== header.name.trim()
|| header.value !== header.value.trim()

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.

not sure if this works well for UX, if there is a genuine space after the header name/value, it will not be registered, maybe we can still register it trimmed?
if new edits to the field land, a new request can be made to save that.
wdyt?

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.

Trimmed values are saved now.

Comment thread src/components/ServiceForm.vue Outdated
Comment on lines +695 to +696
|| this.headerNameInvalid(header.name)
|| this.headerValueInvalid(header.value)

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 good to show an error/red the input box if these fail so the user is aware there is a mistake

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.

ah this is already the case, maybe dirty header can be replaced with a debounce?

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.

Could you give more details on your suggestion?

Comment thread lib/Service/ServicesService.php Outdated
Comment on lines +438 to +439
$name = trim($header['name']);
if ($name !== '' && preg_match(ServiceConfig::HEADER_NAME_PATTERN, $name) !== 1) {

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.

maybe empty header names can be rejected here too

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.

Empty header names and values cannot be saved now.

Comment thread lib/Service/ServiceConfig.php Outdated
Comment on lines +65 to +66
/** Characters an HTTP header name is made of (the RFC 7230 token) */
public const HEADER_NAME_PATTERN = '/^[a-zA-Z0-9!#$%&\'*+.^_`|~-]+$/';

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.

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.

Done

'body' => $body,
'content-type' => $contentTypeHeader,
];
} catch (ClientException|ServerException $e) {

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.

\InvalidArgumentException can be thrown in the request too if headers are not valid, would be nice to catch them too here.
see the header regex link.

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.

Done. It is useful indeed. Some header values could be revealed to the users.

@julien-nc
julien-nc force-pushed the enh/noid/extra-headers branch from 2ccc1d0 to 66b452f Compare October 8, 2026 12:29
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
…tion ID passed as an optional input field in the chat providers

Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
…tion providers

The {$conversation_id} extra header was only expanded for the chat
providers. Summary, translate and all the other task types that go
through the chat completion endpoint are as well concerned: services
requiring that header reject their requests without it.

Every provider reaching the chat completion endpoint now takes an
optional conversation_id input and passes it along the completion
request. The providers delegating to another one (enhanced audio to
text, improved prompt image generation) forward it, and the translation
service gained a conversation ID parameter.

Assisted-by: OpenCode:qwen3.8-flash
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
… one

The assistant generic form schedules tasks through the task processing
endpoints directly, so it cannot pass the optional conversation ID
input. Services requiring the conversation header then rejected the
requests.

Chat completion requests now always carry a conversation ID: a random
throwaway one is generated when the task does not belong to a
conversation, refreshed per request so unrelated tasks never share
state on conversation-aware services. Non-chat endpoints keep dropping
such a header.

Assisted-by: OpenCode:qwen3.8-flash
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
@julien-nc
julien-nc force-pushed the enh/noid/extra-headers branch from 66b452f to 501efdc Compare October 8, 2026 12:30
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
@julien-nc

Copy link
Copy Markdown
Member Author

@edward-ly

Besides OpenCode Go, are there any other services that might be able to take advantage of or require this? Perhaps it would be safer to limit which headers can be sent, or do you think this approach is still fine?

I think it's fine to let the admin set any extra headers. It makes it more generic. Some services might have some exotic authentication based on specific headers.

This branch has not been deployed

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

Labels

3. to review enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow to send extra headers in the requests to the external service

3 participants