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
4 changes: 2 additions & 2 deletions agents/nextjs/guardrails/example/app/api/agent/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import type { ConversationConfig } from "@elevenlabs/elevenlabs-js/api/types/ConversationConfig";
import { ClientEvent } from "@elevenlabs/elevenlabs-js/api/types/ClientEvent";
import type { ConversationConfigInput } from "@elevenlabs/elevenlabs-js/api/types/ConversationConfigInput";
import { NextResponse } from "next/server";

const DEMO_AGENT_NAME = "Guardrails Demo Voice";
Expand Down Expand Up @@ -57,7 +57,7 @@ export async function POST() {
const { client, error } = getClient();
if (error) return error;

const clientEvents: NonNullable<ConversationConfig["clientEvents"]> = [
const clientEvents: NonNullable<ConversationConfigInput["clientEvents"]> = [
ClientEvent.Audio,
ClientEvent.Interruption,
ClientEvent.UserTranscript,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ export async function GET(request: Request) {
const client = new ElevenLabsClient({ apiKey });

try {
const { token } =
await client.conversationalAi.conversations.getWebrtcToken({
const { signedUrl } =
await client.conversationalAi.conversations.getSignedUrl({
agentId,
});
return NextResponse.json({ token });
return NextResponse.json({ signedUrl });
} catch (e) {
const message =
e instanceof Error ? e.message : "Failed to create conversation token.";
e instanceof Error ? e.message : "Failed to create signed URL.";
return NextResponse.json({ error: message }, { status: 502 });
}
}
13 changes: 7 additions & 6 deletions agents/nextjs/guardrails/example/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,15 @@ function GuardrailsPage({
const res = await fetch(
`/api/conversation-token?agentId=${encodeURIComponent(trimmedId)}`
);
const data: { token?: string; error?: string } = await res.json();
if (!res.ok || !data.token) {
setSessionError(data.error ?? "Could not get conversation token.");
const data: { signedUrl?: string; error?: string } = await res.json();
if (!res.ok || !data.signedUrl) {
setSessionError(data.error ?? "Could not get signed URL.");
return;
}

await startSession({
conversationToken: data.token,
connectionType: "websocket",
signedUrl: data.signedUrl,
});
} catch (error) {
const nextMessage =
Expand Down Expand Up @@ -195,11 +196,11 @@ function GuardrailsPage({
<p className="text-sm text-red-600">{lookupError}</p>
) : null}

<div className="rounded-md border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm text-neutral-700">
<div className="space-y-1 text-sm text-neutral-700">
<p className="font-medium text-neutral-900">
Try asking for investment advice
</p>
<p className="mt-1 text-xs text-neutral-500">
<p className="text-xs text-neutral-500">
Example questions: &quot;What should I invest ten thousand dollars
in right now?&quot; or &quot;Should I buy Bitcoin or index funds
this month?&quot; If the agent crosses the line into investment
Expand Down
34 changes: 17 additions & 17 deletions agents/nextjs/guardrails/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,32 @@
"lint": "eslint"
},
"dependencies": {
"@elevenlabs/elevenlabs-js": "^2.43.0",
"@elevenlabs/react": "^1.1.0",
"@elevenlabs/elevenlabs-js": "^2.51.0",
"@elevenlabs/react": "^1.6.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.575.0",
"next": "16.1.6",
"lucide-react": "^1.17.0",
"next": "16.2.7",
"radix-ui": "^1.4.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"tailwind-merge": "^3.5.0"
"react": "19.2.7",
"react-dom": "19.2.7",
"tailwind-merge": "^3.6.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"shadcn": "^3.8.5",
"tailwindcss": "^4",
"@tailwindcss/postcss": "^4.3.0",
"@types/node": "^25.9.1",
"@types/react": "^19.2.16",
"@types/react-dom": "^19.2.3",
"eslint": "^9.39.4",
"eslint-config-next": "16.2.7",
"shadcn": "^4.10.0",
"tailwindcss": "^4.3.0",
"tw-animate-css": "^1.4.0",
"typescript": "^5"
"typescript": "^6.0.3"
},
"pnpm": {
"overrides": {
"livekit-client": "2.16.1"
"livekit-client": "2.19.1"
}
}
}
2 changes: 1 addition & 1 deletion agents/nextjs/guardrails/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ node -e "
delete pkg.dependencies['@elevenlabs/client'];
pkg.pnpm = pkg.pnpm || {};
pkg.pnpm.overrides = pkg.pnpm.overrides || {};
pkg.pnpm.overrides['livekit-client'] = '2.16.1';
pkg.pnpm.overrides['livekit-client'] = '2.19.1';
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"

Expand Down
4 changes: 2 additions & 2 deletions speech-engine/nextjs/quickstart/PROMPT.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Before writing any code, invoke the `/speech-engine` skill to learn the correct

## 6. `lib/assistant.ts`

- Shared OpenAI Responses API helpers: `ASSISTANT_INSTRUCTIONS`, `VOICE_FIRST_MESSAGE`, `isChatRole`, `normalizeChatMessages`, `transcriptToChatMessages`, `createAssistantReply(messages, signal)`, and `createAssistantStream(messages, signal)`.
- Shared OpenAI Responses API helpers: `ASSISTANT_INSTRUCTIONS`, `isChatRole`, `normalizeChatMessages`, `transcriptToChatMessages`, `createAssistantReply(messages, signal)`, and `createAssistantStream(messages, signal)`.
- Map Speech Engine `agent` role to OpenAI `assistant`; keep responses concise.
- Normalize history before sending it to OpenAI: trim content, drop empty messages, cap message count and per-message length.

Expand Down Expand Up @@ -74,7 +74,7 @@ Before writing any code, invoke the `/speech-engine` skill to learn the correct
- Build a single chat UI that works like a normal assistant chat first, then can switch into voice mode without losing context.
- Keep one `messages` state array with `{ id, role: "user" | "assistant", content, channel: "chat" | "voice", pending?, error? }`.
- Text submit path: append the user message, POST the full normalized history to `/api/chat`, replace the pending assistant message with the reply, and keep the composer usable.
- Voice start path: request microphone access, POST current non-pending/non-error chat history to `/api/voice-history`, fetch `/api/token`, then `startSession({ conversationToken: token, overrides: { agent: { firstMessage: VOICE_FIRST_MESSAGE } }, onConversationCreated })`.
- Voice start path: request microphone access, POST current non-pending/non-error chat history to `/api/voice-history`, fetch `/api/token`, then start the voice session with an inline `overrides.agent.firstMessage` greeting.
- In `onConversationCreated`, link the stored `historyId` to `voiceConversation.getId()` with `/api/voice-history/link`; if useful, also send a contextual update summarizing recent typed chat.
- Voice event path: use `useConversation({ onMessage })` to append or update transcript messages in the same `messages` array, mapping SDK role `agent` to local role `assistant`.
- While voice is connected, allow typed messages too: append them to the same thread and call `conversation.sendUserMessage(content)`; avoid duplicating echoes from `onMessage`.
Expand Down
4 changes: 1 addition & 3 deletions speech-engine/nextjs/quickstart/example/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import {
type KeyboardEvent,
} from "react";

import { VOICE_FIRST_MESSAGE } from "@/lib/assistant-constants";

type DemoRole = "user" | "assistant";
type DemoChannel = "chat" | "voice";

Expand Down Expand Up @@ -379,7 +377,7 @@ function ConversationView() {
conversationToken: token,
overrides: {
agent: {
firstMessage: VOICE_FIRST_MESSAGE,
firstMessage: "Hello! How can I help you today?",
},
},
onConversationCreated: voiceConversation => {
Expand Down

This file was deleted.

Loading