$candidates */ public function build(string $basePrompt, string $ticketMessage, array $candidates, string $language): string { $articlesBlock = collect($candidates) ->map(fn (ArticleCandidateDTO $item, int $idx) => sprintf( "%d. article_id=%d\nTitle: %s\nSource URL: %s\nAllowed actions: %s\nInternal note for support assistant: %s\nContent: %s", $idx + 1, $item->articleId, $item->title, $item->sourceUrl ?? '-', $item->allowedActions === [] ? '[]' : json_encode($item->allowedActions, JSON_UNESCAPED_SLASHES), $item->note ?: '-', $item->content )) ->implode("\n\n"); return $basePrompt."\n\n". "User language: {$language}. Return explanation in this language.\n\n". "Return JSON only with this schema:\n". "{\n". " \"article_id\": number,\n". " \"confidence\": number,\n". " \"explanation\": string,\n". " \"tool_call\": null | {\"action\": \"domain_inf\", \"parameters\": {\"sld\": string, \"tld\": string}, \"reason\": string}\n". "}\n\n". "Only include a tool_call when the selected article lists that action in Allowed actions and both required parameters are present in the user question.\n". "Never invent sld or tld. If either parameter is missing, set tool_call to null.\n\n". "User question:\n\"{$ticketMessage}\"\n\nArticles:\n{$articlesBlock}"; } }