mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-01 14:52:25 +00:00
feat: releases
This commit is contained in:
@@ -251,8 +251,15 @@ export namespace Agent {
|
||||
return result
|
||||
})
|
||||
|
||||
export async function get(agent: string) {
|
||||
return state().then((x) => x[agent])
|
||||
export async function get(agent: string): Promise<Info> {
|
||||
const localAgents = await state()
|
||||
if (localAgents[agent]) return localAgents[agent]
|
||||
|
||||
const tfAgents = await loadTFCoderAgents()
|
||||
const tfAgent = tfAgents.find((a) => a.name === agent)
|
||||
if (tfAgent) return tfAgent
|
||||
|
||||
return localAgents.build
|
||||
}
|
||||
|
||||
async function loadTFCoderAgents(): Promise<Info[]> {
|
||||
@@ -261,20 +268,22 @@ export namespace Agent {
|
||||
const content = await Bun.file(toolsPath).text()
|
||||
const data = JSON.parse(content)
|
||||
if (!data.success || !data.tools) return []
|
||||
|
||||
|
||||
return data.tools
|
||||
.filter((t: any) => t.tool_type === "coder_agent")
|
||||
.map((t: any): Info => ({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
mode: "primary" as const,
|
||||
permission: Permission.fromConfig({ "*": "allow" }),
|
||||
native: false,
|
||||
options: {
|
||||
tf_agent_id: t.id,
|
||||
tf_auth_via: t.auth_via,
|
||||
},
|
||||
}))
|
||||
.map(
|
||||
(t: any): Info => ({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
mode: "primary" as const,
|
||||
permission: Permission.fromConfig({ "*": "allow" }),
|
||||
native: false,
|
||||
options: {
|
||||
tf_agent_id: t.id,
|
||||
tf_auth_via: t.auth_via,
|
||||
},
|
||||
}),
|
||||
)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
@@ -284,9 +293,9 @@ export namespace Agent {
|
||||
const cfg = await Config.get()
|
||||
const localAgents = await state()
|
||||
const tfAgents = await loadTFCoderAgents()
|
||||
|
||||
|
||||
return pipe(
|
||||
{ ...localAgents, ...Object.fromEntries(tfAgents.map(a => [a.name, a])) },
|
||||
{ ...localAgents, ...Object.fromEntries(tfAgents.map((a) => [a.name, a])) },
|
||||
values(),
|
||||
sortBy(
|
||||
[(x) => (cfg.default_agent ? x.name === cfg.default_agent : x.name === "build"), "desc"],
|
||||
|
||||
@@ -58,12 +58,9 @@ function getPythonSyncPath(): string {
|
||||
return "tf_sync"
|
||||
}
|
||||
|
||||
async function runPythonSync(
|
||||
method: string,
|
||||
args: Record<string, unknown> = {},
|
||||
): Promise<unknown> {
|
||||
async function runPythonSync(method: string, args: Record<string, unknown> = {}): Promise<unknown> {
|
||||
const credentials = await loadCredentials()
|
||||
|
||||
|
||||
const pythonCode = `
|
||||
import json
|
||||
import sys
|
||||
@@ -458,8 +455,7 @@ const ToolsCredentialsSetCommand = cmd({
|
||||
const ToolsCommand = cmd({
|
||||
command: "tools",
|
||||
describe: "manage ToothFairyAI tools",
|
||||
builder: (yargs) =>
|
||||
yargs.command(ToolsListCommand).command(ToolsCredentialsSetCommand).demandCommand(),
|
||||
builder: (yargs) => yargs.command(ToolsListCommand).command(ToolsCredentialsSetCommand).demandCommand(),
|
||||
async handler() {},
|
||||
})
|
||||
|
||||
@@ -561,8 +557,106 @@ export const ToolsMainCommand = cmd({
|
||||
command: "tools",
|
||||
describe: "manage ToothFairyAI tools",
|
||||
builder: (yargs) =>
|
||||
yargs.command(ToolsListCommand).command(ToolsCredentialsSetCommand).command(ToolsDebugCommand).command(ToolsTestCommand).demandCommand(),
|
||||
yargs
|
||||
.command(ToolsListCommand)
|
||||
.command(ToolsCredentialsSetCommand)
|
||||
.command(ToolsDebugCommand)
|
||||
.command(ToolsTestCommand)
|
||||
.demandCommand(),
|
||||
async handler() {},
|
||||
})
|
||||
|
||||
export { ValidateCommand, SyncCommand, ToolsCommand }
|
||||
export const SetupCommand = cmd({
|
||||
command: "setup",
|
||||
describe: "configure ToothFairyAI credentials",
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.option("api-key", {
|
||||
type: "string",
|
||||
describe: "API key",
|
||||
})
|
||||
.option("workspace-id", {
|
||||
type: "string",
|
||||
describe: "Workspace ID",
|
||||
})
|
||||
.option("region", {
|
||||
type: "string",
|
||||
describe: "Region (dev, au, eu, us)",
|
||||
default: "au",
|
||||
}),
|
||||
handler: async (args) => {
|
||||
const configPath = getConfigPath()
|
||||
const credFile = getCredentialsFilePath()
|
||||
|
||||
// Load existing credentials
|
||||
let existing: { api_key?: string; workspace_id?: string; region?: string } = {}
|
||||
if (await Filesystem.exists(credFile)) {
|
||||
try {
|
||||
existing = await Bun.file(credFile).json()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Get credentials from args or prompt
|
||||
let apiKey = args["api-key"]
|
||||
let workspaceId = args["workspace-id"]
|
||||
let region = args.region || existing.region || "au"
|
||||
|
||||
if (!apiKey || !workspaceId) {
|
||||
info("")
|
||||
info("ToothFairyAI Credentials Setup")
|
||||
info("━".repeat(40))
|
||||
info("")
|
||||
|
||||
if (!workspaceId) {
|
||||
process.stdout.write(`Workspace ID [${existing.workspace_id || ""}]: `)
|
||||
const input = await new Promise<string>((resolve) => {
|
||||
process.stdin.once("data", (data) => resolve(data.toString().trim()))
|
||||
})
|
||||
workspaceId = input || existing.workspace_id
|
||||
}
|
||||
|
||||
if (!apiKey) {
|
||||
process.stdout.write(`API Key [${existing.api_key ? "****" + existing.api_key.slice(-4) : ""}]: `)
|
||||
const input = await new Promise<string>((resolve) => {
|
||||
process.stdin.once("data", (data) => resolve(data.toString().trim()))
|
||||
})
|
||||
apiKey = input || existing.api_key
|
||||
}
|
||||
|
||||
process.stdout.write(`Region [${region}]: `)
|
||||
const regionInput = await new Promise<string>((resolve) => {
|
||||
process.stdin.once("data", (data) => resolve(data.toString().trim()))
|
||||
})
|
||||
if (regionInput) region = regionInput
|
||||
}
|
||||
|
||||
if (!apiKey || !workspaceId) {
|
||||
printError("API key and workspace ID are required")
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
// Save credentials
|
||||
await mkdir(configPath, { recursive: true })
|
||||
await Bun.write(
|
||||
credFile,
|
||||
JSON.stringify(
|
||||
{
|
||||
api_key: apiKey,
|
||||
workspace_id: workspaceId,
|
||||
region,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
)
|
||||
|
||||
success(`✓ Credentials saved to ${credFile}`)
|
||||
info(` Workspace: ${workspaceId}`)
|
||||
info(` Region: ${region}`)
|
||||
info("")
|
||||
info("Run 'tfcode validate' to test your credentials")
|
||||
},
|
||||
})
|
||||
|
||||
export { ValidateCommand, SyncCommand, ToolsCommand }
|
||||
|
||||
@@ -11,6 +11,17 @@ interface ChangelogEntry {
|
||||
}
|
||||
|
||||
const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
version: "1.0.2",
|
||||
date: "2026-03-24",
|
||||
changes: [
|
||||
"Fixed TF coder agents not loading correctly",
|
||||
"Fixed content:null error in ToothFairyAI predictions API",
|
||||
"Added reasoning_content support for thinking models",
|
||||
"Added tfcode setup command to persist credentials",
|
||||
"Removed TF-specific options for non-TF providers",
|
||||
],
|
||||
},
|
||||
{
|
||||
version: "1.0.0-beta",
|
||||
date: "2026-03-24",
|
||||
@@ -71,4 +82,4 @@ export function DialogChangelog() {
|
||||
</box>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import { WebCommand } from "./cli/cmd/web"
|
||||
import { PrCommand } from "./cli/cmd/pr"
|
||||
import { SessionCommand } from "./cli/cmd/session"
|
||||
import { DbCommand } from "./cli/cmd/db"
|
||||
import { ValidateCommand, SyncCommand, ToolsMainCommand } from "./cli/cmd/tools"
|
||||
import { ValidateCommand, SyncCommand, ToolsMainCommand, SetupCommand } from "./cli/cmd/tools"
|
||||
import { QuickstartCommand } from "./cli/cmd/quickstart"
|
||||
import path from "path"
|
||||
import { Global } from "./global"
|
||||
@@ -149,6 +149,7 @@ let cli = yargs(hideBin(process.argv))
|
||||
.command(DbCommand)
|
||||
.command(ValidateCommand)
|
||||
.command(SyncCommand)
|
||||
.command(SetupCommand)
|
||||
.command(ToolsMainCommand)
|
||||
.command(QuickstartCommand)
|
||||
|
||||
|
||||
@@ -115,10 +115,11 @@ export function convertToOpenAICompatibleChatMessages(prompt: LanguageModelV2Pro
|
||||
|
||||
messages.push({
|
||||
role: "assistant",
|
||||
content: text || null,
|
||||
content: text || undefined,
|
||||
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
||||
reasoning_text: reasoningOpaque ? reasoningText : undefined,
|
||||
reasoning_opaque: reasoningOpaque,
|
||||
reasoning_content: reasoningText,
|
||||
...metadata,
|
||||
})
|
||||
|
||||
|
||||
@@ -109,6 +109,13 @@ export namespace LLM {
|
||||
mergeDeep(input.agent.options),
|
||||
mergeDeep(variant),
|
||||
)
|
||||
|
||||
// Remove TF-specific options for non-ToothFairyAI providers
|
||||
if (input.model.providerID !== "toothfairyai") {
|
||||
delete options.tf_agent_id
|
||||
delete options.tf_auth_via
|
||||
}
|
||||
|
||||
if (isOpenaiOauth) {
|
||||
options.instructions = system.join("\n")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user