Skip to content

Commit 7e85e27

Browse files
[Fix] NanoGPT Muse Spark fails during tool use (#1310)
* fix(nanogpt): serialize Muse Spark tool calls * fix(nanogpt): preserve Muse tool-result context --------- Co-authored-by: @navedmerchant <14171946+navedmerchant@users.noreply.github.com>
1 parent bd399fa commit 7e85e27

2 files changed

Lines changed: 80 additions & 1 deletion

File tree

src/api/providers/__tests__/nanogpt.spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,78 @@ describe("NanoGptHandler", () => {
171171
expect(mockCreate.mock.calls[0][0]).not.toHaveProperty("max_completion_tokens")
172172
})
173173

174+
it("keeps Muse Spark tool-result history contiguous across turns", async () => {
175+
const modelId = "meta/muse-spark-1.2-contributor"
176+
vi.mocked(getModels).mockResolvedValue({
177+
[modelId]: {
178+
maxTokens: 65_536,
179+
contextWindow: 1_000_000,
180+
supportsPromptCache: false,
181+
},
182+
})
183+
const tools: OpenAI.Chat.ChatCompletionTool[] = [
184+
{ type: "function", function: { name: "read_file", parameters: { type: "object" } } },
185+
]
186+
const toolHistory: Anthropic.Messages.MessageParam[] = [
187+
{
188+
role: "assistant",
189+
content: [{ type: "tool_use", id: "call_1", name: "read_file", input: { path: "first.txt" } }],
190+
},
191+
{
192+
role: "user",
193+
content: [
194+
{ type: "tool_result", tool_use_id: "call_1", content: "first result" },
195+
{ type: "text", text: "<environment_details>first context</environment_details>" },
196+
],
197+
},
198+
{
199+
role: "assistant",
200+
content: [{ type: "tool_use", id: "call_2", name: "read_file", input: { path: "second.txt" } }],
201+
},
202+
{
203+
role: "user",
204+
content: [
205+
{ type: "tool_result", tool_use_id: "call_2", content: "second result" },
206+
{ type: "text", text: "<environment_details>second context</environment_details>" },
207+
],
208+
},
209+
]
210+
211+
await collectStream(
212+
new NanoGptHandler({ nanoGptModelId: modelId }).createMessage("sys", toolHistory, {
213+
taskId: "task",
214+
tools,
215+
tool_choice: "auto",
216+
parallelToolCalls: true,
217+
}),
218+
)
219+
220+
expect(mockCreate).toHaveBeenCalledWith(
221+
expect.objectContaining({
222+
model: modelId,
223+
messages: [
224+
{ role: "system", content: "sys" },
225+
expect.objectContaining({ role: "assistant", tool_calls: [expect.anything()] }),
226+
{
227+
role: "tool",
228+
tool_call_id: "call_1",
229+
content: "first result\n\n<environment_details>first context</environment_details>",
230+
},
231+
expect.objectContaining({ role: "assistant", tool_calls: [expect.anything()] }),
232+
{
233+
role: "tool",
234+
tool_call_id: "call_2",
235+
content: "second result\n\n<environment_details>second context</environment_details>",
236+
},
237+
],
238+
tools: [expect.objectContaining({ function: expect.objectContaining({ name: "read_file" }) })],
239+
tool_choice: "auto",
240+
parallel_tool_calls: true,
241+
}),
242+
expect.anything(),
243+
)
244+
})
245+
174246
it("omits temperature when it was not explicitly configured", async () => {
175247
await collectStream(new NanoGptHandler({ nanoGptModelId: "model:thinking" }).createMessage("sys", messages))
176248
expect(mockCreate.mock.calls[0][0]).not.toHaveProperty("temperature")

src/api/providers/nanogpt.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type NanoGptUsage = OpenAI.CompletionUsage & {
2727

2828
type NanoGptCachingRequest = { caching?: true }
2929

30+
const NANO_GPT_MERGED_TOOL_RESULT_MODELS = new Set(["meta/muse-spark-1.2-contributor"])
31+
3032
const OPENAI_REASONING_EFFORTS = ["low", "medium", "high"] as const
3133
type OpenAiReasoningEffort = (typeof OPENAI_REASONING_EFFORTS)[number]
3234

@@ -93,7 +95,12 @@ export class NanoGptHandler extends RouterProvider implements SingleCompletionHa
9395
const { id: canonicalModelId, info } = await this.fetchModel()
9496
const body: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming & NanoGptCachingRequest = {
9597
model: this.getRequestModelId(canonicalModelId),
96-
messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
98+
messages: [
99+
{ role: "system", content: systemPrompt },
100+
...convertToOpenAiMessages(messages, {
101+
mergeToolResultText: NANO_GPT_MERGED_TOOL_RESULT_MODELS.has(canonicalModelId),
102+
}),
103+
],
97104
stream: true,
98105
stream_options: { include_usage: true },
99106
max_tokens: info.maxTokens ?? undefined,

0 commit comments

Comments
 (0)