Skip to content

Commit e4a9c9c

Browse files
committed
Fix AI tool format parsing + git author attribution
ToolFormatAdapter: - Add FunctionStyleToolAdapter for <function=name>{json}</function> format - Supports Groq, Together, and other models that use this style - JSON parameter parsing with fallback to key=value Git config: - Remove local user.name/user.email override (was "DeepSeek Assistant") - Now uses global config (joelteply)
1 parent 40f675f commit e4a9c9c

File tree

5 files changed

+88
-5
lines changed

5 files changed

+88
-5
lines changed

src/debug/jtag/generated-command-schemas.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"generated": "2026-02-10T01:53:14.232Z",
2+
"generated": "2026-02-10T02:14:41.861Z",
33
"version": "1.0.0",
44
"commands": [
55
{

src/debug/jtag/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/debug/jtag/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@continuum/jtag",
3-
"version": "1.0.7752",
3+
"version": "1.0.7754",
44
"description": "Global CLI debugging system for any Node.js project. Install once globally, use anywhere: npm install -g @continuum/jtag",
55
"config": {
66
"active_example": "widget-ui",

src/debug/jtag/shared/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
* DO NOT EDIT MANUALLY
44
*/
55

6-
export const VERSION = '1.0.7752';
6+
export const VERSION = '1.0.7754';
77
export const PACKAGE_NAME = '@continuum/jtag';

src/debug/jtag/system/user/server/modules/ToolFormatAdapter.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,88 @@ export class MarkdownToolAdapter extends ToolFormatAdapter {
400400
}
401401
}
402402

403+
/**
404+
* Adapter for OpenAI/Generic function-call style format
405+
* Format: <function=tool_name>{"param": "value"}</function>
406+
*
407+
* This is what Groq, Together, and some other models naturally produce.
408+
* Examples from chat:
409+
* - <function=adapter_search> {"query": "embedding module"} </function>
410+
* - <function=code/search>{"query": "memory clustering"}</function>
411+
*/
412+
export class FunctionStyleToolAdapter extends ToolFormatAdapter {
413+
readonly formatName = 'function-style';
414+
415+
formatToolsForPrompt(tools: ToolDefinition[]): string {
416+
// Use Anthropic format for prompting, this is just for parsing
417+
return '';
418+
}
419+
420+
formatResultsForContext(results: Array<{ toolName: string; success: boolean; content?: string; error?: string }>): string {
421+
return results.map(r => {
422+
if (r.success && r.content) {
423+
return `<function_result name="${r.toolName}" status="success">\n${r.content}\n</function_result>`;
424+
} else {
425+
return `<function_result name="${r.toolName}" status="error">\n${r.error || 'Unknown error'}\n</function_result>`;
426+
}
427+
}).join('\n\n');
428+
}
429+
430+
matches(text: string): ToolCallMatch[] {
431+
const matches: ToolCallMatch[] = [];
432+
// Match <function=name>...</function> or <function=name> {...} </function>
433+
const regex = /<function=([^>\s]+)>\s*([\s\S]*?)\s*<\/function>/gi;
434+
435+
let match: RegExpExecArray | null;
436+
while ((match = regex.exec(text)) !== null) {
437+
matches.push({
438+
fullMatch: match[0],
439+
startIndex: match.index,
440+
endIndex: regex.lastIndex
441+
});
442+
}
443+
444+
return matches;
445+
}
446+
447+
parse(match: ToolCallMatch): ToolCall | null {
448+
// Extract tool name from <function=NAME>
449+
const nameMatch = match.fullMatch.match(/<function=([^>\s]+)>/i);
450+
if (!nameMatch) {
451+
return null;
452+
}
453+
454+
const toolName = nameMatch[1].trim();
455+
const parameters: Record<string, string> = {};
456+
457+
// Extract JSON body between the tags
458+
const bodyMatch = match.fullMatch.match(/<function=[^>]+>\s*([\s\S]*?)\s*<\/function>/i);
459+
if (bodyMatch && bodyMatch[1]) {
460+
const jsonStr = bodyMatch[1].trim();
461+
if (jsonStr) {
462+
try {
463+
const parsed = JSON.parse(jsonStr);
464+
// Flatten to string values for consistency with other adapters
465+
for (const [key, value] of Object.entries(parsed)) {
466+
parameters[key] = typeof value === 'string' ? value : JSON.stringify(value);
467+
}
468+
} catch {
469+
// If not valid JSON, try key=value parsing
470+
const kvMatch = jsonStr.match(/["']?(\w+)["']?\s*[:=]\s*["']?([^"',}]+)["']?/g);
471+
if (kvMatch) {
472+
for (const kv of kvMatch) {
473+
const [k, v] = kv.split(/[:=]/).map(s => s.trim().replace(/["']/g, ''));
474+
if (k && v) parameters[k] = v;
475+
}
476+
}
477+
}
478+
}
479+
}
480+
481+
return { toolName, parameters };
482+
}
483+
}
484+
403485
/**
404486
* Registry of all supported tool format adapters
405487
* Add new adapters here to support additional formats
@@ -409,6 +491,7 @@ export class MarkdownToolAdapter extends ToolFormatAdapter {
409491
export function getToolFormatAdapters(): ToolFormatAdapter[] {
410492
return [
411493
new AnthropicStyleToolAdapter(), // Primary/default format
494+
new FunctionStyleToolAdapter(), // OpenAI/Groq/Together function style
412495
new MarkdownToolAdapter(), // Local model backtick format
413496
new OldStyleToolAdapter() // Legacy XML support
414497
];

0 commit comments

Comments
 (0)