diff --git a/integ-tests/baml_src/test-files/strategies/fallback.baml b/integ-tests/baml_src/test-files/strategies/fallback.baml index 0ab4855e6..7778a3640 100644 --- a/integ-tests/baml_src/test-files/strategies/fallback.baml +++ b/integ-tests/baml_src/test-files/strategies/fallback.baml @@ -16,12 +16,9 @@ client FallbackClient { FaultyClient Lottery_SimpleSyntax - // FaultyClient, - // RetryClientConstant - // RetryClientExponential - // Gemini SecondaryFallback + TertiaryFallback ] } @@ -33,8 +30,18 @@ client SecondaryFallback { strategy [ FaultyClient RetryClientExponential - // RetryClientConstant - // GPT4 + + ] + } +} + +client TertiaryFallback { + provider fallback + options { + strategy [ + FaultyClient + RetryClientExponential + ] } } diff --git a/integ-tests/python/baml_client/client.py b/integ-tests/python/baml_client/client.py index 447f8d86b..6e24fc636 100644 --- a/integ-tests/python/baml_client/client.py +++ b/integ-tests/python/baml_client/client.py @@ -1544,6 +1544,30 @@ async def TestRetryExponential( mdl = create_model("TestRetryExponentialReturnType", inner=(str, ...)) return coerce(mdl, raw.parsed()) + async def TestRoundRobin( + self, + + baml_options: BamlCallOptions = {}, + ) -> str: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = await self.__runtime.call_function( + "TestRoundRobin", + { + + }, + self.__ctx_manager.get(), + tb, + __cr__, + ) + mdl = create_model("TestRoundRobinReturnType", inner=(str, ...)) + return coerce(mdl, raw.parsed()) + async def TestVertex( self, input: str, @@ -3650,9 +3674,9 @@ def TestRetryExponential( self.__ctx_manager.get(), ) - def TestVertex( + def TestRoundRobin( self, - input: str, + baml_options: BamlCallOptions = {}, ) -> baml_py.BamlStream[Optional[str], str]: __tb__ = baml_options.get("tb", None) @@ -3663,9 +3687,8 @@ def TestVertex( __cr__ = baml_options.get("client_registry", None) raw = self.__runtime.stream_function( - "TestVertex", + "TestRoundRobin", { - "input": input, }, None, self.__ctx_manager.get(), @@ -3673,8 +3696,8 @@ def TestVertex( __cr__, ) - mdl = create_model("TestVertexReturnType", inner=(str, ...)) - partial_mdl = create_model("TestVertexPartialReturnType", inner=(Optional[str], ...)) + mdl = create_model("TestRoundRobinReturnType", inner=(str, ...)) + partial_mdl = create_model("TestRoundRobinPartialReturnType", inner=(Optional[str], ...)) return baml_py.BamlStream[Optional[str], str]( raw, @@ -3683,9 +3706,9 @@ def TestVertex( self.__ctx_manager.get(), ) - def TestRoundRobin( + def TestVertex( self, - + input: str, baml_options: BamlCallOptions = {}, ) -> baml_py.BamlStream[Optional[str], str]: __tb__ = baml_options.get("tb", None) @@ -3693,25 +3716,27 @@ def TestRoundRobin( tb = __tb__._tb else: tb = None + __cr__ = baml_options.get("client_registry", None) raw = self.__runtime.stream_function( - "TestRoundRobin", + "TestVertex", { + "input": input, }, None, self.__ctx_manager.get(), tb, + __cr__, ) - mdl = create_model("TestRoundRobinReturnType", inner=(str, ...)) - partial_mdl = create_model("TestRoundRobinPartialReturnType", inner=(Optional[str], ...)) + mdl = create_model("TestVertexReturnType", inner=(str, ...)) + partial_mdl = create_model("TestVertexPartialReturnType", inner=(Optional[str], ...)) return baml_py.BamlStream[Optional[str], str]( raw, lambda x: coerce(partial_mdl, x), lambda x: coerce(mdl, x), self.__ctx_manager.get(), - tb, ) def UnionTest_Function( diff --git a/integ-tests/python/baml_client/inlinedbaml.py b/integ-tests/python/baml_client/inlinedbaml.py index 2945ed34c..a4d500413 100644 --- a/integ-tests/python/baml_client/inlinedbaml.py +++ b/integ-tests/python/baml_client/inlinedbaml.py @@ -16,7 +16,7 @@ file_map = { - "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider openai\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient GPT35LegacyProvider {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options {\n model gemini-1.5-pro-001\n api_key env.GOOGLE_API_KEY\n safetySettings {\n category HARM_CATEGORY_HATE_SPEECH\n threshold BLOCK_LOW_AND_ABOVE\n\n }\n }\n}\n\nclient Vertex {\n provider vertex-ai \n options {\n model gemini-1.5-pro\n project_id anish-testing-426119\n location us-central1\n\n }\n}\n\n\nclient AwsBedrock {\n provider aws-bedrock\n options {\n inference_configuration {\n max_tokens 100\n }\n model_id \"anthropic.claude-3-haiku-20240307-v1:0\"\n // model_id \"meta.llama3-8b-instruct-v1:0\"\n // model_id \"mistral.mistral-7b-instruct-v0:2\"\n api_key \"\"\n }\n}\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", + "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider openai\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient GPT35LegacyProvider {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options {\n model gemini-1.5-pro-001\n api_key env.GOOGLE_API_KEY\n safetySettings {\n category HARM_CATEGORY_HATE_SPEECH\n threshold BLOCK_LOW_AND_ABOVE\n\n }\n }\n}\n\nclient Vertex {\n provider vertex-ai \n options {\n model gemini-1.5-pro\n project_id anish-testing-426119\n location us-central1\n\n }\n}\n\n\nclient AwsBedrock {\n provider aws-bedrock\n options {\n inference_configuration {\n max_tokens 100\n }\n model_id \"anthropic.claude-3-haiku-20240307-v1:0\"\n // model_id \"meta.llama3-8b-instruct-v1:0\"\n // model_id \"mistral.mistral-7b-instruct-v0:2\"\n api_key \"\"\n }\n}\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \n\n", "fiddle-examples/chain-of-thought.baml": "class Email {\n subject string\n body string\n from_address string\n}\n\nenum OrderStatus {\n ORDERED\n SHIPPED\n DELIVERED\n CANCELLED\n}\n\nclass OrderInfo {\n order_status OrderStatus\n tracking_number string?\n estimated_arrival_date string?\n}\n\nfunction GetOrderInfo(email: Email) -> OrderInfo {\n client GPT4\n prompt #\"\n Given the email below:\n\n ```\n from: {{email.from_address}}\n Email Subject: {{email.subject}}\n Email Body: {{email.body}}\n ```\n\n Extract this info from the email in JSON format:\n {{ ctx.output_format }}\n\n Before you output the JSON, please explain your\n reasoning step-by-step. Here is an example on how to do this:\n 'If we think step by step we can see that ...\n therefore the output JSON is:\n {\n ... the json schema ...\n }'\n \"#\n}", "fiddle-examples/chat-roles.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category2 {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage2(input: string) -> Category {\n client GPT4\n\n prompt #\"\n {{ _.role(\"system\") }}\n // You can use _.role(\"system\") to indicate that this text should be a system message\n\n Classify the following INPUT into ONE\n of the following categories:\n\n {{ ctx.output_format }}\n\n {{ _.role(\"user\") }}\n // And _.role(\"user\") to indicate that this text should be a user message\n\n INPUT: {{ input }}\n\n Response:\n \"#\n}", "fiddle-examples/classify-message.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage(input: string) -> Category {\n client GPT4\n\n prompt #\"\n Classify the following INPUT into ONE\n of the following categories:\n\n INPUT: {{ input }}\n\n {{ ctx.output_format }}\n\n Response:\n \"#\n}", @@ -62,8 +62,8 @@ "test-files/functions/prompts/with-chat-messages.baml": "\nfunction PromptTestOpenAIChat(input: string) -> string {\n client GPT35\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAIChatNoSystem(input: string) -> string {\n client GPT35\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChat(input: string) -> string {\n client Claude\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChatNoSystem(input: string) -> string {\n client Claude\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\ntest TestSystemAndNonSystemChat1 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"cats\"\n }\n}\n\ntest TestSystemAndNonSystemChat2 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"lion\"\n }\n}", "test-files/functions/v2/basic.baml": "\n\nfunction ExtractResume2(resume: string) -> Resume {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\n Extract the following information from the resume:\n\n Resume:\n <<<<\n {{ resume }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}\n\n\nclass WithReasoning {\n value string\n reasoning string @description(#\"\n Why the value is a good fit.\n \"#)\n}\n\n\nclass SearchParams {\n dateRange int? @description(#\"\n In ISO duration format, e.g. P1Y2M10D.\n \"#)\n location string[]\n jobTitle WithReasoning? @description(#\"\n An exact job title, not a general category.\n \"#)\n company WithReasoning? @description(#\"\n The exact name of the company, not a product or service.\n \"#)\n description WithReasoning[] @description(#\"\n Any specific projects or features the user is looking for.\n \"#)\n tags (Tag | string)[]\n}\n\nenum Tag {\n Security\n AI\n Blockchain\n}\n\nfunction GetQuery(query: string) -> SearchParams {\n client GPT4\n prompt #\"\n Extract the following information from the query:\n\n Query:\n <<<<\n {{ query }}\n <<<<\n\n OUTPUT_JSON_SCHEMA:\n {{ ctx.output_format }}\n\n Before OUTPUT_JSON_SCHEMA, list 5 intentions the user may have.\n --- EXAMPLES ---\n 1. \n 2. \n 3. \n 4. \n 5. \n\n {\n ... // OUTPUT_JSON_SCHEMA\n }\n \"#\n}\n\nclass RaysData {\n dataType DataType\n value Resume | Event\n}\n\nenum DataType {\n Resume\n Event\n}\n\nclass Event {\n title string\n date string\n location string\n description string\n}\n\nfunction GetDataType(text: string) -> RaysData {\n client GPT4\n prompt #\"\n Extract the relevant info.\n\n Text:\n <<<<\n {{ text }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}", "test-files/providers/providers.baml": "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n", - "test-files/strategies/fallback.baml": "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient,\n RetryClientConstant,\n GPT35\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}", - "test-files/strategies/retry.baml": "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\n", + "test-files/strategies/fallback.baml": "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient\n\n Lottery_SimpleSyntax\n\n SecondaryFallback\n TertiaryFallback\n \n ]\n }\n}\n\nclient SecondaryFallback {\n provider fallback\n options {\n strategy [\n FaultyClient\n RetryClientExponential\n\n ]\n }\n}\n\nclient TertiaryFallback {\n provider fallback\n options {\n strategy [\n FaultyClient\n RetryClientExponential\n\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}\nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n retry_policy Constant\n options {\n strategy [\n GPT35\n Claude\n \n ]\n }\n}\nfunction TestRoundRobin() ->string{\n client Lottery_SimpleSyntax\n\n prompt #\"\n Round robin haiku\n \"#\n}\n\n\n\n\ntest TestName {\n functions [TestFallbackClient, TestRoundRobin]\n args {\n\n }\n}\n", + "test-files/strategies/retry.baml": "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\ntest TestName {\n functions [TestRetryConstant]\n args {\n\n }\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\ntest TestName {\n functions [TestRetryExponential]\n args {\n\n }\n}\n", "test-files/strategies/roundrobin.baml": "", "test-files/testing_pipeline/resume.baml": "class Resume {\n name string\n email string\n phone string\n experience Education[]\n education string[]\n skills string[]\n}\n\nclass Education {\n institution string\n location string\n degree string\n major string[]\n graduation_date string?\n}\n\ntemplate_string AddRole(foo: string) #\"\n {{ _.role('system')}}\n You are a {{ foo }}. be nice\n\n {{ _.role('user') }}\n\"#\n\nfunction ExtractResume(resume: string, img: image?) -> Resume {\n client GPT35\n prompt #\"\n {{ AddRole(\"Software Engineer\") }}\n\n Extract data:\n \n\n <<<<\n {{ resume }}\n <<<<\n\n {% if img %}\n {{img}}\n {% endif %}\n\n {{ ctx.output_format }}\n \"#\n}\n\ntest sam_resume {\n functions [ExtractResume]\n input {\n img {\n url \"https://avatars.githubusercontent.com/u/1016595?v=4\"\n }\n resume #\"\n Sam Lijin\n he/him | jobs@sxlijin.com | sxlijin.github.io | 111-222-3333 | sxlijin | sxlijin\n\n Experience\n Trunk\n | July 2021 - current\n Trunk Check | Senior Software Engineer | Services TL, Mar 2023 - current | IC, July 2021 - Feb 2023\n Proposed, designed, and led a team of 3 to build a web experience for Check (both a web-only onboarding flow and SaaS offerings)\n Proposed and built vulnerability scanning into Check, enabling it to compete with security products such as Snyk\n Helped grow Check from <1K users to 90K+ users by focusing on product-led growth\n Google | Sept 2017 - June 2021\n User Identity SRE | Senior Software Engineer | IC, Mar 2021 - June 2021\n Designed an incremental key rotation system to limit the global outage risk to Google SSO\n Discovered and severed an undocumented Gmail serving dependency on Identity-internal systems\n Cloud Firestore | Senior Software Engineer | EngProd TL, Aug 2019 - Feb 2021 | IC, Sept 2017 - July 2019\n Metadata TTL system: backlog of XX trillion records, sustained 1M ops/sec, peaking at 3M ops/sec\n\n Designed and implemented a logging system with novel observability and privacy requirements\n Designed and implemented Jepsen-style testing to validate correctness guarantees\n Datastore Migration: zero downtime, xM RPS and xxPB of data over xM customers and 36 datacenters\n\n Designed composite index migration, queue processing migration, progressive rollout, fast rollback, and disk stockout mitigations; implemented transaction log replay, state transitions, and dark launch process\n Designed and implemented end-to-end correctness and performance testing\n Velocity improvements for 60-eng org\n\n Proposed and implemented automated rollbacks: got us out of a 3-month release freeze and prevented 5 outages over the next 6 months\n Proposed and implemented new development and release environments spanning 30+ microservices\n Incident response for API proxy rollback affecting every Google Cloud service\n\n Google App Engine Memcache | Software Engineer | EngProd TL, Apr 2019 - July 2019\n Proposed and led execution of test coverage improvement strategy for a new control plane: reduced rollbacks and ensured strong consistency of a distributed cache serving xxM QPS\n Designed and implemented automated performance regression testing for two critical serving paths\n Used to validate Google-wide rollout of AMD CPUs, by proving a 50p latency delta of <10µs\n Implemented on shared Borg (i.e. vulnerable to noisy neighbors) with <12% variance\n Miscellaneous | Sept 2017 - June 2021\n Redesigned the Noogler training on Google-internal storage technologies & trained 2500+ Nooglers\n Landed multiple google3-wide refactorings, each spanning xxK files (e.g. SWIG to CLIF)\n Education\n Vanderbilt University (Nashville, TN) | May 2017 | B.S. in Computer Science, Mathematics, and Political Science\n\n Stuyvesant HS (New York, NY) | 2013\n\n Skills\n C++, Java, Typescript, Javascript, Python, Bash; light experience with Rust, Golang, Scheme\n gRPC, Bazel, React, Linux\n Hobbies: climbing, skiing, photography\n \"#\n }\n}\n\ntest vaibhav_resume {\n functions [ExtractResume]\n input {\n resume #\"\n Vaibhav Gupta\n linkedin/vaigup\n (972) 400-5279\n vaibhavtheory@gmail.com\n EXPERIENCE\n Google,\n Software Engineer\n Dec 2018-Present\n Seattle, WA\n •\n Augmented Reality,\n Depth Team\n •\n Technical Lead for on-device optimizations\n •\n Optimized and designed front\n facing depth algorithm\n on Pixel 4\n •\n Focus: C++ and SIMD on custom silicon\n \n \n EDUCATION\n University of Texas at Austin\n Aug 2012-May 2015\n Bachelors of Engineering, Integrated Circuits\n Bachelors of Computer Science\n \"#\n }\n}", } diff --git a/integ-tests/ruby/baml_client/client.rb b/integ-tests/ruby/baml_client/client.rb index 35c685259..e4045920b 100644 --- a/integ-tests/ruby/baml_client/client.rb +++ b/integ-tests/ruby/baml_client/client.rb @@ -1285,18 +1285,16 @@ def TestRetryExponential( sig { - params( - input: String, - ).returns(String) + returns(String) } - def TestVertex( - input: + def TestRoundRobin( + ) raw = @runtime.call_function( - "TestVertex", + "TestRoundRobin", { - "input" => input, + }, @ctx_manager, ) @@ -2660,16 +2658,16 @@ def TestRetryExponential( sig { params( - input: String, + ).returns(Baml::BamlStream[String]) } - def TestVertex( - input: + def TestRoundRobin( + ) raw = @runtime.stream_function( - "TestVertex", + "TestRoundRobin", { - "input" => input, + }, @ctx_manager, ) diff --git a/integ-tests/ruby/baml_client/inlined.rb b/integ-tests/ruby/baml_client/inlined.rb index f195aeb33..b129c7b36 100644 --- a/integ-tests/ruby/baml_client/inlined.rb +++ b/integ-tests/ruby/baml_client/inlined.rb @@ -16,7 +16,7 @@ module Baml module Inlined FILE_MAP = { - "clients.baml" => "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider openai\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient GPT35LegacyProvider {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options {\n model gemini-1.5-pro-001\n api_key env.GOOGLE_API_KEY\n safetySettings {\n category HARM_CATEGORY_HATE_SPEECH\n threshold BLOCK_LOW_AND_ABOVE\n\n }\n }\n}\n\nclient Vertex {\n provider vertex-ai \n options {\n model gemini-1.5-pro\n project_id anish-testing-426119\n location us-central1\n\n }\n}\n\n\nclient AwsBedrock {\n provider aws-bedrock\n options {\n inference_configuration {\n max_tokens 100\n }\n model_id \"anthropic.claude-3-haiku-20240307-v1:0\"\n // model_id \"meta.llama3-8b-instruct-v1:0\"\n // model_id \"mistral.mistral-7b-instruct-v0:2\"\n api_key \"\"\n }\n}\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", + "clients.baml" => "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider openai\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient GPT35LegacyProvider {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options {\n model gemini-1.5-pro-001\n api_key env.GOOGLE_API_KEY\n safetySettings {\n category HARM_CATEGORY_HATE_SPEECH\n threshold BLOCK_LOW_AND_ABOVE\n\n }\n }\n}\n\nclient Vertex {\n provider vertex-ai \n options {\n model gemini-1.5-pro\n project_id anish-testing-426119\n location us-central1\n\n }\n}\n\n\nclient AwsBedrock {\n provider aws-bedrock\n options {\n inference_configuration {\n max_tokens 100\n }\n model_id \"anthropic.claude-3-haiku-20240307-v1:0\"\n // model_id \"meta.llama3-8b-instruct-v1:0\"\n // model_id \"mistral.mistral-7b-instruct-v0:2\"\n api_key \"\"\n }\n}\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \n\n", "fiddle-examples/chain-of-thought.baml" => "class Email {\n subject string\n body string\n from_address string\n}\n\nenum OrderStatus {\n ORDERED\n SHIPPED\n DELIVERED\n CANCELLED\n}\n\nclass OrderInfo {\n order_status OrderStatus\n tracking_number string?\n estimated_arrival_date string?\n}\n\nfunction GetOrderInfo(email: Email) -> OrderInfo {\n client GPT4\n prompt #\"\n Given the email below:\n\n ```\n from: {{email.from_address}}\n Email Subject: {{email.subject}}\n Email Body: {{email.body}}\n ```\n\n Extract this info from the email in JSON format:\n {{ ctx.output_format }}\n\n Before you output the JSON, please explain your\n reasoning step-by-step. Here is an example on how to do this:\n 'If we think step by step we can see that ...\n therefore the output JSON is:\n {\n ... the json schema ...\n }'\n \"#\n}", "fiddle-examples/chat-roles.baml" => "// This will be available as an enum in your Python and Typescript code.\nenum Category2 {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage2(input: string) -> Category {\n client GPT4\n\n prompt #\"\n {{ _.role(\"system\") }}\n // You can use _.role(\"system\") to indicate that this text should be a system message\n\n Classify the following INPUT into ONE\n of the following categories:\n\n {{ ctx.output_format }}\n\n {{ _.role(\"user\") }}\n // And _.role(\"user\") to indicate that this text should be a user message\n\n INPUT: {{ input }}\n\n Response:\n \"#\n}", "fiddle-examples/classify-message.baml" => "// This will be available as an enum in your Python and Typescript code.\nenum Category {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage(input: string) -> Category {\n client GPT4\n\n prompt #\"\n Classify the following INPUT into ONE\n of the following categories:\n\n INPUT: {{ input }}\n\n {{ ctx.output_format }}\n\n Response:\n \"#\n}", @@ -62,8 +62,8 @@ module Inlined "test-files/functions/prompts/with-chat-messages.baml" => "\nfunction PromptTestOpenAIChat(input: string) -> string {\n client GPT35\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAIChatNoSystem(input: string) -> string {\n client GPT35\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChat(input: string) -> string {\n client Claude\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChatNoSystem(input: string) -> string {\n client Claude\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\ntest TestSystemAndNonSystemChat1 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"cats\"\n }\n}\n\ntest TestSystemAndNonSystemChat2 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"lion\"\n }\n}", "test-files/functions/v2/basic.baml" => "\n\nfunction ExtractResume2(resume: string) -> Resume {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\n Extract the following information from the resume:\n\n Resume:\n <<<<\n {{ resume }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}\n\n\nclass WithReasoning {\n value string\n reasoning string @description(#\"\n Why the value is a good fit.\n \"#)\n}\n\n\nclass SearchParams {\n dateRange int? @description(#\"\n In ISO duration format, e.g. P1Y2M10D.\n \"#)\n location string[]\n jobTitle WithReasoning? @description(#\"\n An exact job title, not a general category.\n \"#)\n company WithReasoning? @description(#\"\n The exact name of the company, not a product or service.\n \"#)\n description WithReasoning[] @description(#\"\n Any specific projects or features the user is looking for.\n \"#)\n tags (Tag | string)[]\n}\n\nenum Tag {\n Security\n AI\n Blockchain\n}\n\nfunction GetQuery(query: string) -> SearchParams {\n client GPT4\n prompt #\"\n Extract the following information from the query:\n\n Query:\n <<<<\n {{ query }}\n <<<<\n\n OUTPUT_JSON_SCHEMA:\n {{ ctx.output_format }}\n\n Before OUTPUT_JSON_SCHEMA, list 5 intentions the user may have.\n --- EXAMPLES ---\n 1. \n 2. \n 3. \n 4. \n 5. \n\n {\n ... // OUTPUT_JSON_SCHEMA\n }\n \"#\n}\n\nclass RaysData {\n dataType DataType\n value Resume | Event\n}\n\nenum DataType {\n Resume\n Event\n}\n\nclass Event {\n title string\n date string\n location string\n description string\n}\n\nfunction GetDataType(text: string) -> RaysData {\n client GPT4\n prompt #\"\n Extract the relevant info.\n\n Text:\n <<<<\n {{ text }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}", "test-files/providers/providers.baml" => "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n", - "test-files/strategies/fallback.baml" => "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient,\n RetryClientConstant,\n GPT35\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}", - "test-files/strategies/retry.baml" => "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\n", + "test-files/strategies/fallback.baml" => "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient\n\n Lottery_SimpleSyntax\n\n SecondaryFallback\n TertiaryFallback\n \n ]\n }\n}\n\nclient SecondaryFallback {\n provider fallback\n options {\n strategy [\n FaultyClient\n RetryClientExponential\n\n ]\n }\n}\n\nclient TertiaryFallback {\n provider fallback\n options {\n strategy [\n FaultyClient\n RetryClientExponential\n\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}\nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n retry_policy Constant\n options {\n strategy [\n GPT35\n Claude\n \n ]\n }\n}\nfunction TestRoundRobin() ->string{\n client Lottery_SimpleSyntax\n\n prompt #\"\n Round robin haiku\n \"#\n}\n\n\n\n\ntest TestName {\n functions [TestFallbackClient, TestRoundRobin]\n args {\n\n }\n}\n", + "test-files/strategies/retry.baml" => "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\ntest TestName {\n functions [TestRetryConstant]\n args {\n\n }\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\ntest TestName {\n functions [TestRetryExponential]\n args {\n\n }\n}\n", "test-files/strategies/roundrobin.baml" => "", "test-files/testing_pipeline/resume.baml" => "class Resume {\n name string\n email string\n phone string\n experience Education[]\n education string[]\n skills string[]\n}\n\nclass Education {\n institution string\n location string\n degree string\n major string[]\n graduation_date string?\n}\n\ntemplate_string AddRole(foo: string) #\"\n {{ _.role('system')}}\n You are a {{ foo }}. be nice\n\n {{ _.role('user') }}\n\"#\n\nfunction ExtractResume(resume: string, img: image?) -> Resume {\n client GPT35\n prompt #\"\n {{ AddRole(\"Software Engineer\") }}\n\n Extract data:\n \n\n <<<<\n {{ resume }}\n <<<<\n\n {% if img %}\n {{img}}\n {% endif %}\n\n {{ ctx.output_format }}\n \"#\n}\n\ntest sam_resume {\n functions [ExtractResume]\n input {\n img {\n url \"https://avatars.githubusercontent.com/u/1016595?v=4\"\n }\n resume #\"\n Sam Lijin\n he/him | jobs@sxlijin.com | sxlijin.github.io | 111-222-3333 | sxlijin | sxlijin\n\n Experience\n Trunk\n | July 2021 - current\n Trunk Check | Senior Software Engineer | Services TL, Mar 2023 - current | IC, July 2021 - Feb 2023\n Proposed, designed, and led a team of 3 to build a web experience for Check (both a web-only onboarding flow and SaaS offerings)\n Proposed and built vulnerability scanning into Check, enabling it to compete with security products such as Snyk\n Helped grow Check from <1K users to 90K+ users by focusing on product-led growth\n Google | Sept 2017 - June 2021\n User Identity SRE | Senior Software Engineer | IC, Mar 2021 - June 2021\n Designed an incremental key rotation system to limit the global outage risk to Google SSO\n Discovered and severed an undocumented Gmail serving dependency on Identity-internal systems\n Cloud Firestore | Senior Software Engineer | EngProd TL, Aug 2019 - Feb 2021 | IC, Sept 2017 - July 2019\n Metadata TTL system: backlog of XX trillion records, sustained 1M ops/sec, peaking at 3M ops/sec\n\n Designed and implemented a logging system with novel observability and privacy requirements\n Designed and implemented Jepsen-style testing to validate correctness guarantees\n Datastore Migration: zero downtime, xM RPS and xxPB of data over xM customers and 36 datacenters\n\n Designed composite index migration, queue processing migration, progressive rollout, fast rollback, and disk stockout mitigations; implemented transaction log replay, state transitions, and dark launch process\n Designed and implemented end-to-end correctness and performance testing\n Velocity improvements for 60-eng org\n\n Proposed and implemented automated rollbacks: got us out of a 3-month release freeze and prevented 5 outages over the next 6 months\n Proposed and implemented new development and release environments spanning 30+ microservices\n Incident response for API proxy rollback affecting every Google Cloud service\n\n Google App Engine Memcache | Software Engineer | EngProd TL, Apr 2019 - July 2019\n Proposed and led execution of test coverage improvement strategy for a new control plane: reduced rollbacks and ensured strong consistency of a distributed cache serving xxM QPS\n Designed and implemented automated performance regression testing for two critical serving paths\n Used to validate Google-wide rollout of AMD CPUs, by proving a 50p latency delta of <10µs\n Implemented on shared Borg (i.e. vulnerable to noisy neighbors) with <12% variance\n Miscellaneous | Sept 2017 - June 2021\n Redesigned the Noogler training on Google-internal storage technologies & trained 2500+ Nooglers\n Landed multiple google3-wide refactorings, each spanning xxK files (e.g. SWIG to CLIF)\n Education\n Vanderbilt University (Nashville, TN) | May 2017 | B.S. in Computer Science, Mathematics, and Political Science\n\n Stuyvesant HS (New York, NY) | 2013\n\n Skills\n C++, Java, Typescript, Javascript, Python, Bash; light experience with Rust, Golang, Scheme\n gRPC, Bazel, React, Linux\n Hobbies: climbing, skiing, photography\n \"#\n }\n}\n\ntest vaibhav_resume {\n functions [ExtractResume]\n input {\n resume #\"\n Vaibhav Gupta\n linkedin/vaigup\n (972) 400-5279\n vaibhavtheory@gmail.com\n EXPERIENCE\n Google,\n Software Engineer\n Dec 2018-Present\n Seattle, WA\n •\n Augmented Reality,\n Depth Team\n •\n Technical Lead for on-device optimizations\n •\n Optimized and designed front\n facing depth algorithm\n on Pixel 4\n •\n Focus: C++ and SIMD on custom silicon\n \n \n EDUCATION\n University of Texas at Austin\n Aug 2012-May 2015\n Bachelors of Engineering, Integrated Circuits\n Bachelors of Computer Science\n \"#\n }\n}", } diff --git a/integ-tests/typescript/baml_client/client.ts b/integ-tests/typescript/baml_client/client.ts index 7534ff476..638d2076d 100644 --- a/integ-tests/typescript/baml_client/client.ts +++ b/integ-tests/typescript/baml_client/client.ts @@ -1033,14 +1033,14 @@ export class BamlClient { return raw.parsed() as string } - async TestVertex( - input: string, + async TestRoundRobin( + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } ): Promise { const raw = await this.runtime.callFunction( - "TestVertex", + "TestRoundRobin", { - "input": input + }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), @@ -1049,17 +1049,18 @@ export class BamlClient { return raw.parsed() as string } - async TestRoundRobin( - - __baml_options__?: { tb?: TypeBuilder } + async TestVertex( + input: string, + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } ): Promise { const raw = await this.runtime.callFunction( - "TestRoundRobin", + "TestVertex", { - + "input": input }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), + __baml_options__?.cr, ) return raw.parsed() as string } @@ -2512,14 +2513,14 @@ class BamlStreamClient { ) } - TestVertex( - input: string, + TestRoundRobin( + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } ): BamlStream, string> { const raw = this.runtime.streamFunction( - "TestVertex", + "TestRoundRobin", { - "input": input + }, undefined, this.ctx_manager.cloneContext(), @@ -2535,18 +2536,19 @@ class BamlStreamClient { ) } - TestRoundRobin( - - __baml_options__?: { tb?: TypeBuilder } + TestVertex( + input: string, + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } ): BamlStream, string> { const raw = this.runtime.streamFunction( - "TestRoundRobin", + "TestVertex", { - + "input": input }, undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), + __baml_options__?.cr, ) return new BamlStream, string>( raw, diff --git a/integ-tests/typescript/baml_client/inlinedbaml.ts b/integ-tests/typescript/baml_client/inlinedbaml.ts index c5e056d1f..db285c9af 100644 --- a/integ-tests/typescript/baml_client/inlinedbaml.ts +++ b/integ-tests/typescript/baml_client/inlinedbaml.ts @@ -17,7 +17,7 @@ $ pnpm add @boundaryml/baml /* eslint-disable */ const fileMap = { - "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider openai\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient GPT35LegacyProvider {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options {\n model gemini-1.5-pro-001\n api_key env.GOOGLE_API_KEY\n safetySettings {\n category HARM_CATEGORY_HATE_SPEECH\n threshold BLOCK_LOW_AND_ABOVE\n\n }\n }\n}\n\nclient Vertex {\n provider vertex-ai \n options {\n model gemini-1.5-pro\n project_id anish-testing-426119\n location us-central1\n\n }\n}\n\n\nclient AwsBedrock {\n provider aws-bedrock\n options {\n inference_configuration {\n max_tokens 100\n }\n model_id \"anthropic.claude-3-haiku-20240307-v1:0\"\n // model_id \"meta.llama3-8b-instruct-v1:0\"\n // model_id \"mistral.mistral-7b-instruct-v0:2\"\n api_key \"\"\n }\n}\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", + "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider openai\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider openai\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient GPT35LegacyProvider {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options {\n model gemini-1.5-pro-001\n api_key env.GOOGLE_API_KEY\n safetySettings {\n category HARM_CATEGORY_HATE_SPEECH\n threshold BLOCK_LOW_AND_ABOVE\n\n }\n }\n}\n\nclient Vertex {\n provider vertex-ai \n options {\n model gemini-1.5-pro\n project_id anish-testing-426119\n location us-central1\n\n }\n}\n\n\nclient AwsBedrock {\n provider aws-bedrock\n options {\n inference_configuration {\n max_tokens 100\n }\n model_id \"anthropic.claude-3-haiku-20240307-v1:0\"\n // model_id \"meta.llama3-8b-instruct-v1:0\"\n // model_id \"mistral.mistral-7b-instruct-v0:2\"\n api_key \"\"\n }\n}\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \n\n", "fiddle-examples/chain-of-thought.baml": "class Email {\n subject string\n body string\n from_address string\n}\n\nenum OrderStatus {\n ORDERED\n SHIPPED\n DELIVERED\n CANCELLED\n}\n\nclass OrderInfo {\n order_status OrderStatus\n tracking_number string?\n estimated_arrival_date string?\n}\n\nfunction GetOrderInfo(email: Email) -> OrderInfo {\n client GPT4\n prompt #\"\n Given the email below:\n\n ```\n from: {{email.from_address}}\n Email Subject: {{email.subject}}\n Email Body: {{email.body}}\n ```\n\n Extract this info from the email in JSON format:\n {{ ctx.output_format }}\n\n Before you output the JSON, please explain your\n reasoning step-by-step. Here is an example on how to do this:\n 'If we think step by step we can see that ...\n therefore the output JSON is:\n {\n ... the json schema ...\n }'\n \"#\n}", "fiddle-examples/chat-roles.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category2 {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage2(input: string) -> Category {\n client GPT4\n\n prompt #\"\n {{ _.role(\"system\") }}\n // You can use _.role(\"system\") to indicate that this text should be a system message\n\n Classify the following INPUT into ONE\n of the following categories:\n\n {{ ctx.output_format }}\n\n {{ _.role(\"user\") }}\n // And _.role(\"user\") to indicate that this text should be a user message\n\n INPUT: {{ input }}\n\n Response:\n \"#\n}", "fiddle-examples/classify-message.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage(input: string) -> Category {\n client GPT4\n\n prompt #\"\n Classify the following INPUT into ONE\n of the following categories:\n\n INPUT: {{ input }}\n\n {{ ctx.output_format }}\n\n Response:\n \"#\n}", @@ -63,8 +63,8 @@ const fileMap = { "test-files/functions/prompts/with-chat-messages.baml": "\nfunction PromptTestOpenAIChat(input: string) -> string {\n client GPT35\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAIChatNoSystem(input: string) -> string {\n client GPT35\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChat(input: string) -> string {\n client Claude\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChatNoSystem(input: string) -> string {\n client Claude\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\ntest TestSystemAndNonSystemChat1 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"cats\"\n }\n}\n\ntest TestSystemAndNonSystemChat2 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"lion\"\n }\n}", "test-files/functions/v2/basic.baml": "\n\nfunction ExtractResume2(resume: string) -> Resume {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\n Extract the following information from the resume:\n\n Resume:\n <<<<\n {{ resume }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}\n\n\nclass WithReasoning {\n value string\n reasoning string @description(#\"\n Why the value is a good fit.\n \"#)\n}\n\n\nclass SearchParams {\n dateRange int? @description(#\"\n In ISO duration format, e.g. P1Y2M10D.\n \"#)\n location string[]\n jobTitle WithReasoning? @description(#\"\n An exact job title, not a general category.\n \"#)\n company WithReasoning? @description(#\"\n The exact name of the company, not a product or service.\n \"#)\n description WithReasoning[] @description(#\"\n Any specific projects or features the user is looking for.\n \"#)\n tags (Tag | string)[]\n}\n\nenum Tag {\n Security\n AI\n Blockchain\n}\n\nfunction GetQuery(query: string) -> SearchParams {\n client GPT4\n prompt #\"\n Extract the following information from the query:\n\n Query:\n <<<<\n {{ query }}\n <<<<\n\n OUTPUT_JSON_SCHEMA:\n {{ ctx.output_format }}\n\n Before OUTPUT_JSON_SCHEMA, list 5 intentions the user may have.\n --- EXAMPLES ---\n 1. \n 2. \n 3. \n 4. \n 5. \n\n {\n ... // OUTPUT_JSON_SCHEMA\n }\n \"#\n}\n\nclass RaysData {\n dataType DataType\n value Resume | Event\n}\n\nenum DataType {\n Resume\n Event\n}\n\nclass Event {\n title string\n date string\n location string\n description string\n}\n\nfunction GetDataType(text: string) -> RaysData {\n client GPT4\n prompt #\"\n Extract the relevant info.\n\n Text:\n <<<<\n {{ text }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}", "test-files/providers/providers.baml": "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n", - "test-files/strategies/fallback.baml": "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient,\n RetryClientConstant,\n GPT35\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}", - "test-files/strategies/retry.baml": "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\n", + "test-files/strategies/fallback.baml": "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient\n\n Lottery_SimpleSyntax\n\n SecondaryFallback\n TertiaryFallback\n \n ]\n }\n}\n\nclient SecondaryFallback {\n provider fallback\n options {\n strategy [\n FaultyClient\n RetryClientExponential\n\n ]\n }\n}\n\nclient TertiaryFallback {\n provider fallback\n options {\n strategy [\n FaultyClient\n RetryClientExponential\n\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}\nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n retry_policy Constant\n options {\n strategy [\n GPT35\n Claude\n \n ]\n }\n}\nfunction TestRoundRobin() ->string{\n client Lottery_SimpleSyntax\n\n prompt #\"\n Round robin haiku\n \"#\n}\n\n\n\n\ntest TestName {\n functions [TestFallbackClient, TestRoundRobin]\n args {\n\n }\n}\n", + "test-files/strategies/retry.baml": "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\ntest TestName {\n functions [TestRetryConstant]\n args {\n\n }\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\ntest TestName {\n functions [TestRetryExponential]\n args {\n\n }\n}\n", "test-files/strategies/roundrobin.baml": "", "test-files/testing_pipeline/resume.baml": "class Resume {\n name string\n email string\n phone string\n experience Education[]\n education string[]\n skills string[]\n}\n\nclass Education {\n institution string\n location string\n degree string\n major string[]\n graduation_date string?\n}\n\ntemplate_string AddRole(foo: string) #\"\n {{ _.role('system')}}\n You are a {{ foo }}. be nice\n\n {{ _.role('user') }}\n\"#\n\nfunction ExtractResume(resume: string, img: image?) -> Resume {\n client GPT35\n prompt #\"\n {{ AddRole(\"Software Engineer\") }}\n\n Extract data:\n \n\n <<<<\n {{ resume }}\n <<<<\n\n {% if img %}\n {{img}}\n {% endif %}\n\n {{ ctx.output_format }}\n \"#\n}\n\ntest sam_resume {\n functions [ExtractResume]\n input {\n img {\n url \"https://avatars.githubusercontent.com/u/1016595?v=4\"\n }\n resume #\"\n Sam Lijin\n he/him | jobs@sxlijin.com | sxlijin.github.io | 111-222-3333 | sxlijin | sxlijin\n\n Experience\n Trunk\n | July 2021 - current\n Trunk Check | Senior Software Engineer | Services TL, Mar 2023 - current | IC, July 2021 - Feb 2023\n Proposed, designed, and led a team of 3 to build a web experience for Check (both a web-only onboarding flow and SaaS offerings)\n Proposed and built vulnerability scanning into Check, enabling it to compete with security products such as Snyk\n Helped grow Check from <1K users to 90K+ users by focusing on product-led growth\n Google | Sept 2017 - June 2021\n User Identity SRE | Senior Software Engineer | IC, Mar 2021 - June 2021\n Designed an incremental key rotation system to limit the global outage risk to Google SSO\n Discovered and severed an undocumented Gmail serving dependency on Identity-internal systems\n Cloud Firestore | Senior Software Engineer | EngProd TL, Aug 2019 - Feb 2021 | IC, Sept 2017 - July 2019\n Metadata TTL system: backlog of XX trillion records, sustained 1M ops/sec, peaking at 3M ops/sec\n\n Designed and implemented a logging system with novel observability and privacy requirements\n Designed and implemented Jepsen-style testing to validate correctness guarantees\n Datastore Migration: zero downtime, xM RPS and xxPB of data over xM customers and 36 datacenters\n\n Designed composite index migration, queue processing migration, progressive rollout, fast rollback, and disk stockout mitigations; implemented transaction log replay, state transitions, and dark launch process\n Designed and implemented end-to-end correctness and performance testing\n Velocity improvements for 60-eng org\n\n Proposed and implemented automated rollbacks: got us out of a 3-month release freeze and prevented 5 outages over the next 6 months\n Proposed and implemented new development and release environments spanning 30+ microservices\n Incident response for API proxy rollback affecting every Google Cloud service\n\n Google App Engine Memcache | Software Engineer | EngProd TL, Apr 2019 - July 2019\n Proposed and led execution of test coverage improvement strategy for a new control plane: reduced rollbacks and ensured strong consistency of a distributed cache serving xxM QPS\n Designed and implemented automated performance regression testing for two critical serving paths\n Used to validate Google-wide rollout of AMD CPUs, by proving a 50p latency delta of <10µs\n Implemented on shared Borg (i.e. vulnerable to noisy neighbors) with <12% variance\n Miscellaneous | Sept 2017 - June 2021\n Redesigned the Noogler training on Google-internal storage technologies & trained 2500+ Nooglers\n Landed multiple google3-wide refactorings, each spanning xxK files (e.g. SWIG to CLIF)\n Education\n Vanderbilt University (Nashville, TN) | May 2017 | B.S. in Computer Science, Mathematics, and Political Science\n\n Stuyvesant HS (New York, NY) | 2013\n\n Skills\n C++, Java, Typescript, Javascript, Python, Bash; light experience with Rust, Golang, Scheme\n gRPC, Bazel, React, Linux\n Hobbies: climbing, skiing, photography\n \"#\n }\n}\n\ntest vaibhav_resume {\n functions [ExtractResume]\n input {\n resume #\"\n Vaibhav Gupta\n linkedin/vaigup\n (972) 400-5279\n vaibhavtheory@gmail.com\n EXPERIENCE\n Google,\n Software Engineer\n Dec 2018-Present\n Seattle, WA\n •\n Augmented Reality,\n Depth Team\n •\n Technical Lead for on-device optimizations\n •\n Optimized and designed front\n facing depth algorithm\n on Pixel 4\n •\n Focus: C++ and SIMD on custom silicon\n \n \n EDUCATION\n University of Texas at Austin\n Aug 2012-May 2015\n Bachelors of Engineering, Integrated Circuits\n Bachelors of Computer Science\n \"#\n }\n}", } diff --git a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx index ea831b719..7e10555c4 100644 --- a/typescript/playground-common/src/baml_wasm_web/EventListener.tsx +++ b/typescript/playground-common/src/baml_wasm_web/EventListener.tsx @@ -469,8 +469,6 @@ const getScopeInfo = (scope: any) => { } } export const orchestration_nodes = atom((get): { nodes: GroupEntry[]; edges: Edge[] } => { - // ... existing code ... - const func = get(selectedFunctionAtom) const runtime = get(selectedRuntimeAtom) @@ -478,223 +476,132 @@ export const orchestration_nodes = atom((get): { nodes: GroupEntry[]; edges: Edg return { nodes: [], edges: [] } } - let wasmScopes = func.orchestration_graph(runtime) - + const wasmScopes = func.orchestration_graph(runtime) if (wasmScopes === null) { return { nodes: [], edges: [] } - } else { - // console.log(`orchestrationGraph: ${wasmScopes.length}`) - let indexOuter = 0 - - var nodes: ClientNode[] = [] - - for (const scope of wasmScopes) { - const scopeInfo = scope.get_orchestration_scope_info() - - // Represents the current node as a path of scopes from the root - const scopePath = scopeInfo as any[] + } - let stackGroup: TypeCount[] = [] + const nodes = createClientNodes(wasmScopes) + nodes.forEach((node) => { + node.identifier.unshift({ + type: 'F', + name: 0, + }) + }) - scopePath.forEach((scope) => { - const indexVal = - scope.type === 'Retry' - ? scope.count - : scope.type === 'Direct' - ? 0 - : scope.type === 'RoundRobin' - ? scope.strategy_name - : scope.index + nodes.forEach((node) => { + const stackGroupString = node.identifier.map((item: TypeCount) => `${item.type}${item.name}`).join(' | ') + console.log(`${stackGroupString}`) + }) - stackGroup.push({ - type: getTypeLetter(scope.type), - name: indexVal, - }) - }) + const { unitNodes, groups } = buildUnitNodesAndGroups(nodes) + const edges = createEdges(unitNodes) - var typeScope: any + const groupArray: GroupEntry[] = Object.values(groups) + return { nodes: groupArray, edges } +}) - if (scopePath.length > 2) { - typeScope = scopePath[scopePath.length - 2] - } else { - typeScope = scopePath[scopePath.length - 1] - } +function createClientNodes(wasmScopes: any[]): ClientNode[] { + let indexOuter = 0 + const nodes: ClientNode[] = [] - const lastScope = scopePath[scopePath.length - 1] + for (const scope of wasmScopes) { + const scopeInfo = scope.get_orchestration_scope_info() + const scopePath = scopeInfo as any[] + const stackGroup = createStackGroup(scopePath) - // Create a new ClientNode object - const clientNode: ClientNode = { - name: lastScope.name, - node_index: indexOuter, - type: typeScope.type, - identifier: stackGroup, - } + const typeScope = scopePath.length > 2 ? scopePath[scopePath.length - 2] : scopePath[scopePath.length - 1] + const lastScope = scopePath[scopePath.length - 1] - switch (typeScope.type) { - case 'Retry': - clientNode.node_index = typeScope.count - clientNode.retry_delay = typeScope.delay - break - case 'RoundRobin': - clientNode.round_robin_name = typeScope.strategy_name - break - case 'Fallback': - clientNode.type = lastScope.type - break - case 'Direct': - break - default: - console.error('Unknown scope type') - } - - nodes.push(clientNode) + const clientNode: ClientNode = { + name: lastScope.name, + node_index: indexOuter, + type: typeScope.type, + identifier: stackGroup, + } - indexOuter++ + switch (typeScope.type) { + case 'Retry': + clientNode.node_index = typeScope.count + clientNode.retry_delay = typeScope.delay + break + case 'RoundRobin': + clientNode.round_robin_name = typeScope.strategy_name + break + case 'Fallback': + clientNode.type = lastScope.type + break + case 'Direct': + break + default: + console.error('Unknown scope type') } - } - for (const node of nodes) { - const stackGroupString = node.identifier.map((item: TypeCount) => `${item.type}${item.name}`).join(' | ') - // console.log(`${stackGroupString}`) + nodes.push(clientNode) + indexOuter++ } - //we construct edges between unitNodes - var unitNodes: NodeEntry[] = [] + return nodes +} - //groups holds all of our nodes that we will show, including group nodes - var groups: { [gid: ReturnType]: GroupEntry } = {} +function createStackGroup(scopePath: any[]): TypeCount[] { + const stackGroup: TypeCount[] = [] + + for (let i = 0; i < scopePath.length; i++) { + const scope = scopePath[i] + const indexVal = + scope.type === 'Retry' + ? scope.count + : scope.type === 'Direct' + ? 0 + : scope.type === 'RoundRobin' + ? scope.strategy_name + : scope.index + + stackGroup.push({ + type: getTypeLetter(scope.type), + name: indexVal, + }) + } - //utility only for building the above two - var indexGroups: GroupEntry[] = [] + return stackGroup +} - for (let index = 0; index < nodes.length; index++) { - const node = nodes[index] +function buildUnitNodesAndGroups(nodes: ClientNode[]): { + unitNodes: NodeEntry[] + groups: { [gid: string]: GroupEntry } +} { + const unitNodes: NodeEntry[] = [] + const groups: { [gid: string]: GroupEntry } = {} + const indexGroups: GroupEntry[] = [] - let stackGroup: TypeCount[] = node.identifier + for (const node of nodes) { + const stackGroup = node.identifier let parentGid = '' - // console.log(`StackGroup: ${stackGroup.map((item) => `${item.type}${item.name}`).join(' | ')}`) - // console.log(`Index Groups at state ${index}`) - // indexGroups.forEach((group, index) => { - // console.log( - // `Index ${index}: letter: ${group.letter}, name: ${group.index}, gid: ${group.gid}, parentGid: ${group.parentGid}`, - // ) - // }) - for (let stackIndex = 0; stackIndex < stackGroup.length; stackIndex++) { - const scopeLayer: TypeCount = stackGroup[stackIndex] - const scopeType = scopeLayer.type - const scopeName = scopeLayer.name - - let indexGroupEntry = stackIndex < indexGroups.length ? indexGroups[stackIndex] : null - - //the current depth is not stored in the indexGroups array - if (indexGroupEntry === null) { - const curGid = uuid() - if (!(curGid in groups)) { - groups[curGid] = { - letter: scopeType, - index: scopeName, - client_name: node.name, - gid: curGid, - ...(parentGid !== null && { parentGid: parentGid }), - } - } - parentGid = curGid + const scopeLayer = stackGroup[stackIndex] + const { scopeType, scopeName, curGid } = getScopeDetails(scopeLayer, indexGroups, stackIndex, parentGid) - indexGroups[stackIndex] = { + if (!(curGid in groups)) { + groups[curGid] = { letter: scopeType, index: scopeName, + client_name: node.name, gid: curGid, + ...(parentGid && { parentGid }), } } - // current depth exists, validation is needed - else { - const indexEntryName = indexGroupEntry.index - const indexEntryGid = indexGroupEntry.gid - - let curGid = '' - - switch (scopeType) { - case 'R': - //retry >= is same group - if (scopeName >= indexEntryName) { - curGid = indexEntryGid - } - //retry < is new group -- shouldn't execute, as ancestor nodes will have reset this - else { - curGid = uuid() - indexGroups = indexGroups.slice(0, stackIndex) - } - break - case 'F': - //fallback == is same group - if (scopeName == indexEntryName) { - curGid = indexEntryGid - } - //lower fallback means in different group entirely - else if (scopeName < indexEntryName) { - curGid = uuid() - indexGroups = indexGroups.slice(0, stackIndex) - } - //increased fallback fall under same group, but trailing elements are new - else { - curGid = indexEntryGid - indexGroups = indexGroups.slice(0, stackIndex) - } - break - case 'D': - //direct == its own group - curGid = uuid() - indexGroups = indexGroups.slice(0, stackIndex) - break - case 'B': - //round robin falls under same group if same strategy name - if (scopeName == indexEntryName) { - curGid = indexEntryGid - } - // new round robin strategy name means new group -- shouldn't execute, as ancestor nodes will have reset this - else { - curGid = uuid() - indexGroups = indexGroups.slice(0, stackIndex) - } - break - default: - console.error('Unknown scope type') - } - - //add the new group/node to the groups (stores every node/layer) - if (!(curGid in groups)) { - groups[curGid] = { - letter: scopeType, - index: scopeName, - client_name: node.name, - - gid: curGid, - ...(parentGid !== null && { parentGid: parentGid }), - } - } - - // console.log(`Letter: ${scopeType}, Name: ${scopeName}, Gid: ${curGid}`) - //update table for future iterations - indexGroups[stackIndex] = { - letter: scopeType, - index: scopeName, - gid: curGid, - ...(parentGid !== null && { parentGid: parentGid }), - } - //store the parent gid for the next iteration - parentGid = curGid + indexGroups[stackIndex] = { + letter: scopeType, + index: scopeName, + gid: curGid, + ...(parentGid && { parentGid }), } + + parentGid = curGid } - // console.log(`Index Groups after state ${index}:`) - // indexGroups.forEach((group, index) => { - // console.log( - // `Index ${index}: letter: ${group.letter}, name: ${group.index}, client_name: ${group.client_name} gid: ${group.gid}, parentGid: ${group.parentGid}`, - // ) - // }) - // console.log('-----------------------------------') unitNodes.push({ gid: parentGid, @@ -702,32 +609,50 @@ export const orchestration_nodes = atom((get): { nodes: GroupEntry[]; edges: Edg }) } - //create edges between the unit nodes - let edges: Edge[] = unitNodes.slice(0, -1).map((fromNode, index) => ({ + return { unitNodes, groups } +} + +function getScopeDetails(scopeLayer: TypeCount, indexGroups: GroupEntry[], stackIndex: number, parentGid: string) { + const scopeType = scopeLayer.type + const scopeName = scopeLayer.name + const indexGroupEntry = stackIndex < indexGroups.length ? indexGroups[stackIndex] : null + + let curGid = '' + + if (indexGroupEntry === null) { + curGid = uuid() + } else { + const indexEntryName = indexGroupEntry.index + const indexEntryGid = indexGroupEntry.gid + + switch (scopeType) { + case 'R': + curGid = scopeName >= indexEntryName ? indexEntryGid : uuid() + break + case 'F': + curGid = scopeName == indexEntryName ? indexEntryGid : uuid() + break + case 'D': + curGid = uuid() + break + case 'B': + curGid = scopeName == indexEntryName ? indexEntryGid : uuid() + break + default: + console.error('Unknown scope type') + } + } + + return { scopeType, scopeName, curGid } +} + +function createEdges(unitNodes: NodeEntry[]): Edge[] { + return unitNodes.slice(0, -1).map((fromNode, index) => ({ from_node: fromNode.gid, to_node: unitNodes[index + 1].gid, ...(fromNode.weight !== null && { weight: fromNode.weight }), })) - - // // Log all contents of edges - // console.log('Edges:') - // edges.forEach((edge, index) => { - // console.log(`Edge ${index}: from ${edge.from_node} to ${edge.to_node}, weight: ${edge.weight}`) - // }) - - // // Log all contents of groups - // console.log('Groups:') - // Object.entries(groups).forEach(([gid, group]) => { - // console.log( - // `Group ${gid}: letter: ${group.letter}, client_name: ${group.client_name}, name: ${group.index}, parentGid: ${group.parentGid}`, - // ) - // }) - - // Convert groups to an array - const groupArray: GroupEntry[] = Object.values(groups) - - return { nodes: groupArray, edges } -}) +} export const diagnositicsAtom = atom((get) => { const diagnostics = get(selectedDiagnosticsAtom) diff --git a/typescript/playground-common/src/shared/FunctionPanel.tsx b/typescript/playground-common/src/shared/FunctionPanel.tsx index 8d8d9f12b..b3eddda17 100644 --- a/typescript/playground-common/src/shared/FunctionPanel.tsx +++ b/typescript/playground-common/src/shared/FunctionPanel.tsx @@ -41,10 +41,10 @@ const CurlSnippet: React.FC = () => { return (
-
-