mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-03 07:33:45 +00:00
feat: new integration
This commit is contained in:
@@ -306,6 +306,37 @@ export namespace Agent {
|
||||
}
|
||||
}
|
||||
|
||||
export interface TFPrompt {
|
||||
id: string
|
||||
label: string
|
||||
interpolation_string: string
|
||||
available_to_agents?: string[]
|
||||
}
|
||||
|
||||
async function loadTFPrompts(): Promise<TFPrompt[]> {
|
||||
const toolsPath = path.join(os.homedir(), ".tfcode", "tools.json")
|
||||
try {
|
||||
const content = await Bun.file(toolsPath).text()
|
||||
const data = JSON.parse(content)
|
||||
if (!data.success || !data.prompts) return []
|
||||
return data.prompts as TFPrompt[]
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export async function getPromptForAgent(agentId: string): Promise<TFPrompt | null> {
|
||||
const prompts = await loadTFPrompts()
|
||||
return prompts.find((p) => p.available_to_agents?.includes(agentId)) ?? null
|
||||
}
|
||||
|
||||
export async function getPromptForAgentName(agentName: string): Promise<TFPrompt | null> {
|
||||
const agents = await loadTFCoderAgents()
|
||||
const agent = agents.find((a) => a.name === agentName)
|
||||
if (!agent?.options?.tf_agent_id) return null
|
||||
return getPromptForAgent(agent.options.tf_agent_id)
|
||||
}
|
||||
|
||||
export async function list() {
|
||||
const cfg = await Config.get()
|
||||
const localAgents = await state()
|
||||
|
||||
@@ -14,7 +14,7 @@ const printError = (msg: string) => UI.error(msg)
|
||||
const success = (msg: string) => UI.println(UI.Style.TEXT_SUCCESS_BOLD + msg + UI.Style.TEXT_NORMAL)
|
||||
const info = (msg: string) => UI.println(UI.Style.TEXT_NORMAL + msg)
|
||||
|
||||
type ToolType = "mcp_server" | "agent_skill" | "database_script" | "api_function"
|
||||
type ToolType = "mcp_server" | "agent_skill" | "database_script" | "api_function" | "coder_agent" | "prompt"
|
||||
|
||||
interface SyncedTool {
|
||||
id: string
|
||||
@@ -28,11 +28,27 @@ interface SyncedTool {
|
||||
url?: string
|
||||
tools: string[]
|
||||
auth_via: string
|
||||
interpolation_string?: string
|
||||
goals?: string
|
||||
temperature?: number
|
||||
max_tokens?: number
|
||||
llm_base_model?: string
|
||||
llm_provider?: string
|
||||
}
|
||||
|
||||
interface SyncedPrompt {
|
||||
id: string
|
||||
label: string
|
||||
interpolation_string: string
|
||||
prompt_type?: string
|
||||
available_to_agents?: string[]
|
||||
description?: string
|
||||
}
|
||||
|
||||
interface ToolSyncResult {
|
||||
success: boolean
|
||||
tools: SyncedTool[]
|
||||
prompts: SyncedPrompt[]
|
||||
by_type: Record<string, number>
|
||||
error?: string
|
||||
}
|
||||
@@ -101,12 +117,30 @@ try:
|
||||
"request_type": tool.request_type.value if tool.request_type else None,
|
||||
"url": tool.url,
|
||||
"tools": tool.tools,
|
||||
"auth_via": tool.auth_via
|
||||
"auth_via": tool.auth_via,
|
||||
"interpolation_string": tool.interpolation_string,
|
||||
"goals": tool.goals,
|
||||
"temperature": tool.temperature,
|
||||
"max_tokens": tool.max_tokens,
|
||||
"llm_base_model": tool.llm_base_model,
|
||||
"llm_provider": tool.llm_provider
|
||||
})
|
||||
|
||||
prompts_data = []
|
||||
for prompt in result.prompts:
|
||||
prompts_data.append({
|
||||
"id": prompt.id,
|
||||
"label": prompt.label,
|
||||
"interpolation_string": prompt.interpolation_string,
|
||||
"prompt_type": prompt.prompt_type,
|
||||
"available_to_agents": prompt.available_to_agents,
|
||||
"description": prompt.description
|
||||
})
|
||||
|
||||
print(json.dumps({
|
||||
"success": result.success,
|
||||
"tools": tools_data,
|
||||
"prompts": prompts_data,
|
||||
"by_type": result.by_type,
|
||||
"error": result.error
|
||||
}))
|
||||
@@ -138,7 +172,13 @@ try:
|
||||
"request_type": tool.request_type.value if tool.request_type else None,
|
||||
"url": tool.url,
|
||||
"tools": tool.tools,
|
||||
"auth_via": tool.auth_via
|
||||
"auth_via": tool.auth_via,
|
||||
"interpolation_string": tool.interpolation_string,
|
||||
"goals": tool.goals,
|
||||
"temperature": tool.temperature,
|
||||
"max_tokens": tool.max_tokens,
|
||||
"llm_base_model": tool.llm_base_model,
|
||||
"llm_provider": tool.llm_provider
|
||||
})
|
||||
|
||||
print(json.dumps({
|
||||
@@ -353,6 +393,8 @@ const ToolsListCommand = cmd({
|
||||
agent_skill: "Skill",
|
||||
database_script: "DB",
|
||||
api_function: "API",
|
||||
coder_agent: "Coder Agent",
|
||||
prompt: "Prompt",
|
||||
}[tool.tool_type]
|
||||
|
||||
info(` ${tool.name}`)
|
||||
|
||||
@@ -13,6 +13,8 @@ import { useTerminalDimensions } from "@opentui/solid"
|
||||
import { Locale } from "@/util/locale"
|
||||
import type { PromptInfo } from "./history"
|
||||
import { useFrecency } from "./frecency"
|
||||
import { Agent } from "@/agent/agent"
|
||||
import { useLocal } from "@tui/context/local"
|
||||
|
||||
function removeLineRange(input: string) {
|
||||
const hashIndex = input.lastIndexOf("#")
|
||||
@@ -77,6 +79,7 @@ export function Autocomplete(props: {
|
||||
}) {
|
||||
const sdk = useSDK()
|
||||
const sync = useSync()
|
||||
const local = useLocal()
|
||||
const command = useCommandDialog()
|
||||
const { theme } = useTheme()
|
||||
const dimensions = useTerminalDimensions()
|
||||
@@ -353,6 +356,42 @@ export function Autocomplete(props: {
|
||||
)
|
||||
})
|
||||
|
||||
const tfPrompts = createMemo(() => {
|
||||
if (!store.visible || store.visible === "/") return []
|
||||
|
||||
const currentAgent = local.agent.current()
|
||||
const agentId = currentAgent.options?.tf_agent_id as string | undefined
|
||||
if (!agentId) return []
|
||||
|
||||
const options: AutocompleteOption[] = []
|
||||
const width = props.anchor().width - 4
|
||||
|
||||
const prompts = sync.data.prompts || []
|
||||
|
||||
for (const prompt of prompts) {
|
||||
const isAvailable =
|
||||
!prompt.available_to_agents ||
|
||||
prompt.available_to_agents.length === 0 ||
|
||||
prompt.available_to_agents.includes(agentId)
|
||||
|
||||
if (isAvailable) {
|
||||
options.push({
|
||||
display: Locale.truncateMiddle("@" + prompt.label, width),
|
||||
value: prompt.label,
|
||||
description: "Prompt template",
|
||||
onSelect: () => {
|
||||
const cursor = props.input().logicalCursor
|
||||
props.input().deleteRange(0, 0, cursor.row, cursor.col)
|
||||
props.input().insertText(prompt.interpolation_string)
|
||||
props.input().cursorOffset = Bun.stringWidth(prompt.interpolation_string)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
})
|
||||
|
||||
const commands = createMemo((): AutocompleteOption[] => {
|
||||
const results: AutocompleteOption[] = [...command.slashes()]
|
||||
|
||||
@@ -386,9 +425,12 @@ export function Autocomplete(props: {
|
||||
const filesValue = files()
|
||||
const agentsValue = agents()
|
||||
const commandsValue = commands()
|
||||
const promptsValue = tfPrompts()
|
||||
|
||||
const mixed: AutocompleteOption[] =
|
||||
store.visible === "@" ? [...agentsValue, ...(filesValue || []), ...mcpResources()] : [...commandsValue]
|
||||
store.visible === "@"
|
||||
? [...agentsValue, ...promptsValue, ...(filesValue || []), ...mcpResources()]
|
||||
: [...commandsValue]
|
||||
|
||||
const searchValue = search()
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ import { batch, onMount } from "solid-js"
|
||||
import { Log } from "@/util/log"
|
||||
import type { Path } from "@opencode-ai/sdk"
|
||||
import type { Workspace } from "@opencode-ai/sdk/v2"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
|
||||
export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
name: "Sync",
|
||||
@@ -75,6 +77,12 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
vcs: VcsInfo | undefined
|
||||
path: Path
|
||||
workspaceList: Workspace[]
|
||||
prompts: Array<{
|
||||
id: string
|
||||
label: string
|
||||
interpolation_string: string
|
||||
available_to_agents?: string[]
|
||||
}>
|
||||
}>({
|
||||
provider_next: {
|
||||
all: [],
|
||||
@@ -103,6 +111,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
vcs: undefined,
|
||||
path: { state: "", config: "", worktree: "", directory: "" },
|
||||
workspaceList: [],
|
||||
prompts: [],
|
||||
})
|
||||
|
||||
const sdk = useSDK()
|
||||
@@ -113,6 +122,19 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
setStore("workspaceList", reconcile(result.data))
|
||||
}
|
||||
|
||||
async function loadTFPrompts() {
|
||||
const toolsPath = path.join(os.homedir(), ".tfcode", "tools.json")
|
||||
try {
|
||||
const content = await Bun.file(toolsPath).text()
|
||||
const data = JSON.parse(content)
|
||||
if (data.success && data.prompts) {
|
||||
setStore("prompts", reconcile(data.prompts))
|
||||
}
|
||||
} catch {
|
||||
// File doesn't exist or is invalid, that's OK
|
||||
}
|
||||
}
|
||||
|
||||
sdk.event.listen((e) => {
|
||||
const event = e.details
|
||||
switch (event.type) {
|
||||
@@ -423,6 +445,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||
sdk.client.vcs.get().then((x) => setStore("vcs", reconcile(x.data))),
|
||||
sdk.client.path.get().then((x) => setStore("path", reconcile(x.data!))),
|
||||
syncWorkspaces(),
|
||||
loadTFPrompts(),
|
||||
]).then(() => {
|
||||
setStore("status", "complete")
|
||||
})
|
||||
|
||||
@@ -70,7 +70,7 @@ export namespace LLM {
|
||||
const system: string[] = []
|
||||
|
||||
// Build highlighted agent instructions for ToothFairyAI agents
|
||||
const tfHighlightedInstructions = buildTFAgentInstructions(input.agent)
|
||||
const tfHighlightedInstructions = await buildTFAgentInstructions(input.agent)
|
||||
|
||||
system.push(
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user