diff --git a/README.md b/README.md index 45c9d63..177844e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ auto_session = true [openai] key = sk-... -model = gpt-4.1-nano-2025-04-14 +`model = gpt-5-nano [gemini] key = ... @@ -69,8 +69,8 @@ seance chat "What is the speed of light?" # Specify a provider for your query seance chat "Explain the theory of relativity" --provider gemini -# Use piped content as input -cat src/seance.nim | seance chat "Explain what this Nim code does." +# Use piping to write your PR descriptions +git diff main... | seance chat "Write a conventional commit PR" ``` ### 3. Session Management @@ -104,7 +104,7 @@ This will delete all sessions older than 10 days, or whatever you specify with - seance chat "This chat should not be saved." --no_session ``` -- **Using a JSON Schema**: To force the output to be in a specific JSON format, you can use the `--json` flag. For the Gemini, Anthropic, and OpenAI providers, you can also use the `--schema` flag to provide a JSON schema to which the output must conform. +- **Using a JSON Schema**: To force the output to be in a specific JSON format, you can use the `--json` flag. For the Gemini, Anthropic, OpenAI, and LMStudio providers, you can also use the `--schema` flag to provide a JSON schema to which the output must conform. ```bash # Create a schema file diff --git a/seance.nimble b/seance.nimble index 74d56be..018e779 100644 --- a/seance.nimble +++ b/seance.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.0" +version = "0.5.0" author = "Emre Şafak" description = "A CLI tool and library for interacting with various LLMs" license = "MIT" diff --git a/src/seance/providers/lmstudio.nim b/src/seance/providers/lmstudio.nim index 3ba89d8..ae84c81 100644 --- a/src/seance/providers/lmstudio.nim +++ b/src/seance/providers/lmstudio.nim @@ -96,15 +96,21 @@ method chat*(provider: LMStudioProvider, messages: seq[ChatMessage], model: Opti processedMessages.add(ChatMessage(role: system, content: "Return the response in JSON format.")) var requestBody: string + let request = LMStudioChatRequest(model: usedModel, messages: processedMessages) + var requestJson = %*request if jsonMode: - let schemaNode = schema.get(%*{"type": "object"}) - let request = LMStudioChatRequest(model: usedModel, messages: processedMessages) - var requestJson = %*request - requestJson["response_format"] = %*{"type": "json_object"} - requestBody = $requestJson - else: - let request = LMStudioChatRequest(model: usedModel, messages: processedMessages) - requestBody = $(%*request) + if schema.isSome: + requestJson["response_format"] = %*{ + "type": "json_schema", + "json_schema": { + "name": "json_schema", + "strict": true, + "schema": schema.get() + } + } + else: + requestJson["response_format"] = %*{"type": "json_object"} + requestBody = $requestJson info "LMStudio Request Body: " & requestBody debug "curl -X POST " & endpoint & " -H \"Content-Type: application/json\" -d '" & requestBody & "'" diff --git a/tests/t_providers_lmstudio.nim b/tests/t_providers_lmstudio.nim index 066b023..20c2c67 100644 --- a/tests/t_providers_lmstudio.nim +++ b/tests/t_providers_lmstudio.nim @@ -167,3 +167,25 @@ suite "LMStudio Provider": let requestJson = parseJson(capturedRequestBody) check requestJson["model"].getStr() == "model-2" check result.model == "model-2" + + test "chat method sends correct request with json schema": + mockHttpResponse = Response( + status: "200 OK", + bodyStream: newStringStream("""{"choices": [{"message": {"role": "assistant", "content": "{\"tool_code\":\"ls()\"}"}}]}""") + ) + + let conf = ProviderConfig(key: "", model: none(string), endpoint: none(string)) + let provider = newProvider(some(LMStudio), some(conf)) + provider.postRequestHandler = mockPostRequestHandler + + let schema = %*{"type": "object", "properties": {"tool_code": {"type": "string"}}} + let result = provider.chat(testMessages, model = none(string), jsonMode = true, schema = some(schema)) + + check capturedUrl == DefaultLMStudioEndpoint + let requestJson = parseJson(capturedRequestBody) + check requestJson.hasKey("response_format") + let responseFormat = requestJson["response_format"] + check responseFormat["type"].getStr() == "json_schema" + check responseFormat["json_schema"]["name"].getStr() == "json_schema" + check responseFormat["json_schema"]["strict"].getBool() == true + check responseFormat["json_schema"]["schema"] == schema