TMS AI Studio - SystemRole is silently dropped when Service = aiClaude

I am using TMS AI Studio v1.7.4.0.

The content of the SystemRole property is never sent to the Anthropic API when
the service is Claude. No error, no warning: the request succeeds and the model
simply runs with no system prompt at all.

In BuildPostData, the block that builds the system message excludes Claude:

"if (FSystemRole.Text <> '') and (Service <> aiClaude) then"

That exclusion is correct, because the Anthropic Messages API rejects a
"system" role inside the messages array with HTTP 400:

"messages: Unexpected role "system". The Messages API accepts a top-level
'system' parameter, not "system" as an input message role."

The problem is that the alternative Anthropic requires was never implemented.
Unlike the OpenAI-style providers, Anthropic expects the system prompt as a
top-level parameter, sibling of "messages". The cDataClaude template has no
"system" field, and FSystemRole is not referenced anywhere else in the
request-building path, so for Claude the value never leaves the component.

- Possible FIX (I made an API Call with this fix and it worked correctly)

Add a slot to the template:

cDataClaude = '{' +
  '"model": "%s",' +
  '%s'+                        // system prompt, top-level
  '"messages": [ %s ],'+
  ...

Populate it in the aiClaude branch of BuildPostData:

AClaudeSystemRole := '';
if FSystemRole.Text <> '' then
  AClaudeSystemRole := '"system": "' + JsonEncode(FSystemRole.Text) + '",';

And pass it in second position:

Result := string.Format(cDataClaude, [FSettings.ClaudeModel,
  AClaudeSystemRole, AMessages, FAllTools.ToJSON(Service, Settings.WebSearch),
  AParallel, ATemperature, AMaxTokens, AOptions, ACacheControl]);

I have applied this fix in our code and confirmed the request now succeeds with the "system"
field present.

Reference: Messages - Claude API Reference

One more thing, also related with Claude API. In the same aiClaude branch, the reasoning effort is emitted inside "thinking" instead of in the "output_config" parameter that Anthropic expects. I have not tested it and have no fix for this, because it does not affect our code, but I think it could be a related issued with Claude API calls.

We've fixed the system role handling for Claude. Next update will address this.

Regarding thinking, I'm not sure where you see something emitted in output_config? I couldn't find anything in the code that would use 'output_config'

The doc states this is expected:

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 16000,
    "thinking": {"type": "adaptive", "display": "summarized"},
    "messages": [{"role": "user", "content": "GCD of 1071 and 462?"}]
  }'

and this is how we emit it. Do you have more details?

Thanks for fixing the system role, much appreciated.

Sorry, if my report was ambiguous: I did not say TMS emits "output_config". The opposite: TMS never emits it, and that's the bug.

Your curl is correct, and that's my point: "thinking" carries only "type" and "display". There is no "effort" member. Effort is a separate, sibling top-level parameter: "output_config": {"effort": low|medium|high|xhigh|max}, default "high".


TMS.MCP.CloudAI.pas, TTMSMCPCloudAI.BuildPostData, aiClaude branch, emits:

aiLow: ',"thinking": {"type": "adaptive", "effort": "low"}'

aiMedium: ',"thinking": {"type": "adaptive", "effort": "medium"}'

aiHigh: ',"thinking": {"type": "adaptive"}'

"effort" inside "thinking" is an unrecognized key, so aiLow and aiMedium return HTTP 400. aiHigh works only because it emits no effort — and "high" happens to be Anthropic's default, so the intent survives by accident.


Correct for aiLow:

"thinking": {"type": "adaptive"},

"output_config": {"effort": "low"},

Docs: Effort - Claude Platform Docs