feat: add /new slash command to create chat sessions
Introduces a `/new` slash command that lets users create a fresh chat session for the current agent without leaving the chat input. - Add `createNewSession` to `useGateway` that calls `sessions.create` on the gateway (with a client-side fallback key when the RPC is unavailable). - Register `/new` in the slash-command menu with i18n descriptions across all 8 supported languages. - Wire `onNewSession` through `Chat` → `ChatInput` so typing `/new` triggers session creation. - Add `extractAgentIdFromKey` and `formatAgentId` helpers to `sessionName.ts` to derive a human-readable agent name from the session key (e.g. `agent:my-cool-bot:…` → "My Cool Bot"). - Use the new helpers in `Header` and `App` to show per-session agent names, especially for sub-agent sessions where the gateway-level identity differs from the session agent. Made-with: Cursor
This commit is contained in:
@@ -5,6 +5,7 @@ import { getStoredCredentials, storeCredentials, clearCredentials, type AuthMode
|
||||
import { getOrCreateDeviceIdentity } from '../lib/deviceIdentity';
|
||||
import { isSystemEvent } from '../lib/systemEvent';
|
||||
import { getCachedMessages, setCachedMessages, mergeWithCache } from '../lib/messageCache';
|
||||
import { extractAgentIdFromKey } from '../lib/sessionName';
|
||||
import { extractText, extractThinking, type ChatPayloadMessage } from '../lib/messageExtract';
|
||||
import type { ChatMessage, MessageBlock, ConnectionStatus, Session, AgentIdentity } from '../types';
|
||||
|
||||
@@ -23,9 +24,12 @@ export function useGateway() {
|
||||
const messagesRef = useRef(messages);
|
||||
const activeSessionRef = useRef(activeSession);
|
||||
|
||||
const sessionsRef = useRef(sessions);
|
||||
|
||||
// Sync refs in an effect to avoid ref writes during render
|
||||
useEffect(() => { messagesRef.current = messages; }, [messages]);
|
||||
useEffect(() => { activeSessionRef.current = activeSession; }, [activeSession]);
|
||||
useEffect(() => { sessionsRef.current = sessions; }, [sessions]);
|
||||
const currentRunIdRef = useRef<string | null>(null);
|
||||
const [activeSessions, setActiveSessions] = useState<Set<string>>(new Set());
|
||||
const [unreadSessions, setUnreadSessions] = useState<Map<string, number>>(new Map());
|
||||
@@ -480,6 +484,48 @@ export function useGateway() {
|
||||
loadHistory(key);
|
||||
}, [loadHistory]);
|
||||
|
||||
const createNewSession = useCallback(async () => {
|
||||
const client = clientRef.current;
|
||||
if (!client) return;
|
||||
|
||||
const currentKey = activeSessionRef.current;
|
||||
const currentSession = sessionsRef.current.find((s) => s.key === currentKey);
|
||||
const targetAgentId = currentSession?.agentId || extractAgentIdFromKey(currentKey) || 'main';
|
||||
const targetChannel = currentSession?.channel || 'webchat';
|
||||
const expectedPrefix = `agent:${targetAgentId}:`;
|
||||
|
||||
const fallbackKey = `${expectedPrefix}webchat-${Date.now()}`;
|
||||
let nextKey = fallbackKey;
|
||||
|
||||
try {
|
||||
const res = await client.send('sessions.create', {
|
||||
channel: targetChannel,
|
||||
agentId: targetAgentId,
|
||||
}) as JsonPayload | undefined;
|
||||
const fromRoot = (typeof res?.key === 'string' && res.key)
|
||||
|| (typeof res?.sessionKey === 'string' && res.sessionKey)
|
||||
|| null;
|
||||
const nestedSession = (res?.session && typeof res.session === 'object') ? res.session as Record<string, unknown> : null;
|
||||
const fromNested = (nestedSession && typeof nestedSession.key === 'string' && nestedSession.key)
|
||||
|| (nestedSession && typeof nestedSession.sessionKey === 'string' && nestedSession.sessionKey)
|
||||
|| null;
|
||||
|
||||
const returnedKey = (fromRoot || fromNested) as string | null;
|
||||
if (returnedKey && returnedKey.startsWith(expectedPrefix)) {
|
||||
nextKey = returnedKey;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[createNewSession] sessions.create not supported, using fallback key', err);
|
||||
}
|
||||
|
||||
switchSession(nextKey);
|
||||
try {
|
||||
await loadSessions();
|
||||
} catch (err) {
|
||||
console.warn('[createNewSession] failed to refresh session list', err);
|
||||
}
|
||||
}, [switchSession, loadSessions]);
|
||||
|
||||
const login = useCallback((url: string, token: string, authMode: AuthMode = 'token', clientId?: string) => {
|
||||
setupClient(url, token, authMode, clientId);
|
||||
}, [setupClient]);
|
||||
@@ -541,7 +587,7 @@ export function useGateway() {
|
||||
|
||||
return {
|
||||
status, messages, sessions: enrichedSessions, activeSession, isGenerating, isLoadingHistory,
|
||||
sendMessage, abort, switchSession, loadSessions, deleteSession,
|
||||
sendMessage, abort, switchSession, createNewSession, loadSessions, deleteSession,
|
||||
authenticated, login, logout, connectError, isConnecting, agentIdentity,
|
||||
getClient, addEventListener,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user