Implement chat completions in go (#16491)

### Summary

POST   /api/v1/chat/completions
This commit is contained in:
qinling0210
2026-07-01 15:52:52 +08:00
committed by GitHub
parent b8e960e6c8
commit 7862f69f39
19 changed files with 1917 additions and 2362 deletions

View File

@@ -2702,6 +2702,13 @@ func (p *Parser) parseAPIDisable() (*Command, error) {
func (p *Parser) parseAPIChat() (*Command, error) {
p.nextToken() // consume CHAT
// Redirect "chat completion[s]" to the standalone chat completions parser.
if p.curToken.Type == TokenIdentifier &&
(strings.EqualFold(p.curToken.Value, "completion") || strings.EqualFold(p.curToken.Value, "completions")) {
p.nextToken() // consume completion/completions
return p.parseChatCompletionsBody()
}
var err error
var modelNameOrID string = ""
var messages []string
@@ -3759,6 +3766,150 @@ optionsLoop:
return cmd, nil
}
// CHAT COMPLETIONS <question>
// [chat_id <string>] [session <string>] [llm <string>]
// parseChatCompletionsBody parses the question and options of a CHAT COMPLETIONS
// command. The leading keyword(s) must already have been consumed by the caller.
func (p *Parser) parseChatCompletionsBody() (*Command, error) {
if p.curToken.Type == TokenDash {
dashCount := 0
for p.curToken.Type == TokenDash {
dashCount++
p.nextToken()
}
if dashCount > 0 && p.curToken.Type == TokenIdentifier {
switch strings.ToLower(p.curToken.Value) {
case "h", "help":
return NewCommand("chat completions help"), nil
}
}
return nil, fmt.Errorf("CHAT COMPLETIONS: only -h/--help takes no args; otherwise expected question")
}
cmd := NewCommand("chat completions")
// Defaults
cmd.Params["chat_id"] = ""
cmd.Params["temperature"] = 0.0
cmd.Params["max_tokens"] = 0
cmd.Params["stream"] = false
// Track which options were explicitly set (distinguishes from defaults).
cmd.Params["_set"] = map[string]bool{}
// Required positional: <question>
question, err := p.parseQuotedString()
if err != nil {
return nil, fmt.Errorf("CHAT COMPLETIONS: expected question: %w", err)
}
cmd.Params["question"] = question
p.nextToken()
// Optional named options
handleOption := func(name string) error {
switch name {
case "chat_id", "session", "llm", "system":
v, err := p.parseQuotedString()
if err != nil {
return fmt.Errorf("CHAT COMPLETIONS %s: expected quoted string, got %s", name, p.curToken.Value)
}
cmd.Params[name] = v
p.nextToken()
markSet(cmd, name)
case "temperature", "top_p", "frequency_penalty", "presence_penalty":
v, err := p.parseFloat()
if err != nil {
return fmt.Errorf("CHAT COMPLETIONS %s: expected number, got %s", name, p.curToken.Value)
}
cmd.Params[name] = v
p.nextToken()
markSet(cmd, name)
case "max_tokens":
v, err := p.parseNumber()
if err != nil {
return fmt.Errorf("CHAT COMPLETIONS max_tokens: expected integer, got %s", p.curToken.Value)
}
cmd.Params["max_tokens"] = v
p.nextToken()
markSet(cmd, "max_tokens")
case "stream", "pass_all_history", "legacy":
v, err := p.parseBool()
if err != nil {
return fmt.Errorf("CHAT COMPLETIONS %s: expected true|false, got %s", name, p.curToken.Value)
}
cmd.Params[name] = v
markSet(cmd, name)
case "history":
raw, err := p.parseQuotedString()
if err != nil {
return fmt.Errorf("CHAT COMPLETIONS history: expected quoted string, got %s", p.curToken.Value)
}
cmd.Params["history_raw"] = raw
p.nextToken()
case "history_delimiter":
v, err := p.parseQuotedString()
if err != nil {
return fmt.Errorf("CHAT COMPLETIONS history_delimiter: expected quoted string, got %s", p.curToken.Value)
}
cmd.Params["history_delimiter"] = v
p.nextToken()
default:
return fmt.Errorf("CHAT COMPLETIONS: unknown option %q (valid: chat_id, session, llm, system, history, history_delimiter, temperature, max_tokens, stream, top_p, frequency_penalty, presence_penalty, pass_all_history, legacy)", name)
}
return nil
}
// Named options, any order, until ';'.
optionsLoop:
for {
switch p.curToken.Type {
case TokenSemicolon:
p.nextToken()
break optionsLoop
case TokenEOF:
break optionsLoop
case TokenIdentifier, TokenQuotedString:
name := p.curToken.Value
if p.curToken.Type == TokenQuotedString {
name = strings.Trim(name, "'\"")
}
p.nextToken()
if err := handleOption(name); err != nil {
return nil, err
}
default:
if !isKeyword(p.curToken.Type) {
return nil, fmt.Errorf("CHAT COMPLETIONS: unexpected token %q in option list (valid options: chat_id, session, llm, system, history, history_delimiter, temperature, max_tokens, stream, top_p, frequency_penalty, presence_penalty, pass_all_history, legacy)", p.curToken.Value)
}
name := p.curToken.Value
p.nextToken()
if err := handleOption(name); err != nil {
return nil, err
}
}
}
return cmd, nil
}
func markSet(cmd *Command, name string) {
if s, ok := cmd.Params["_set"].(map[string]bool); ok {
s[name] = true
}
}
func isSet(cmd *Command, name string) bool {
if s, ok := cmd.Params["_set"].(map[string]bool); ok {
return s[name]
}
return false
}
// parseJSONLiteral consumes a TokenQuotedString whose payload is a JSON
// value (object, array, string, number, or boolean) and returns it as
// the original raw string (NOT decoded — the caller decides whether to