Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/supercode-cli/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "supercode-cli",
"version": "0.1.62",
"version": "0.1.63",
"description": "AI-powered coding agent CLI",
"main": "dist/main.js",
"bin": {
Expand Down
16 changes: 13 additions & 3 deletions apps/supercode-cli/server/src/cli/ai/concentrate-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@ interface NonStreamingResponse {
usage?: { prompt_tokens?: number; completion_tokens?: number }
}

async function nonStreamingRequest(modelName: string, system: string, messages: Array<{ role: string; content: string }>): Promise<NonStreamingResponse> {
async function nonStreamingRequest(modelName: string, system: string, messages: Array<{ role: string; content: string }>, tools?: any): Promise<NonStreamingResponse> {
const body: Record<string, unknown> = {
model: modelName,
messages: system ? [{ role: "system", content: system }, ...messages] : messages,
temperature: 0.7,
stream: false,
}
if (!HIGH_VALUE_MODELS.includes(modelName)) body.max_tokens = 8192
if (tools && typeof tools === "object") {
body.tools = Object.entries(tools).map(([name, fn]: [string, any]) => ({
type: "function",
function: { name, description: fn.description || "", parameters: fn.parameters || { type: "object", properties: {} } },
}))
}
const res = await fetchWithRetry(`${BASE_URL}/chat/completions`, {
method: "POST",
headers: { Authorization: `Bearer ${CONCENTRATE_API_KEY}`, "Content-Type": "application/json" },
Expand Down Expand Up @@ -309,6 +315,7 @@ export class ConcentrateService {
})

let toolChunkCount = 0
let sawToolEvents = false
// Iterate fullStream to surface reasoning chunks alongside text.
for await (const event of result.fullStream) {
if (event.type === "text-delta") {
Expand All @@ -318,14 +325,17 @@ export class ConcentrateService {
onChunk?.(event.text)
} else if (event.type === "reasoning-delta") {
if (event.text) onReasoning?.(event.text)
} else if (event.type === "tool-call" || event.type === "tool-result") {
sawToolEvents = true
}
}
// console.error(`[d] tools streamed ${toolChunkCount} chunks resp="${fullResponse}"`)

// Same empty-stream fallback as non-tools path — ConcentrateAI's
// Novita proxy intermittently drops content on streaming requests.
if (!fullResponse.trim()) {
const nonStreamData = await nonStreamingRequest(this.modelName, system, nonSystemMessages.map((m: any) => ({ role: m.role, content: typeof m.content === "string" ? m.content : JSON.stringify(m.content) })))
// Skip if the model made tool calls (tool-text-only responses are valid).
if (!fullResponse.trim() && !sawToolEvents) {
const nonStreamData = await nonStreamingRequest(this.modelName, system, nonSystemMessages.map((m: any) => ({ role: m.role, content: typeof m.content === "string" ? m.content : JSON.stringify(m.content) })), tools)
const content = nonStreamData?.choices?.[0]?.message?.content ?? ""
if (content) {
onChunk?.(content)
Expand Down
20 changes: 5 additions & 15 deletions apps/supercode-cli/server/src/cli/commands/ai/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,16 @@ export const wakeUpAction = async (resumeId: string | null = null) => {
}

if (stored) {
switch (stored.mode) {
case "agent":
await startAgentChat(stored.provider, stored.model, resumeId, workspaceInfo ?? undefined)
break
default:
await startChat(stored.provider, stored.model, resumeId, workspaceInfo ?? undefined, stored.mode)
break
if (resumeId && stored.mode === "agent") {
await startAgentChat(stored.provider, stored.model, resumeId, workspaceInfo ?? undefined)
} else {
await startChat(stored.provider, stored.model, resumeId, workspaceInfo ?? undefined, "chat")
}
return
}

const defaults = await saveCliConfig({})
switch (defaults.mode) {
case "agent":
await startAgentChat(defaults.provider, defaults.model, resumeId, workspaceInfo ?? undefined)
break
default:
await startChat(defaults.provider, defaults.model, resumeId, workspaceInfo ?? undefined, defaults.mode)
break
}
await startChat(defaults.provider, defaults.model, resumeId, workspaceInfo ?? undefined, "chat")
}

export const supercodeInit = new Command("init")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const MODELS: ModelEntry[] = [
{ value: "kimi-k2-6", label: "Kimi K2.6", provider: "concentrateai", cost: "0.8x", desc: "Long context" },
{ value: "deepseek-v4-flash", label: "DeepSeek V4 Flash", provider: "concentrateai", cost: "1.0x", desc: "Fast & capable" },
{ value: "minimax-m3", label: "MiniMax M3", provider: "concentrateai", cost: "0.5x", desc: "Fast & smart" },
{ value: "anthropic/claude-opus-4-8", label: "Opus 4.8", provider: "concentrateai", cost: "40x", desc: "Deep reasoning" },
{ value: "anthropic/claude-opus-4-8", label: "Opus 4.8", provider: "mergedev", cost: "40x", desc: "Via Merge Dev" },
{ value: "gemini-2.5-flash", label: "Gemini 2.5 Flash", provider: "google", cost: "2.0x", desc: "Smart & fast" },
{ value: "gemini-2.5-pro", label: "Gemini 2.5 Pro", provider: "google", cost: "4.0x", desc: "Deep reasoning" },
Expand Down
8 changes: 6 additions & 2 deletions apps/supercode-cli/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import { writeFileSync, unlinkSync } from "fs"
import { randomUUID } from "crypto"

function toolParams(fn: any): object {
const raw = fn.inputSchema ?? fn.parameters ?? {}
return raw && typeof raw === "object" && "_def" in raw ? {} : raw
const raw = fn.inputSchema ?? fn.parameters
if (!raw || (typeof raw === "object" && "_def" in raw)) {
return { type: "object", properties: {} }
}
return raw
Comment on lines +17 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for zod-to-json-schema package to use for converting Zod schemas
rg "zod-to-json-schema" package.json apps/supercode-cli/server/package.json

Repository: yashdev9274/supercli

Length of output: 233


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== outline: apps/supercode-cli/server/src/index.ts ==\n'
ast-grep outline apps/supercode-cli/server/src/index.ts --view expanded || true

printf '\n== outline: apps/supercode-cli/server/src/cli/ai/concentrate-service.ts ==\n'
ast-grep outline apps/supercode-cli/server/src/cli/ai/concentrate-service.ts --view expanded || true

printf '\n== relevant ranges ==\n'
sed -n '1,120p' apps/supercode-cli/server/src/index.ts
printf '\n---\n'
sed -n '1,140p' apps/supercode-cli/server/src/cli/ai/concentrate-service.ts

Repository: yashdev9274/supercli

Length of output: 11564


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== toolParams references ==\n'
rg -n "toolParams\\(" apps/supercode-cli/server/src/index.ts apps/supercode-cli/server/src/cli/ai/concentrate-service.ts

printf '\n== parameters / inputSchema references in server src ==\n'
rg -n "inputSchema|\\.parameters\\b|zod-to-json-schema|toJsonSchema|json schema|tool schema" apps/supercode-cli/server/src -g '!**/node_modules/**'

printf '\n== surrounding block in index.ts around tool usage ==\n'
sed -n '140,260p' apps/supercode-cli/server/src/index.ts

printf '\n== surrounding block in concentrate-service.ts around nonStreamingRequest ==\n'
sed -n '1,110p' apps/supercode-cli/server/src/cli/ai/concentrate-service.ts

Repository: yashdev9274/supercli

Length of output: 11035


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== toolParams references ==\n'
rg -n "toolParams\\(" apps/supercode-cli/server/src/index.ts apps/supercode-cli/server/src/cli/ai/concentrate-service.ts

printf '\n== nonStreamingRequest references ==\n'
rg -n "nonStreamingRequest\\(" apps/supercode-cli/server/src/cli/ai/concentrate-service.ts

printf '\n== parameters / inputSchema references in server src ==\n'
rg -n "inputSchema|\\.parameters\\b|zod-to-json-schema|toJsonSchema|json schema|tool schema" apps/supercode-cli/server/src -g '!**/node_modules/**'

printf '\n== surrounding block in index.ts around tool usage ==\n'
sed -n '140,260p' apps/supercode-cli/server/src/index.ts

printf '\n== surrounding block in concentrate-service.ts around nonStreamingRequest ==\n'
sed -n '1,110p' apps/supercode-cli/server/src/cli/ai/concentrate-service.ts

Repository: yashdev9274/supercli

Length of output: 11691


Convert tool schemas before serializing.

  • apps/supercode-cli/server/src/index.ts#L16-L21: toolParams() returns { type: "object", properties: {} } for any Zod schema, so tool arguments are stripped.
  • apps/supercode-cli/server/src/cli/ai/concentrate-service.ts#L40-L45: this path still forwards fn.parameters directly and never normalizes fn.inputSchema. Pull fn.inputSchema ?? fn.parameters and convert Zod inputs to JSON Schema (the repo already includes zod-to-json-schema).
📍 Affects 2 files
  • apps/supercode-cli/server/src/index.ts#L17-L21 (this comment)
  • apps/supercode-cli/server/src/cli/ai/concentrate-service.ts#L40-L45
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/supercode-cli/server/src/index.ts` around lines 17 - 21, Update
toolParams() in apps/supercode-cli/server/src/index.ts (lines 17-21) to convert
Zod schemas to JSON Schema with the repository’s zod-to-json-schema dependency
instead of returning an empty object; preserve existing handling for absent or
already-serializable schemas. In
apps/supercode-cli/server/src/cli/ai/concentrate-service.ts (lines 40-45),
normalize the tool schema by selecting fn.inputSchema ?? fn.parameters and
applying the same Zod-to-JSON-Schema conversion before forwarding it.

}

loadEnvOnce()
Expand Down Expand Up @@ -738,6 +741,7 @@ app.post("/api/ai/chat", async (req, res) => {
}
const finishReason = data.choices?.[0]?.finish_reason
if (finishReason === "tool_calls") {
sawToolCalls = true
for (const [, call] of Object.entries(pendingToolCalls)) {
if (call.name && call.args) {
try {
Expand Down
Loading