Skip to content

Commit 4d6eba8

Browse files
Joelclaude
andcommitted
Fix DM caller identity + add markdown tool format adapter
DM command now correctly uses persona's callerId: - Priority 1: params.callerId from persona tool context - Priority 2: params.personaId alternative - Priority 3: UserIdentityResolver fallback (human/CLI) This fixes the bug where Teacher AI calling DM tool created "Claude Code & Claude Code" instead of "Teacher AI & Claude Code". Also adds MarkdownToolAdapter to parse tool calls that local models (llama3.2-3b, etc.) produce in backtick format: `tool: collaboration/dm` `participants=helper` This format is now parsed alongside the standard XML formats. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8dd18b8 commit 4d6eba8

File tree

2 files changed

+126
-2
lines changed

2 files changed

+126
-2
lines changed

src/debug/jtag/commands/collaboration/dm/server/DmServerCommand.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,35 @@ export class DmServerCommand extends DmCommand {
8080

8181
/**
8282
* Resolve caller identity (who's initiating the DM)
83+
*
84+
* Priority:
85+
* 1. params.callerId - Persona tool execution context
86+
* 2. params.personaId - Alternative persona context
87+
* 3. UserIdentityResolver - Human/CLI context fallback
8388
*/
8489
private async resolveCallerIdentity(params: DmParams): Promise<{ id: UUID; entity: UserEntity }> {
90+
// Priority 1: Use callerId from persona tool context
91+
const callerIdFromParams = (params as any).callerId || (params as any).personaId;
92+
93+
if (callerIdFromParams) {
94+
const result = await Commands.execute<DataListParams<UserEntity>, DataListResult<UserEntity>>(
95+
DATA_COMMANDS.LIST,
96+
{
97+
collection: UserEntity.collection,
98+
filter: { id: callerIdFromParams },
99+
limit: 1,
100+
context: params.context,
101+
sessionId: params.sessionId
102+
}
103+
);
104+
105+
if (result.success && result.items && result.items.length > 0) {
106+
const user = result.items[0];
107+
return { id: user.id, entity: user };
108+
}
109+
}
110+
111+
// Priority 2: Fall back to UserIdentityResolver (human/CLI context)
85112
const identity = await UserIdentityResolver.resolve();
86113

87114
if (identity.exists && identity.userId) {

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

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,103 @@ Examples:
287287
}
288288
}
289289

290+
/**
291+
* Adapter for Markdown/Backtick format that local models (llama, etc.) often produce
292+
* Format: `tool: name` `param=value` `param2=value2`
293+
*
294+
* Examples:
295+
* - `tool: collaboration/dm` `participants=helper`
296+
* - `tool: read` `filepath=/path/to/file`
297+
*/
298+
export class MarkdownToolAdapter extends ToolFormatAdapter {
299+
readonly formatName = 'markdown-backtick';
300+
301+
formatToolsForPrompt(tools: ToolDefinition[]): string {
302+
// This adapter is for parsing, not prompting - use Anthropic format for prompts
303+
return '';
304+
}
305+
306+
formatResultsForContext(results: Array<{ toolName: string; success: boolean; content?: string; error?: string }>): string {
307+
return results.map(r => {
308+
if (r.success && r.content) {
309+
return `Tool '${r.toolName}' completed: ${r.content}`;
310+
} else {
311+
return `Tool '${r.toolName}' failed: ${r.error || 'Unknown error'}`;
312+
}
313+
}).join('\n\n');
314+
}
315+
316+
matches(text: string): ToolCallMatch[] {
317+
const matches: ToolCallMatch[] = [];
318+
319+
// Match patterns like: `tool: name` followed by optional params `key=value`
320+
// Strategy: Find all `tool: X` occurrences and capture until end of line or next tool
321+
const lines = text.split('\n');
322+
let currentMatch = '';
323+
let startIndex = 0;
324+
let charOffset = 0;
325+
326+
for (const line of lines) {
327+
const toolMatch = line.match(/`tool:\s*[^`]+`/i);
328+
329+
if (toolMatch) {
330+
// Save previous match if exists
331+
if (currentMatch) {
332+
matches.push({
333+
fullMatch: currentMatch.trim(),
334+
startIndex,
335+
endIndex: charOffset
336+
});
337+
}
338+
// Start new match
339+
currentMatch = line;
340+
startIndex = charOffset + (toolMatch.index || 0);
341+
} else if (currentMatch && line.includes('`') && line.includes('=')) {
342+
// Continue current match with param line
343+
currentMatch += ' ' + line;
344+
}
345+
346+
charOffset += line.length + 1; // +1 for newline
347+
}
348+
349+
// Don't forget last match
350+
if (currentMatch) {
351+
matches.push({
352+
fullMatch: currentMatch.trim(),
353+
startIndex,
354+
endIndex: charOffset
355+
});
356+
}
357+
358+
return matches;
359+
}
360+
361+
parse(match: ToolCallMatch): ToolCall | null {
362+
// Extract tool name from first backtick section
363+
const toolNameMatch = match.fullMatch.match(/`tool:\s*([^`]+)`/i);
364+
if (!toolNameMatch) {
365+
return null;
366+
}
367+
368+
const toolName = toolNameMatch[1].trim();
369+
const parameters: Record<string, string> = {};
370+
371+
// Extract all param=value pairs from subsequent backtick sections
372+
const paramRegex = /`([^`=]+)=([^`]*)`/g;
373+
let paramMatch: RegExpExecArray | null;
374+
375+
while ((paramMatch = paramRegex.exec(match.fullMatch)) !== null) {
376+
const paramName = paramMatch[1].trim();
377+
const paramValue = paramMatch[2].trim();
378+
if (paramName && paramName !== 'tool') {
379+
parameters[paramName] = paramValue;
380+
}
381+
}
382+
383+
return { toolName, parameters };
384+
}
385+
}
386+
290387
/**
291388
* Registry of all supported tool format adapters
292389
* Add new adapters here to support additional formats
@@ -296,8 +393,8 @@ Examples:
296393
export function getToolFormatAdapters(): ToolFormatAdapter[] {
297394
return [
298395
new AnthropicStyleToolAdapter(), // Primary/default format
299-
new OldStyleToolAdapter() // Legacy support
300-
// Add new adapters here for future formats
396+
new MarkdownToolAdapter(), // Local model backtick format
397+
new OldStyleToolAdapter() // Legacy XML support
301398
];
302399
}
303400

0 commit comments

Comments
 (0)