Skip to content

Commit 6d0b9ef

Browse files
update
1 parent a0b9da0 commit 6d0b9ef

File tree

4 files changed

+23
-7
lines changed

4 files changed

+23
-7
lines changed

examples/09-vapi.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ If you cannot help, offer to transfer to a human agent.`,
129129
// The assistant's response (what Vapi's AI would say)
130130
const assistantResponse = "I'd be happy to help you reset your password! Let me look into why you didn't receive the reset email. Can you confirm the email address associated with your account?";
131131

132+
// IMPORTANT: outputData must be a structured object (not a bare string) so it
133+
// survives the backend's JSONB serialization round-trip. The optimization pipeline
134+
// extracts the answer from output_data.content — a plain string like
135+
// outputData: assistantResponse will be lost during JSON parsing and cause
136+
// "No valid examples to train on" errors.
137+
132138
// Build the zeroeval metadata object for span attributes
133139
// This is what links the span to the prompt for feedback
134140
const spanZeroEvalMetadata = {
@@ -160,10 +166,13 @@ If you cannot help, offer to transfer to a human agent.`,
160166
messages: conversationMessages,
161167
streaming: false,
162168
},
163-
// Input should be the messages array (system + user messages)
164-
inputData: JSON.stringify(conversationMessages),
165-
// Output should be just the assistant's response
166-
outputData: assistantResponse,
169+
// Input: pass the messages array directly (SDK will JSON.stringify objects automatically)
170+
inputData: conversationMessages,
171+
// Output: MUST be a structured object, not a bare string.
172+
// The backend extracts the answer via output_data.get("content").
173+
// A plain string (e.g. outputData: "some text") fails JSONB round-trip parsing
174+
// and causes all optimization examples to be skipped.
175+
outputData: { role: 'assistant', content: assistantResponse },
167176
},
168177
async () => {
169178
// Capture span ID for feedback

src/observability/promptClient.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class PromptClient {
8484
content: response.content,
8585
version: response.version,
8686
versionId: response.version_id,
87+
promptSlug: response.prompt || null,
8788
tag: response.tag,
8889
isLatest: response.is_latest,
8990
model: response.model_id

src/prompt.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,14 @@ export async function prompt(options: PromptOptions): Promise<string> {
129129
// Pull linkage metadata for decoration
130130
let promptSlug: string | null = null;
131131
try {
132-
const metadata = promptObj.metadata || {};
133-
promptSlug =
134-
(metadata.prompt_slug as string) ?? (metadata.prompt as string) ?? null;
132+
// Prefer the prompt slug from the response (top-level field)
133+
promptSlug = promptObj.promptSlug ?? null;
134+
// Fallback to version metadata if not available
135+
if (!promptSlug) {
136+
const metadata = promptObj.metadata || {};
137+
promptSlug =
138+
(metadata.prompt_slug as string) ?? (metadata.prompt as string) ?? null;
139+
}
135140
} catch {
136141
promptSlug = null;
137142
}

src/types/prompt.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface Prompt {
3030
content: string;
3131
version: number | null;
3232
versionId: string | null;
33+
promptSlug: string | null;
3334
tag: string | null;
3435
isLatest: boolean;
3536
model: string | null;

0 commit comments

Comments
 (0)