feat(agent): add llm assistant chat with api tools (task 88)
OpenAI-compatible client with mock fallback, tool-calling loop, and /assistant UI. Tools map to /api/v1/ endpoints per ADR 0006 direct-tools decision.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import type { ChatCompletionRequest, ChatCompletionResult, LlmClient } from "./types";
|
||||
|
||||
function lastUserText(messages: ChatCompletionRequest["messages"]): string {
|
||||
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
||||
const message = messages[i];
|
||||
if (message?.role === "user" && message.content) {
|
||||
return message.content.toLowerCase();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function hadToolResults(messages: ChatCompletionRequest["messages"]): boolean {
|
||||
return messages.some((message) => message.role === "tool");
|
||||
}
|
||||
|
||||
export function createMockLlmClient(): LlmClient {
|
||||
return {
|
||||
async chatCompletion(request: ChatCompletionRequest): Promise<ChatCompletionResult> {
|
||||
const userText = lastUserText(request.messages);
|
||||
|
||||
if (hadToolResults(request.messages)) {
|
||||
return {
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: "Done — I updated your household data using the API.",
|
||||
},
|
||||
finishReason: "stop",
|
||||
};
|
||||
}
|
||||
|
||||
if (userText.includes("milk") && request.tools?.length) {
|
||||
return {
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: null,
|
||||
tool_calls: [
|
||||
{
|
||||
id: "mock_call_add_item",
|
||||
type: "function",
|
||||
function: {
|
||||
name: "add_list_item",
|
||||
arguments: JSON.stringify({
|
||||
listType: "shopping",
|
||||
text: "milk",
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
finishReason: "tool_calls",
|
||||
};
|
||||
}
|
||||
|
||||
if (userText.includes("calendar") && request.tools?.length) {
|
||||
const now = new Date();
|
||||
const from = new Date(now);
|
||||
from.setDate(from.getDate() - 1);
|
||||
const to = new Date(now);
|
||||
to.setDate(to.getDate() + 7);
|
||||
|
||||
return {
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: null,
|
||||
tool_calls: [
|
||||
{
|
||||
id: "mock_call_list_events",
|
||||
type: "function",
|
||||
function: {
|
||||
name: "list_events",
|
||||
arguments: JSON.stringify({
|
||||
from: from.toISOString(),
|
||||
to: to.toISOString(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
finishReason: "tool_calls",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
message: {
|
||||
role: "assistant",
|
||||
content:
|
||||
"I'm the famapp assistant (mock provider). Ask me to add items or check the calendar.",
|
||||
},
|
||||
finishReason: "stop",
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user