diff --git a/engine/baml-runtime/src/internal/llm_client/mod.rs b/engine/baml-runtime/src/internal/llm_client/mod.rs index cca2d2c24..1560f6405 100644 --- a/engine/baml-runtime/src/internal/llm_client/mod.rs +++ b/engine/baml-runtime/src/internal/llm_client/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use base64::write; use colored::*; pub mod llm_provider; pub mod orchestrator; @@ -162,10 +163,11 @@ impl std::fmt::Display for LLMCompleteResponse { f, "{}", format!( - "Client: {} ({}) - {}ms", + "Client: {} ({}) - {}ms. StopReason: {}", self.client, self.model, - self.latency.as_millis() + self.latency.as_millis(), + self.metadata.finish_reason.as_deref().unwrap_or("unknown") ) .yellow() )?; diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs index c593b43cc..b6a4ac481 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/openai/openai_client.rs @@ -369,7 +369,15 @@ impl SseResponseTrait for OpenAIClient { inner.metadata.finish_reason = Some(FinishReason::Stop.to_string()); } - _ => (), + finish_reason => { + log::info!( + "Received a non-stop finish reason: {:?}", + finish_reason + ); + inner.metadata.baml_is_complete = false; + inner.metadata.finish_reason = + finish_reason.as_ref().map(|r| r.to_string()); + } } } inner.latency = instant_start.elapsed(); @@ -529,6 +537,7 @@ fn convert_message_parts_to_content(parts: &Vec) -> serde_json: })}) } BamlMedia::Base64(BamlMediaType::Image, image) => { + // TODO: validate the media_type is present! json!({"type": "image_url", "image_url": json!({ "url" : format!("data:{};base64,{}", image.media_type, image.base64) })}) diff --git a/engine/baml-runtime/src/internal/llm_client/primitive/request.rs b/engine/baml-runtime/src/internal/llm_client/primitive/request.rs index c8a769307..3f4d904a2 100644 --- a/engine/baml-runtime/src/internal/llm_client/primitive/request.rs +++ b/engine/baml-runtime/src/internal/llm_client/primitive/request.rs @@ -74,7 +74,7 @@ pub async fn make_request( } }; - log::debug!("built request: {:?}", req); + log::debug!("LLM request: {:?} body: {:?}", req, req.body()); let response = match client.http_client().execute(req).await { Ok(response) => response, diff --git a/engine/baml-runtime/src/types/response.rs b/engine/baml-runtime/src/types/response.rs index 0ea4f033b..b98459a93 100644 --- a/engine/baml-runtime/src/types/response.rs +++ b/engine/baml-runtime/src/types/response.rs @@ -16,6 +16,14 @@ pub struct FunctionResult { impl std::fmt::Display for FunctionResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // print out the number of previous tries only if there was more than 1 + if self.event_chain.len() > 1 { + writeln!( + f, + "{}", + format!("({} other previous tries)", self.event_chain.len() - 1).yellow() + )?; + } writeln!(f, "{}", self.llm_response())?; match &self.parsed() { Some(Ok(val)) => { diff --git a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs index 6db56af36..23d8831c5 100644 --- a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs +++ b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs @@ -385,6 +385,7 @@ pub struct WasmLLMResponse { pub input_tokens: Option, pub output_tokens: Option, pub total_tokens: Option, + pub stop_reason: Option, } #[wasm_bindgen(getter_with_clone, inspectable)] @@ -604,6 +605,7 @@ impl IntoWasm input_tokens: s.metadata.prompt_tokens, output_tokens: s.metadata.output_tokens, total_tokens: s.metadata.total_tokens, + stop_reason: s.metadata.finish_reason.clone(), }), _ => None, } diff --git a/typescript/fiddle-frontend/app/[project_id]/_atoms/atoms.ts b/typescript/fiddle-frontend/app/[project_id]/_atoms/atoms.ts index 0ca5e5765..8c112720e 100644 --- a/typescript/fiddle-frontend/app/[project_id]/_atoms/atoms.ts +++ b/typescript/fiddle-frontend/app/[project_id]/_atoms/atoms.ts @@ -25,14 +25,22 @@ const activeFileNameAtomRaw = atomWithStorage('active_file', null export const activeFileNameAtom = atom( (get) => { const files = get(currentEditorFilesAtom) - // hack to get default file selection for now.. - const activeFileName = get(activeFileNameAtomRaw) ?? 'baml_src/01-extract-receipt.baml' - const selectedFile = files.find((f) => f.path === activeFileName) ?? files[0] + let activeFileName = get(activeFileNameAtomRaw) + // Validate the current active file or determine a new one + if (!activeFileName || !files.some((f) => f.path === activeFileName)) { + const defaultFile = 'baml_src/01-extract-receipt.baml' + const excludeFile = 'baml_src/clients.baml' + const alternativeFiles = files.filter((f) => f.path !== excludeFile).sort((a, b) => a.path.localeCompare(b.path)) - if (selectedFile) { - return selectedFile.path + // 1. Default file if available + // 2. First non-excluded file, sorted alphabetically + // 3. First file in the list as a last resort + activeFileName = files.find((f) => f.path === defaultFile)?.path || alternativeFiles[0]?.path || files[0]?.path } - return null + + // Find and return the selected file path or null if none are valid + const selectedFile = files.find((f) => f.path === activeFileName) + return selectedFile ? selectedFile.path : null }, (get, set, path: string) => { const files = get(currentEditorFilesAtom) diff --git a/typescript/fiddle-frontend/app/[project_id]/_components/CodeMirrorEditor.tsx b/typescript/fiddle-frontend/app/[project_id]/_components/CodeMirrorEditor.tsx index 2b2ffbdd9..2a30f44a4 100644 --- a/typescript/fiddle-frontend/app/[project_id]/_components/CodeMirrorEditor.tsx +++ b/typescript/fiddle-frontend/app/[project_id]/_components/CodeMirrorEditor.tsx @@ -121,6 +121,7 @@ function makeLinter() { message: err.message, severity: err.type === 'warning' ? 'warning' : 'error', source: 'baml', + markClass: err.type === 'error' ? 'decoration-wavy decoration-red-500 text-red-450 stroke-blue-500' : '', } }) ?? [] ) @@ -235,9 +236,9 @@ export const CodeMirrorEditor = ({ project }: { project: BAMLProject }) => { setUnsavedChanges(true) }} /> -
+
{numErrors.errors > 0 && ( -
+
{numErrors.errors} {numErrors.errors === 1 ? 'error' : 'errors'}
)} diff --git a/typescript/fiddle-frontend/app/globals.css b/typescript/fiddle-frontend/app/globals.css index 19d87e3fb..66056ca5d 100644 --- a/typescript/fiddle-frontend/app/globals.css +++ b/typescript/fiddle-frontend/app/globals.css @@ -84,7 +84,7 @@ /* controls dropdown styling on rsjf */ .form-control { -@apply bg-vscode-input-background text-vscode-input-foreground rounded-sm; + @apply bg-vscode-input-background text-vscode-input-foreground rounded-sm; } .array-item { @@ -279,3 +279,28 @@ background-color: var(--vscode-terminal-ansiWhite); opacity: 0.3; } + +#cw-widget-holder { + @apply left-0 ml-2; +} + +button.woot-widget-bubble:nth-child(1) { + @apply scale-50 origin-bottom-right left-0; +} + +button.woot-elements--right:nth-child(2) { + @apply scale-50 origin-bottom-right left-0; +} + +.cm-lintRange-error { + @apply decoration-wavy stroke-blue-500 !important; +} + +[class*='cm-lintRange-error'] { + background-image: none !important; + @apply underline underline-offset-2 decoration-wavy stroke-2 decoration-red-500 decoration-[1.2px] !important; +} + +.tok-typeName { + /* @apply decoration-green-400 bg-purple-500; */ +} diff --git a/typescript/fiddle-frontend/public/_examples/all-projects/baml_src/01-extract-receipt.baml b/typescript/fiddle-frontend/public/_examples/all-projects/baml_src/01-extract-receipt.baml index 37ec5347a..5ce654340 100644 --- a/typescript/fiddle-frontend/public/_examples/all-projects/baml_src/01-extract-receipt.baml +++ b/typescript/fiddle-frontend/public/_examples/all-projects/baml_src/01-extract-receipt.baml @@ -1,7 +1,7 @@ // This is a BAML file, which extends the Jinja2 templating language to write LLM functions. // Run a test to see how it works! -// How to call BAML functions from other languages: https://docs.boundaryml.com +// https://docs.boundaryml.com // We want the LLM to extract this info from an image receipt class Receipt { diff --git a/typescript/playground-common/src/baml_wasm_web/test_uis/test_result.tsx b/typescript/playground-common/src/baml_wasm_web/test_uis/test_result.tsx index f3d3ecdac..540b18baa 100644 --- a/typescript/playground-common/src/baml_wasm_web/test_uis/test_result.tsx +++ b/typescript/playground-common/src/baml_wasm_web/test_uis/test_result.tsx @@ -122,6 +122,7 @@ const LLMTestResult: React.FC<{ test: WasmTestResponse; doneStatus: DoneTestStat latency_ms: llm_response?.latency_ms, output_tokens: llm_response?.output_tokens, model: llm_response?.model, + stop_reason: llm_response?.stop_reason, }) const details = [ @@ -134,7 +135,8 @@ const LLMTestResult: React.FC<{ test: WasmTestResponse; doneStatus: DoneTestStat .filter((x) => x[0] !== undefined) .map((x) => x[1]) - const detailsText = details.length > 0 ? ` (${details.join(', ')})` : '' + const stopReasonText = llm_response?.stop_reason ? ` | StopReason: ${llm_response?.stop_reason} | ` : '' + const detailsText = details.length > 0 ? `${stopReasonText} (${details.join(', ')})` : '' return (
@@ -374,6 +376,12 @@ const TestStatusBanner: React.FC = () => { }) } + const isNextJS = (window as any).next?.version!! + if (isNextJS) { + // simplify UI in promptfiddle + return null + } + return (
diff --git a/typescript/playground-common/src/lib/feedback_widget.ts b/typescript/playground-common/src/lib/feedback_widget.ts index 2666e85a2..e1a6dd6c8 100644 --- a/typescript/playground-common/src/lib/feedback_widget.ts +++ b/typescript/playground-common/src/lib/feedback_widget.ts @@ -74,6 +74,7 @@ const loadChatwoot = () => { ;(window as any).chatwootSDK.run({ websiteToken: 'M4EXKvdb9NGgxqZzkTZfeFV7', baseUrl: BASE_URL, + position: 'left', }) } })(document, 'script') diff --git a/typescript/playground-common/src/shared/FunctionPanel.tsx b/typescript/playground-common/src/shared/FunctionPanel.tsx index 20e2c085b..09d0a78e9 100644 --- a/typescript/playground-common/src/shared/FunctionPanel.tsx +++ b/typescript/playground-common/src/shared/FunctionPanel.tsx @@ -21,8 +21,8 @@ const CurlSnippet: React.FC = () => { return (
-
-