Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"eslint": "^9.39.2",
"eslint-plugin-vue": "^10.6.2",
"globals": "^17.0.0",
"gui-chat-protocol": "^0.0.1",
"gui-chat-protocol": "^0.0.2",
"tailwindcss": "^4.1.18",
"typescript": "~5.9.3",
"vite": "^7.3.1",
Expand Down
31 changes: 24 additions & 7 deletions src/core/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
*/

import type { ToolDefinition } from "gui-chat-protocol";
import { getRoles } from "./roles";
import type { Role } from "./types";

export const TOOL_NAME = "switchRole";

/**
* Create tool definition with current roles
* This needs to be called dynamically since roles can be configured
* Create tool definition with specific roles
* @param roles - Array of available roles
*/
export function createToolDefinition(): ToolDefinition {
const roles = getRoles();
export function createToolDefinition(roles: Role[]): ToolDefinition {
const roleIds = roles.map((r) => r.id);
const roleOptionsDescription = roles
.map((r) => `'${r.id}' (${r.name})`)
Expand All @@ -36,7 +35,25 @@ export function createToolDefinition(): ToolDefinition {
};
}

// Default tool definition using default roles
export const TOOL_DEFINITION: ToolDefinition = createToolDefinition();
/**
* Default tool definition (used when roles are not provided)
* Apps should use createToolDefinition() with their roles for better LLM guidance
*/
export const TOOL_DEFINITION: ToolDefinition = {
type: "function",
name: TOOL_NAME,
description:
"Switch the system prompt role and reconnect to the LLM. This changes the AI's personality and behavior.",
parameters: {
type: "object",
properties: {
role: {
type: "string",
description: "The role ID to switch to",
},
},
required: ["role"],
},
};

export const SYSTEM_PROMPT = `When users ask to change the role, personality, or behavior of the AI (e.g., 'switch to tutor role', 'change to listener role', 'be a teacher'), use the ${TOOL_NAME} function. Note that switching roles will disconnect and reconnect the conversation.`;
3 changes: 0 additions & 3 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
// Export plugin-specific types
export type { Role, SwitchRoleArgs, SwitchRoleJsonData } from "./types";

// Export role configuration
export { DEFAULT_ROLES, setRoles, getRoles, getRoleById } from "./roles";

// Export plugin utilities
export {
TOOL_NAME,
Expand Down
59 changes: 42 additions & 17 deletions src/core/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,61 @@
*/

import type { ToolPluginCore, ToolContext, ToolResult } from "gui-chat-protocol";
import type { SwitchRoleArgs, SwitchRoleJsonData } from "./types";
import type { Role, SwitchRoleArgs, SwitchRoleJsonData } from "./types";
import { TOOL_DEFINITION, SYSTEM_PROMPT } from "./definition";
import { getRoles, getRoleById } from "./roles";

// Re-export for convenience
export { TOOL_NAME, TOOL_DEFINITION, SYSTEM_PROMPT, createToolDefinition } from "./definition";
export { DEFAULT_ROLES, setRoles, getRoles, getRoleById } from "./roles";

/**
* Extended ToolContext with role-related app functions
*/
interface SwitchRoleToolContext extends ToolContext {
app?: ToolContext["app"] & {
getRoles?: () => Role[];
switchRole?: (roleId: string) => void;
};
}

/**
* Get roles from context.app (provided by the host app)
*/
function getRolesFromContext(context: SwitchRoleToolContext): Role[] {
if (typeof context.app?.getRoles === "function") {
return context.app.getRoles();
}
console.warn(
"switchRole: context.app.getRoles() not available, returning empty roles",
);
return [];
}

/**
* Get role by ID from context
*/
function getRoleByIdFromContext(
context: SwitchRoleToolContext,
id: string,
): Role | undefined {
const roles = getRolesFromContext(context);
return roles.find((role) => role.id === id);
}

/**
* Execute the switchRole function
* Triggers a role switch via the app layer
*/
export const executeSwitchRole = async (
_context: ToolContext,
context: SwitchRoleToolContext,
args: SwitchRoleArgs,
): Promise<ToolResult<unknown, SwitchRoleJsonData>> => {
const { role } = args;
const roles = getRoles();
const roles = getRolesFromContext(context);
const availableRolesSummary = roles.map((r) => `${r.id} (${r.name})`).join(", ");

try {
// Validate role
const validRole = getRoleById(role);
const validRole = getRoleByIdFromContext(context, role);
if (!validRole) {
return {
message: `Invalid role: ${role}`,
Expand All @@ -38,21 +70,14 @@ export const executeSwitchRole = async (
};
}

// Call switchRole asynchronously (don't await)
const globalObject = globalThis as typeof globalThis & {
switchRole?: (selectedRole: string) => void;
};

if (
typeof window !== "undefined" &&
typeof globalObject.switchRole === "function"
) {
// Call switchRole via context.app (provided by the host app)
if (typeof context.app?.switchRole === "function") {
// Fire and forget - this will disconnect and reconnect
setTimeout(() => {
globalObject.switchRole?.(role);
context.app?.switchRole?.(role);
}, 0);
} else {
console.error("switchRole function not found on window object");
console.error("switchRole: context.app.switchRole() not available");
return {
message: "Failed to switch role: switchRole API not available",
jsonData: {
Expand Down
32 changes: 0 additions & 32 deletions src/core/roles.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/vue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ export {
createToolDefinition,
executeSwitchRole,
pluginCore,
DEFAULT_ROLES,
setRoles,
getRoles,
getRoleById,
} from "../core/plugin";

export { Preview };
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1145,10 +1145,10 @@ graceful-fs@^4.2.4:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==

gui-chat-protocol@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/gui-chat-protocol/-/gui-chat-protocol-0.0.1.tgz#d0770d03a6669b075473a0d8753ca9506f718dcd"
integrity sha512-FStQbzQ7gvjDugWAmf4IOsvhqxe8/DUdA9VK9PgXwi44J2lZyEd1ww1bhThoHXpXT4djFpayQ2uMO1YMtQhCqA==
gui-chat-protocol@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/gui-chat-protocol/-/gui-chat-protocol-0.0.2.tgz#96ce2b565dcc3908a8cb0aa024be842ee6513391"
integrity sha512-Hn/+iwbvbYF+HL8siDKCRxUYZBYT6FyhiMa/kL4EF0BCoF55e65yAtpZdAxUBebfT5VXZvgp+/DCIC3i0RPuLw==

has-flag@^4.0.0:
version "4.0.0"
Expand Down