├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── actions │ ├── ollama │ │ └── action.yml │ └── run-examples │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── build.yml │ ├── mkdocs-gh-pages.yml │ ├── pdl-live-react-tests.yml │ ├── publish-quay.yaml │ ├── release-static-web-app.yml │ ├── release-ui.yml │ ├── release.yml │ ├── run-examples-prep.yml │ ├── run-examples.yml │ ├── rust-interpreter.yml │ └── tauri-cli.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── bandit.yaml ├── contrib └── prompt_library │ ├── CoT.pdl │ ├── ReAct.pdl │ ├── ReWoo.pdl │ └── tools.pdl ├── dockerfile ├── docs ├── .nojekyll ├── README.md ├── api_reference.md ├── assets │ ├── ai-governance--prompt.svg │ ├── animated_chatbot.gif │ ├── pdl-ui-1.png │ ├── pdl-ui-2.png │ ├── pdl-ui-3.png │ ├── pdl_quick_reference.pdf │ ├── pdl_quick_reference.png │ ├── telemetry.png │ └── ui.gif ├── autopdl.md ├── contrib.md ├── css │ └── index.css ├── stylesheets │ └── extra.css ├── telemetry.md ├── tutorial.md └── viewer.md ├── examples ├── callback │ ├── README.md │ ├── repair_main.py │ └── repair_prompt.pdl ├── chatbot │ └── chatbot.pdl ├── cldk │ ├── README.md │ └── cldk-assistant.pdl ├── code │ ├── README.md │ ├── code-eval.pdl │ ├── code-json-output.json │ ├── code-json.pdl │ ├── code.pdl │ ├── data.yaml │ └── ground_truth.txt ├── demo │ ├── 1-hello.pdl │ ├── 10-sdg.pdl │ ├── 11-repeat.pdl │ ├── 2-model-chaining.pdl │ ├── 3-def-use.pdl │ ├── 4-function.pdl │ ├── 5-code-eval.pdl │ ├── 6-code-json.pdl │ ├── 7-chatbot-roles.pdl │ ├── 8-tools.pdl │ ├── 9-react.pdl │ ├── data.yaml │ ├── ground_truth.txt │ └── qna.yaml ├── demos │ ├── granite_io_hallucinations.pdl │ ├── react.pdl │ ├── react_call.pdl │ ├── react_fun.pdl │ ├── repair_main.py │ ├── repair_prompt.pdl │ └── wiki.pdl ├── fibonacci │ └── fib.pdl ├── granite-io │ ├── granite_io_hallucinations.pdl │ ├── granite_io_openai.pdl │ ├── granite_io_thinking.pdl │ └── granite_io_transformers.pdl ├── gsm8k │ ├── README.md │ ├── demos.yaml │ ├── gsm8.pdl │ ├── gsm8k-plan-few-shots.pdl │ ├── gsm8k-plan.pdl │ ├── gsm8k-tot-few-shot.pdl │ ├── gsm8k-tot-multiplan.pdl │ └── gsm8k-tot.pdl ├── input │ ├── data.txt │ ├── input_test.pdl │ ├── input_test1.pdl │ └── input_test2.pdl ├── intrinsics │ ├── README.md │ ├── demo-hallucination.json │ └── demo-hallucination.pdl ├── notebooks │ ├── data.yaml │ ├── demo.ipynb │ ├── demonstrations.txt │ ├── granite_io_demo.ipynb │ ├── ground_truth.txt │ ├── notebook.ipynb │ ├── notebook_debug.ipynb │ └── pdl.ipynb ├── optimizer │ ├── __init__.py │ ├── config.yml │ ├── fever.pdl │ ├── fever_evaluator.py │ ├── gsm8k.pdl │ ├── gsm8k_evaluator.py │ ├── gsmhard_evaluator.py │ ├── mbpp.pdl │ ├── mbpp_dataset.py │ ├── mbpp_evaluator.py │ └── optimize.py ├── prompt_library │ ├── gsm8k_cot.pdl │ ├── gsm8k_react.pdl │ └── gsm8k_rewoo.pdl ├── rag │ ├── README.md │ ├── pdf_index.pdl │ ├── pdf_query.pdl │ ├── rag.py │ ├── rag_library1.pdl │ └── tfidf_rag.pdl ├── react │ ├── demo.pdl │ ├── demonstrations.txt │ ├── react_call.pdl │ └── react_fun.pdl ├── sdk │ ├── hello.pdl │ ├── hello_dict.py │ ├── hello_file.py │ ├── hello_prog.py │ └── hello_str.py ├── skeleton-of-thought │ ├── tips.pdl │ └── topic.jsonl ├── teacher │ ├── qna.yaml │ └── teacher.pdl ├── tools │ ├── calc.pdl │ ├── search.pdl │ └── wiki.pdl └── tutorial │ ├── calling_llm.pdl │ ├── calling_llm_chaining.pdl │ ├── calling_llm_with_input.pdl │ ├── calling_llm_with_input_messages.pdl │ ├── calling_llm_with_input_messages_var.pdl │ ├── code_command.pdl │ ├── code_jinja.pdl │ ├── code_pdl.pdl │ ├── code_python.pdl │ ├── data.txt │ ├── data.yaml │ ├── data_block_raw.pdl │ ├── defs-hello.pdl │ ├── defs.pdl │ ├── for.pdl │ ├── for_array.pdl │ ├── for_lastOf.pdl │ ├── for_multiple_lists.pdl │ ├── for_object.pdl │ ├── for_with.pdl │ ├── free_variables.pdl │ ├── function_alias.pdl │ ├── function_definition.pdl │ ├── function_empty_context.pdl │ ├── function_optional_params.pdl │ ├── if.pdl │ ├── import.pdl │ ├── import_lib.pdl │ ├── independent.pdl │ ├── independent_docs.pdl │ ├── independent_for.pdl │ ├── input.json │ ├── input_file.pdl │ ├── input_file_json.pdl │ ├── input_stdin.pdl │ ├── input_stdin_multiline.pdl │ ├── loop_index.pdl │ ├── muting_block_output.pdl │ ├── parser-regex.pdl │ ├── parser_findall.pdl │ ├── parser_regex_code.pdl │ ├── programs │ ├── chatbot.pdl │ ├── code-json.pdl │ ├── demo-hallucination.pdl │ ├── tfidf_rag.pdl │ └── weather.pdl │ ├── repeat.pdl │ ├── simple_program.pdl │ ├── structured_decoding.pdl │ ├── test.pdl │ ├── type_checking.pdl │ ├── type_checking_data.yaml │ ├── type_list.pdl │ ├── variable_def_use.pdl │ └── while.pdl ├── mkdocs.yml ├── mypy.ini ├── pdl-live-react ├── .editorconfig ├── .gitignore ├── .vscode │ └── extensions.json ├── README.md ├── demos │ ├── beeai │ │ └── test1.py │ ├── demo1.pdl │ ├── demo2.pdl │ ├── error.pdl │ ├── gen-data.yaml │ └── run.sh ├── eslint.config.js ├── index.html ├── package-lock.json ├── package.json ├── playwright.config.ts ├── public │ └── ai-governance--prompt.svg ├── src-tauri │ ├── .gitignore │ ├── .taurignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ ├── capabilities │ │ ├── default.json │ │ └── desktop.json │ ├── icons │ │ ├── 128x128.png │ │ ├── 128x128@2x.png │ │ ├── 32x32.png │ │ ├── icon.icns │ │ ├── icon.ico │ │ └── icon.png │ ├── src │ │ ├── cli.rs │ │ ├── commands │ │ │ ├── interpreter.rs │ │ │ ├── mod.rs │ │ │ ├── read_trace.rs │ │ │ └── replay_prep.rs │ │ ├── compile │ │ │ ├── beeai.rs │ │ │ └── mod.rs │ │ ├── gui.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── pdl │ │ │ ├── ast.rs │ │ │ ├── extract.rs │ │ │ ├── interpreter.rs │ │ │ ├── interpreter_tests.rs │ │ │ ├── mod.rs │ │ │ ├── pip.rs │ │ │ ├── pull.rs │ │ │ └── requirements.rs │ │ ├── util.rs │ │ └── util │ │ │ └── shasum.rs │ ├── tauri.conf.json │ └── tests │ │ ├── cli │ │ ├── call-no-args.pdl │ │ ├── call-with-args.pdl │ │ ├── code-python.pdl │ │ ├── data1.pdl │ │ ├── data2.pdl │ │ ├── data3.pdl │ │ ├── data4.pdl │ │ ├── if1.pdl │ │ ├── if2.pdl │ │ ├── include1.pdl │ │ ├── json-parser-lastOf.pdl │ │ ├── json-parser.pdl │ │ ├── jsonl-parser.pdl │ │ ├── model-input-array.pdl │ │ ├── model-input-nested.pdl │ │ ├── model-input-string.pdl │ │ ├── object1.pdl │ │ ├── object2.pdl │ │ ├── read-file.pdl │ │ ├── read-stdin.pdl │ │ ├── regex-findall.pdl │ │ ├── repeat1.pdl │ │ ├── repeat2.pdl │ │ ├── repeat3.pdl │ │ ├── scoping_1.pdl │ │ └── scoping_1_wrapper.pdl │ │ └── data │ │ ├── bee_1.py │ │ ├── foo.txt │ │ └── struct.yaml ├── src │ ├── App.tsx │ ├── assets │ │ ├── 404.png │ │ └── ai-governance--prompt.svg │ ├── demos │ │ ├── README.md │ │ ├── demo1.json │ │ ├── demo2.json │ │ ├── demo3.json │ │ ├── demo4.json │ │ ├── demo5.json │ │ ├── demo6.json │ │ ├── demo7.json │ │ ├── demo8.json │ │ ├── demo9.json │ │ └── demos.ts │ ├── helpers.ts │ ├── main.tsx │ ├── page │ │ ├── About.tsx │ │ ├── ClearMyTraces.tsx │ │ ├── DarkModeContext.ts │ │ ├── DarkModeToggle.tsx │ │ ├── Demo.tsx │ │ ├── DemoNavItems.tsx │ │ ├── Demos.tsx │ │ ├── ErrorBoundary.tsx │ │ ├── Local.tsx │ │ ├── Masthead.css │ │ ├── Masthead.tsx │ │ ├── MyTrace.tsx │ │ ├── MyTraces.ts │ │ ├── MyTracesNavItems.tsx │ │ ├── MyTracesPage.tsx │ │ ├── Page.css │ │ ├── Page.tsx │ │ ├── PageBreadcrumbDropdown.tsx │ │ ├── PageBreadcrumbDropdownItem.tsx │ │ ├── PageBreadcrumbs.css │ │ ├── PageBreadcrumbs.tsx │ │ ├── Run.css │ │ ├── Run.tsx │ │ ├── Sidebar.tsx │ │ ├── Uploader.css │ │ ├── Uploader.tsx │ │ └── welcome │ │ │ ├── Intro.tsx │ │ │ ├── Links.tsx │ │ │ ├── Tile.tsx │ │ │ ├── Tiles.tsx │ │ │ ├── Toolbar.tsx │ │ │ ├── Welcome.css │ │ │ ├── Welcome.tsx │ │ │ └── tiles │ │ │ ├── Demos.tsx │ │ │ └── MyTraces.tsx │ ├── pdl_ast.d.ts │ ├── pdl_ast_utils.ts │ ├── pdl_code_cleanup.ts │ ├── routes │ │ └── PdlRoutes.tsx │ ├── svg.d.ts │ ├── title.ts │ ├── view │ │ ├── CopyToClipboard.css │ │ ├── CopyToClipboard.tsx │ │ ├── Markdown.css │ │ ├── Markdown.tsx │ │ ├── Result.tsx │ │ ├── Value.tsx │ │ ├── breadcrumbs │ │ │ ├── BreadcrumbBar.css │ │ │ ├── BreadcrumbBar.tsx │ │ │ ├── BreadcrumbBarForBlock.tsx │ │ │ ├── BreadcrumbBarForBlockId.tsx │ │ │ ├── BreadcrumbBarItem.tsx │ │ │ └── Def.tsx │ │ ├── code │ │ │ ├── Code.tsx │ │ │ ├── CodeGroup.tsx │ │ │ ├── PreviewLight.css │ │ │ └── PreviewLight.tsx │ │ ├── detail │ │ │ ├── BlockNotFound.tsx │ │ │ ├── ContextTabContent.tsx │ │ │ ├── DefContent.css │ │ │ ├── DefContent.tsx │ │ │ ├── DrawerContent.css │ │ │ ├── DrawerContent.tsx │ │ │ ├── DrawerContentBody.tsx │ │ │ ├── Group.tsx │ │ │ ├── RawTraceTabContent.tsx │ │ │ ├── ResultTabContent.tsx │ │ │ ├── SourceTabContent.tsx │ │ │ ├── SummaryTabContent.tsx │ │ │ ├── UsageTabContent.tsx │ │ │ ├── find.ts │ │ │ └── kind │ │ │ │ ├── Call.tsx │ │ │ │ ├── Code.tsx │ │ │ │ ├── Data.tsx │ │ │ │ ├── Error.tsx │ │ │ │ ├── Function.tsx │ │ │ │ ├── If.tsx │ │ │ │ ├── Model.tsx │ │ │ │ ├── Read.tsx │ │ │ │ └── Text.tsx │ │ ├── masonry │ │ │ ├── Duration.css │ │ │ ├── Duration.tsx │ │ │ ├── Masonry.css │ │ │ ├── Masonry.tsx │ │ │ ├── MasonryCombo.tsx │ │ │ ├── MasonryTile.tsx │ │ │ ├── MasonryTileWrapper.tsx │ │ │ ├── RunMenu.tsx │ │ │ ├── Stability.css │ │ │ ├── Tile.ts │ │ │ ├── Toolbar.tsx │ │ │ ├── ToolbarPaginator.tsx │ │ │ ├── ToolbarReplayButton.tsx │ │ │ ├── ToolbarSMLToggle.tsx │ │ │ ├── ToolbarShowSourceButton.tsx │ │ │ ├── View.ts │ │ │ ├── condvar.ts │ │ │ ├── model.ts │ │ │ └── stability.ts │ │ ├── term │ │ │ ├── RunTerminal.css │ │ │ └── RunTerminal.tsx │ │ └── timeline │ │ │ ├── Timeline.css │ │ │ ├── Timeline.tsx │ │ │ ├── TimelineBar.tsx │ │ │ ├── TimelineFromModel.tsx │ │ │ ├── TimelineRow.tsx │ │ │ ├── TimelineRowKindCell.tsx │ │ │ └── model.ts │ ├── vite-env.d.ts │ └── window.d.ts ├── tests │ └── basics.spec.test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── pylintrc ├── pyproject.toml ├── scripts └── generate_pdl_examples_runner.sh ├── src └── pdl │ ├── __init__.py │ ├── optimize │ ├── __init__.py │ ├── config_parser.py │ ├── optimizer_evaluator.py │ ├── parse_number.py │ ├── pdl_optimizer.py │ └── util.py │ ├── pdl-schema.json │ ├── pdl.py │ ├── pdl_analysis.py │ ├── pdl_ast.py │ ├── pdl_ast_utils.py │ ├── pdl_compilers │ ├── __init__.py │ └── to_regex.py │ ├── pdl_context.py │ ├── pdl_dumper.py │ ├── pdl_granite_io.py │ ├── pdl_interpreter.py │ ├── pdl_lazy.py │ ├── pdl_linter.py │ ├── pdl_llms.py │ ├── pdl_location_utils.py │ ├── pdl_notebook_ext.py │ ├── pdl_parser.py │ ├── pdl_python_repl.py │ ├── pdl_runner.py │ ├── pdl_scheduler.py │ ├── pdl_schema_error_analyzer.py │ ├── pdl_schema_utils.py │ ├── pdl_schema_validator.py │ └── pdl_utils.py └── tests ├── __init__.py ├── data ├── call_expression_args.pdl ├── function.pdl ├── hello.pdl ├── input.json ├── input1.json ├── input_data.txt ├── line │ ├── hello.pdl │ ├── hello1.pdl │ ├── hello10.pdl │ ├── hello11.pdl │ ├── hello12.pdl │ ├── hello13.pdl │ ├── hello14.pdl │ ├── hello15.pdl │ ├── hello16.pdl │ ├── hello16_data.json │ ├── hello17.pdl │ ├── hello18.pdl │ ├── hello19.pdl │ ├── hello20.pdl │ ├── hello21.pdl │ ├── hello22.pdl │ ├── hello23.pdl │ ├── hello24.pdl │ ├── hello25.pdl │ ├── hello26.pdl │ ├── hello27.pdl │ ├── hello28.pdl │ ├── hello29.pdl │ ├── hello3.pdl │ ├── hello30.pdl │ ├── hello31.pdl │ ├── hello4.pdl │ ├── hello7.pdl │ ├── hello8.pdl │ └── hello9.pdl └── optimizer_gsm8k.pdl ├── results ├── contrib │ └── prompt_library │ │ ├── CoT.0.result │ │ ├── ReAct.0.result │ │ ├── ReWoo.0.result │ │ └── tools.0.result ├── examples │ ├── chatbot │ │ ├── chatbot.0.result │ │ └── chatbot.1.result │ ├── code │ │ ├── code-eval.0.result │ │ ├── code-eval.1.result │ │ ├── code-eval.2.result │ │ ├── code-json.0.result │ │ ├── code-json.1.result │ │ ├── code.0.result │ │ ├── code.1.result │ │ └── code.2.result │ ├── demo │ │ ├── 1-hello.0.result │ │ ├── 10-sdg.0.result │ │ ├── 10-sdg.1.result │ │ ├── 11-repeat.0.result │ │ ├── 2-model-chaining.0.result │ │ ├── 3-def-use.0.result │ │ ├── 3-def-use.1.result │ │ ├── 4-function.0.result │ │ ├── 4-function.1.result │ │ ├── 5-code-eval.0.result │ │ ├── 5-code-eval.1.result │ │ ├── 6-code-json.0.result │ │ ├── 6-code-json.1.result │ │ ├── 7-chatbot-roles.0.result │ │ ├── 7-chatbot-roles.1.result │ │ ├── 8-tools.0.result │ │ ├── 9-react.0.result │ │ ├── 9-react.1.result │ │ ├── 9-react.2.result │ │ ├── 9-react.3.result │ │ └── 9-react.4.result │ ├── demos │ │ └── react_fun.0.result │ ├── fibonacci │ │ ├── fib.0.result │ │ └── fib.1.result │ ├── input │ │ ├── input_test.0.result │ │ ├── input_test1.0.result │ │ └── input_test2.0.result │ ├── intrinsics │ │ └── demo-hallucination.0.result │ ├── prompt_library │ │ ├── gsm8k_cot.0.result │ │ ├── gsm8k_react.0.result │ │ └── gsm8k_rewoo.0.result │ ├── rag │ │ └── tfidf_rag.0.result │ ├── react │ │ ├── demo.0.result │ │ ├── demo.1.result │ │ ├── demo.2.result │ │ ├── demo.3.result │ │ ├── demo.4.result │ │ ├── demo.5.result │ │ ├── demo.6.result │ │ ├── react_call.0.result │ │ └── react_fun.0.result │ ├── sdk │ │ └── hello.0.result │ ├── skeleton-of-thought │ │ ├── tips.0.result │ │ └── tips.1.result │ ├── teacher │ │ ├── teacher.0.result │ │ └── teacher.1.result │ ├── tools │ │ ├── calc.0.result │ │ └── search.0.result │ └── tutorial │ │ ├── calling_llm.0.result │ │ ├── calling_llm_chaining.0.result │ │ ├── calling_llm_with_input.0.result │ │ ├── calling_llm_with_input_messages.0.result │ │ ├── calling_llm_with_input_messages_var.0.result │ │ ├── calling_llm_with_input_messages_var.1.result │ │ ├── code_command.0.result │ │ ├── code_jinja.0.result │ │ ├── code_pdl.0.result │ │ ├── code_python.0.result │ │ ├── code_python.1.result │ │ ├── data_block_raw.0.result │ │ ├── defs-hello.0.result │ │ ├── defs.0.result │ │ ├── defs.1.result │ │ ├── for.0.result │ │ ├── for_array.0.result │ │ ├── for_lastOf.0.result │ │ ├── for_multiple_lists.0.result │ │ ├── for_object.0.result │ │ ├── for_with.0.result │ │ ├── free_variables.0.result │ │ ├── function_alias.0.result │ │ ├── function_definition.0.result │ │ ├── function_definition.1.result │ │ ├── function_definition.2.result │ │ ├── function_empty_context.0.result │ │ ├── function_empty_context.1.result │ │ ├── function_optional_params.0.result │ │ ├── if.0.result │ │ ├── import.0.result │ │ ├── import_lib.0.result │ │ ├── independent.0.result │ │ ├── independent.1.result │ │ ├── independent_docs.0.result │ │ ├── independent_docs.1.result │ │ ├── independent_docs.2.result │ │ ├── independent_for.0.result │ │ ├── input_file.0.result │ │ ├── input_file_json.0.result │ │ ├── input_stdin.0.result │ │ ├── input_stdin_multiline.0.result │ │ ├── loop_index.0.result │ │ ├── muting_block_output.0.result │ │ ├── muting_block_output.1.result │ │ ├── parser-regex.0.result │ │ ├── parser_findall.0.result │ │ ├── parser_regex_code.0.result │ │ ├── parser_regex_code.1.result │ │ ├── programs │ │ ├── chatbot.0.result │ │ ├── chatbot.1.result │ │ ├── code-json.0.result │ │ ├── code-json.1.result │ │ ├── demo-hallucination.0.result │ │ ├── tfidf_rag.0.result │ │ ├── weather.0.result │ │ └── weather.1.result │ │ ├── repeat.0.result │ │ ├── simple_program.0.result │ │ ├── test.0.result │ │ ├── variable_def_use.0.result │ │ └── while.0.result ├── pdl-live-react │ ├── demos │ │ ├── demo1.0.result │ │ ├── demo2.0.result │ │ └── demo2.1.result │ └── src-tauri │ │ └── tests │ │ └── cli │ │ ├── call-no-args.0.result │ │ ├── call-with-args.0.result │ │ ├── code-python.0.result │ │ ├── data1.0.result │ │ ├── data2.0.result │ │ ├── data3.0.result │ │ ├── data4.0.result │ │ ├── if1.0.result │ │ ├── if2.0.result │ │ ├── include1.0.result │ │ ├── json-parser-lastOf.0.result │ │ ├── json-parser.0.result │ │ ├── jsonl-parser.0.result │ │ ├── model-input-array.0.result │ │ ├── model-input-nested.0.result │ │ ├── model-input-nested.1.result │ │ ├── model-input-string.0.result │ │ ├── object1.0.result │ │ ├── object2.0.result │ │ ├── read-file.0.result │ │ ├── regex-findall.0.result │ │ ├── regex-findall.1.result │ │ ├── repeat1.0.result │ │ ├── repeat2.0.result │ │ ├── repeat3.0.result │ │ ├── scoping_1.0.result │ │ ├── scoping_1_wrapper.0.result │ │ └── tips.0.result └── tests │ └── data │ ├── call_expression_args.12.result │ ├── function.0.result │ ├── hello.0.result │ └── optimizer_gsm8k.0.result ├── test_array.py ├── test_ast_utils.py ├── test_code.py ├── test_cond.py ├── test_context.py ├── test_data.py ├── test_defaults.py ├── test_defs.py ├── test_dump.py ├── test_errors.py ├── test_examples_parse.py ├── test_examples_run.py ├── test_examples_run.yaml ├── test_expr.py ├── test_fallback.py ├── test_for.py ├── test_function.py ├── test_include.py ├── test_independent.py ├── test_input.py ├── test_lib_version.py ├── test_line_table.py ├── test_linter.py ├── test_match.py ├── test_messages.py ├── test_model.py ├── test_object.py ├── test_optimizer.py ├── test_parse.py ├── test_parser.py ├── test_repeat.py ├── test_retry.py ├── test_role.py ├── test_runtime_errors.py ├── test_schema.py ├── test_type_checking.py └── test_var.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 89 3 | max-complexity = 18 4 | extend-ignore = E203, E501 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | PDL program and command 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Desktop (please complete the following information):** 23 | - OS: [e.g. iOS] 24 | - Browser [e.g. Chrome, Safari] 25 | - Version [e.g. 22] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | 13 | # Maintain dependencies for npm 14 | - package-ecosystem: "npm" 15 | directory: "/pdl-live" 16 | schedule: 17 | interval: "weekly" 18 | -------------------------------------------------------------------------------- /.github/workflows/pdl-live-react-tests.yml: -------------------------------------------------------------------------------- 1 | name: Viewer Tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | # cancel any prior runs for this workflow and this PR (or branch) 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | viewer: 16 | name: Test PDL live viewer 17 | runs-on: ubuntu-latest 18 | defaults: 19 | run: 20 | working-directory: ./pdl-live-react 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up node 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: 22 27 | - name: Install dependencies 28 | run: | 29 | npm ci & sudo apt update && sudo apt install -y libgtk-3-dev libwebkit2gtk-4.1-dev librsvg2-dev patchelf at-spi2-core 30 | wait 31 | - name: Install Playwright Browsers 32 | run: npx playwright install --with-deps 33 | - name: Test pdl-live viewer 34 | run: npm test 35 | -------------------------------------------------------------------------------- /.github/workflows/publish-quay.yaml: -------------------------------------------------------------------------------- 1 | name: Quay Publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: read 9 | 10 | env: 11 | REGISTRY: quay.io 12 | # github.repository as account/repo 13 | IMAGE_NAME: project_pdl/pdl 14 | 15 | jobs: 16 | # Build and push a multi-platform Docker image to Docker Hub 17 | publish-image: 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: read 21 | packages: write 22 | 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@v3 26 | 27 | - name: Docker Setup QEMU 28 | uses: docker/setup-qemu-action@v2 29 | 30 | - name: Set up Docker Buildx 31 | uses: docker/setup-buildx-action@v2 32 | 33 | - name: Login to Docker Hub 34 | uses: docker/login-action@v2 35 | with: 36 | registry: ${{ env.REGISTRY }} 37 | username: ${{ secrets.QUAYIO_USERNAME }} 38 | password: ${{ secrets.QUAYIO_TOKEN }} 39 | 40 | - name: Build and push ${{ github.ref_name }} to ${{ env.REGISTRY }} 41 | uses: docker/build-push-action@v4 42 | with: 43 | context: . 44 | platforms: linux/amd64,linux/arm64 45 | push: true 46 | tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest -------------------------------------------------------------------------------- /.github/workflows/run-examples.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Run examples 3 | 4 | on: 5 | schedule: 6 | - cron: '0 1 * * *' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | tests: 11 | name: Execution tests 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | python-version: ['3.11', '3.12', '3.13'] 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | ref: ${{ github.head_ref }} 21 | - uses: ./.github/actions/run-examples 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | runner-os: ${{ runner.os }} 25 | repository: ${{ github.repository }} 26 | head-ref: ${{ github.head_ref }} 27 | token: ${{ github.token }} 28 | update-results: 'false' 29 | check: '[]' # Empty list means run against all PDL programs 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/rust-interpreter.yml: -------------------------------------------------------------------------------- 1 | name: Rust Interpreter Tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | # cancel any prior runs for this workflow and this PR (or branch) 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | rust-interpreter: 16 | name: Test Rust interpreter 17 | runs-on: ubuntu-latest 18 | defaults: 19 | run: 20 | working-directory: ./pdl-live-react 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up node 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: 22 27 | - name: Install dependencies 28 | # sleep 2 to wait for ollama to be running... hack warning 29 | run: | 30 | npm ci & sudo apt update && sudo apt install -y libgtk-3-dev libwebkit2gtk-4.1-dev librsvg2-dev patchelf at-spi2-core & 31 | (curl -fsSL https://ollama.com/install.sh | sudo -E sh && sleep 2) 32 | wait 33 | - name: Run interpreter tests 34 | run: | 35 | python3.12 -mvenv venv 36 | source venv/bin/activate 37 | pip install nested-diff 38 | npm run test:interpreter 39 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "yaml.schemas": { 3 | "./src/pdl/pdl-schema.json": "*.pdl" 4 | }, 5 | "files.associations": { 6 | "*.pdl": "yaml", 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /bandit.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is the configuration file for the bandit python static analysis tool 3 | exclude_dirs: 4 | - build 5 | # We are less worried about tests, as they are not a part of the library meant to be used by users 6 | # with untrusted inputs. 7 | - test 8 | skips: 9 | - B101 # allow the use of assert 10 | -------------------------------------------------------------------------------- /dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-slim 2 | 3 | WORKDIR /pdl 4 | 5 | RUN apt-get update && apt-get install -y git 6 | 7 | COPY . /pdl 8 | 9 | RUN pip install prompt-declaration-language[examples] 10 | 11 | ENTRYPOINT ["pdl"] 12 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/.nojekyll -------------------------------------------------------------------------------- /docs/api_reference.md: -------------------------------------------------------------------------------- 1 | # API Reference 2 | 3 | This page documents the PDL members that likely to be used to run PDL programs from Python. 4 | 5 | ## Program 6 | ::: src.pdl.pdl_ast 7 | 8 | ## Interpreter 9 | ::: src.pdl.pdl 10 | 11 | 25 | -------------------------------------------------------------------------------- /docs/assets/animated_chatbot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/animated_chatbot.gif -------------------------------------------------------------------------------- /docs/assets/pdl-ui-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/pdl-ui-1.png -------------------------------------------------------------------------------- /docs/assets/pdl-ui-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/pdl-ui-2.png -------------------------------------------------------------------------------- /docs/assets/pdl-ui-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/pdl-ui-3.png -------------------------------------------------------------------------------- /docs/assets/pdl_quick_reference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/pdl_quick_reference.pdf -------------------------------------------------------------------------------- /docs/assets/pdl_quick_reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/pdl_quick_reference.png -------------------------------------------------------------------------------- /docs/assets/telemetry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/telemetry.png -------------------------------------------------------------------------------- /docs/assets/ui.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/docs/assets/ui.gif -------------------------------------------------------------------------------- /docs/css/index.css: -------------------------------------------------------------------------------- 1 | html,body { 2 | font-family: 'IBM Plex Sans', 'Helvetica Neue', Arial, sans-serif; 3 | background: var(--cds-background, #ffffff); 4 | } 5 | 6 | #mainview { 7 | margin-top: 4rem; 8 | height: calc(100% - 4rem); 9 | } 10 | -------------------------------------------------------------------------------- /docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --md-primary-fg-color: #0f62fe; 3 | --md-primary-fg-color--light: #4589ff; 4 | --md-primary-fg-color--dark: #002d9c; 5 | } -------------------------------------------------------------------------------- /docs/viewer.md: -------------------------------------------------------------------------------- 1 | --- 2 | hide: 3 | - navigation 4 | - toc 5 | - footer 6 | --- 7 | 8 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/callback/README.md: -------------------------------------------------------------------------------- 1 | # Callback example 2 | 3 | This example shows a Python program `repair_main.py` that calls a PDL program `repair_prompt.pdl` through the SDK. Then, `repair_prompt.pdl` calls a function `parse_output` defined in `repair_main.py` to obtain more information. Finally, the PDL program returns to Python an output that the Python code prints. In this example, all data is passed back and forth between Python and PDL using JSON. This JSON data is type-checked using `TypedDict` on the Python side and using `spec` on the PDL side. 4 | 5 | To run: 6 | 7 | ``` 8 | python repair_main.py 9 | ``` 10 | 11 | Expected output: 12 | 13 | ``` 14 | ---- before call to PDL ---- 15 | ---- during callback from PDL ---- 16 | ---- after return from PDL ---- 17 | {'before': "print('Hello, world!']", 'after': "print('Hello, world!')"} 18 | ``` -------------------------------------------------------------------------------- /examples/callback/repair_main.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import TypedDict, cast 3 | 4 | import pdl.pdl 5 | 6 | PDLScope = TypedDict("PDLScope", {"code_line": str, "error_msg": str}) 7 | ParsedOutput = TypedDict("ParsedOutput", {"thought": str, "code_line": str | None}) 8 | PDLResult = TypedDict("PDLResult", {"before": str, "after": str | None}) 9 | 10 | 11 | def parse_output(raw_output: str) -> ParsedOutput: 12 | print("---- during callback from PDL ----") 13 | match_start = re.search(r"```python\s", raw_output) 14 | if not match_start: 15 | return ParsedOutput(thought=raw_output, code_line=None) 16 | thought = raw_output[: match_start.start()] 17 | rest = raw_output[match_start.end() :] 18 | match_end = re.search(r"\s```", rest) 19 | if not match_end: 20 | return ParsedOutput(thought=thought, code_line=rest) 21 | return ParsedOutput(thought=thought, code_line=rest[: match_end.start()]) 22 | 23 | 24 | if __name__ == "__main__": 25 | pdl_input = PDLScope( 26 | code_line="print('Hello, world!']", 27 | error_msg="SyntaxError: closing parenthesis ']' does not match opening '('", 28 | ) 29 | print("---- before call to PDL ----") 30 | pdl_output: PDLResult = pdl.pdl.exec_file( 31 | "./repair_prompt.pdl", scope=cast(pdl.pdl.ScopeType, pdl_input) 32 | ) 33 | print("---- after return from PDL ----") 34 | print(pdl_output) 35 | -------------------------------------------------------------------------------- /examples/callback/repair_prompt.pdl: -------------------------------------------------------------------------------- 1 | lastOf: 2 | - | 3 | Given the following code: 4 | ```python 5 | ${code_line} 6 | ``` 7 | and the following error: 8 | ${error_msg} 9 | Please repair the code! 10 | 11 | - def: raw_output 12 | model: ollama_chat/granite3.2:2b 13 | parameters: 14 | temperature: 0 15 | 16 | - lang: python 17 | def: parsed_output 18 | spec: {thought: string, code_line: string} 19 | code: | 20 | import repair_main 21 | # (In PDL, set `result` to the output you wish for your code block.) 22 | result = repair_main.parse_output(raw_output) 23 | 24 | - spec: {before: string, after: string} 25 | object: 26 | before: ${code_line} 27 | after: ${parsed_output.code_line} 28 | -------------------------------------------------------------------------------- /examples/chatbot/chatbot.pdl: -------------------------------------------------------------------------------- 1 | description: A Chatbot that responds to user's questions 2 | text: 3 | # Allow the user to type any question, implicitly adding the question to the context. 4 | - read: 5 | message: "What is your query?\n" 6 | - repeat: 7 | text: 8 | # Send context to Granite model hosted at ollama 9 | - model: ollama_chat/granite3.2:2b 10 | # Allow the user to type 'yes', 'no', or anything else, storing 11 | # the input into a variable named `eval`. The input is also implicitly 12 | # added to the context. 13 | - read: 14 | def: eval 15 | message: "\nIs this a good answer[yes/no]?\n" 16 | - "\n" 17 | # If the user only typed "no", prompt the user for input to add to the context. 18 | - if: ${ eval == 'no' } 19 | then: 20 | text: 21 | - read: 22 | message: "Why not?\n" 23 | # If the user typed only "yes", finish the `repeat` and end the program 24 | until: ${ eval == 'yes'} 25 | -------------------------------------------------------------------------------- /examples/cldk/README.md: -------------------------------------------------------------------------------- 1 | The PDL program `cldk-assistant.pdl` makes use of the [CLDK](https://github.com/IBM/codellm-devkit) toolkit to analyze a Java project and answer user questions about the project. 2 | 3 | To install CLDK: 4 | ``` 5 | pip install git+https://github.com/IBM/codellm-devkit.git 6 | ``` 7 | 8 | For example, download the `commons-cli` Java project as follows: 9 | ``` 10 | wget https://github.com/apache/commons-cli/archive/refs/tags/rel/commons-cli-1.7.0.zip -O commons-cli-1.7.0.zip && unzip commons-cli-1.7.0.zip 11 | ``` 12 | 13 | To run the CLDK assistant: 14 | ``` 15 | pdl cldk-assistant.pdl 16 | ``` 17 | 18 | Enter the path to the above Java project when prompted. Then you can make queries such as "what are all the classes?". -------------------------------------------------------------------------------- /examples/code/code-json-output.json: -------------------------------------------------------------------------------- 1 | {"input": {"source_code": "@SuppressWarnings(\"unchecked\")\npublic static Map deserializeOffsetMap(String lastSourceOffset) throws IOException {\n Map offsetMap;\n if (lastSourceOffset == null || lastSourceOffset.isEmpty()) { \n offsetMap = new HashMap<>(); \n } else {\n offsetMap = JSON_MAPPER.readValue(lastSourceOffset, Map.class); \n }\n return offsetMap;\n}\n", "repo_info": {"repo": "streamsets/datacollector", "path": "stagesupport/src/main/java/com/.../OffsetUtil.java", "function_name": "OffsetUtil.deserializeOffsetMap"}}, "output": "\nThe function `deserializeOffsetMap` takes a string as input and returns a map. It first checks if the input string is null or empty. If it is, it creates a new empty map and returns it. Otherwise, it uses the Jackson library to parse the input string into a map and returns it.\n\nThe `@SuppressWarnings(\"unchecked\")` annotation is used to suppress the warning that the type of the parsed map is not checked. This is because the Jackson library is used to parse the input string into a map, but the specific type of the map is not known at compile time. Therefore, the warning is suppressed to avoid potential issues.", "metric": 0.9967637540453075} 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/code/code-json.pdl: -------------------------------------------------------------------------------- 1 | description: Code explanation example 2 | defs: 3 | CODE: 4 | read: ./data.yaml 5 | parser: yaml 6 | TRUTH: 7 | read: ./ground_truth.txt 8 | lastOf: 9 | - model: ollama_chat/granite3.2:2b 10 | def: EXPLANATION 11 | input: 12 | | 13 | Here is some info about the location of the function in the repo. 14 | repo: 15 | ${ CODE.repo_info.repo } 16 | path: ${ CODE.repo_info.path } 17 | Function_name: ${ CODE.repo_info.function_name } 18 | 19 | 20 | Explain the following code: 21 | ``` 22 | ${ CODE.source_code }``` 23 | - def: EVAL 24 | lang: python 25 | code: 26 | | 27 | import textdistance 28 | expl = """ 29 | ${ EXPLANATION } 30 | """ 31 | truth = """ 32 | ${ TRUTH } 33 | """ 34 | result = textdistance.levenshtein.normalized_similarity(expl, truth) 35 | - data: 36 | input: ${ CODE } 37 | output: ${ EXPLANATION } 38 | metric: ${ EVAL } 39 | 40 | -------------------------------------------------------------------------------- /examples/code/code.pdl: -------------------------------------------------------------------------------- 1 | description: Code explanation example 2 | defs: 3 | # Read data.yaml as YAML and store it in a variable `CODE` 4 | CODE: 5 | read: ./data.yaml 6 | parser: yaml 7 | text: 8 | # Output the `source_code:` of the YAML to the console 9 | - "\n${ CODE.source_code }\n" 10 | # Use ollama to invoke a Granite model with a prompt 11 | - model: ollama_chat/granite3.2:2b 12 | input: | 13 | Here is some info about the location of the function in the repo. 14 | repo: 15 | ${ CODE.repo_info.repo } 16 | path: ${ CODE.repo_info.path } 17 | Function_name: ${ CODE.repo_info.function_name } 18 | 19 | 20 | Explain the following code: 21 | ``` 22 | ${ CODE.source_code }``` 23 | parameters: 24 | # Use no LLM creativity. (Note that 0 is the default; this line has no effect) 25 | temperature: 0 -------------------------------------------------------------------------------- /examples/code/data.yaml: -------------------------------------------------------------------------------- 1 | source_code: 2 | | 3 | @SuppressWarnings("unchecked") 4 | public static Map deserializeOffsetMap(String lastSourceOffset) throws IOException { 5 | Map offsetMap; 6 | if (lastSourceOffset == null || lastSourceOffset.isEmpty()) { 7 | offsetMap = new HashMap<>(); 8 | } else { 9 | offsetMap = JSON_MAPPER.readValue(lastSourceOffset, Map.class); 10 | } 11 | return offsetMap; 12 | } 13 | repo_info: 14 | repo: streamsets/datacollector 15 | path: stagesupport/src/main/java/com/.../OffsetUtil.java 16 | function_name: OffsetUtil.deserializeOffsetMap 17 | -------------------------------------------------------------------------------- /examples/code/ground_truth.txt: -------------------------------------------------------------------------------- 1 | The function `deserializeOffsetMap` takes a string as input and returns a map. It first checks if the input string is null or empty. If it is, it creates a new empty map and returns it. Otherwise, it uses the Jackson library to parse the input string into a map and returns it. 2 | 3 | The `@SuppressWarnings("unchecked")` annotation is used to suppress the warning that the type of the parsed map is not checked. This is because the Jackson library is used to parse the input string into a map, but the specific type of the map is not known at compile time. Therefore, the warning is suppressed to avoid potential issues. 4 | -------------------------------------------------------------------------------- /examples/demo/1-hello.pdl: -------------------------------------------------------------------------------- 1 | description: Model call 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | parameters: 6 | stop: ["!"] 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/demo/11-repeat.pdl: -------------------------------------------------------------------------------- 1 | description: Loop semantics 2 | defs: 3 | numbers: 4 | data: [1, 2, 3, 4] 5 | names: 6 | data: ["Bob", "Carol", "David", "Ernest"] 7 | for: 8 | number: ${ numbers } 9 | name: ${ names } 10 | repeat: 11 | text: 12 | - "${ name }'s number is ${ number }\n" 13 | - data: 14 | name: ${ name } 15 | number: ${ number } 16 | join: 17 | with: "\n" -------------------------------------------------------------------------------- /examples/demo/2-model-chaining.pdl: -------------------------------------------------------------------------------- 1 | description: Model chaining 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | parameters: 6 | stop: ["!"] 7 | - "\nDid you just say Hello?\n" 8 | - model: ollama_chat/granite3.2:2b 9 | parameters: 10 | stop: ["!"] 11 | -------------------------------------------------------------------------------- /examples/demo/3-def-use.pdl: -------------------------------------------------------------------------------- 1 | description: Variable def and use, model input 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | def: name 6 | parameters: 7 | stop: ["!"] 8 | - "\n" 9 | - model: ollama_chat/granite3.2:2b 10 | input: "Translate the word ${ name | trim } to French\n" 11 | parameters: 12 | stop: ["\n"] 13 | temperature: 0 14 | -------------------------------------------------------------------------------- /examples/demo/4-function.pdl: -------------------------------------------------------------------------------- 1 | description: Function def and call 2 | text: 3 | - def: translate 4 | function: 5 | sentence: string 6 | language: string 7 | return: 8 | lastOf: 9 | - "\nTranslate the sentence '${ sentence }' to ${ language }.\n" 10 | - model: ollama_chat/granite3.2:2b 11 | parameters: 12 | stop: ["\n"] 13 | temperature: 0 14 | - call: ${ translate } 15 | args: 16 | sentence: I love Paris! 17 | language: French 18 | - "\n" 19 | - call: ${ translate } 20 | args: 21 | sentence: I love Madrid! 22 | language: Spanish 23 | -------------------------------------------------------------------------------- /examples/demo/6-code-json.pdl: -------------------------------------------------------------------------------- 1 | description: Code explanation example 2 | defs: 3 | CODE: 4 | read: ./data.yaml 5 | parser: yaml 6 | TRUTH: 7 | read: ./ground_truth.txt 8 | text: 9 | - model: ollama_chat/granite3.2:2b 10 | def: EXPLANATION 11 | contribute: [] 12 | input: 13 | | 14 | Here is some info about the location of the function in the repo. 15 | repo: 16 | ${ CODE.repo_info.repo } 17 | path: ${ CODE.repo_info.path } 18 | Function_name: ${ CODE.repo_info.function_name } 19 | 20 | 21 | Explain the following code: 22 | ``` 23 | ${ CODE.source_code }``` 24 | parameters: 25 | temperature: 0 26 | - def: EVAL 27 | contribute: [] 28 | lang: python 29 | code: 30 | | 31 | import textdistance 32 | expl = """ 33 | ${ EXPLANATION } 34 | """ 35 | truth = """ 36 | ${ TRUTH } 37 | """ 38 | # (In PDL, set `result` to the output you wish for your code block.) 39 | result = textdistance.levenshtein.normalized_similarity(expl, truth) 40 | - data: 41 | input: ${ CODE } 42 | output: ${ EXPLANATION } 43 | metric: ${ EVAL } 44 | 45 | -------------------------------------------------------------------------------- /examples/demo/7-chatbot-roles.pdl: -------------------------------------------------------------------------------- 1 | description: Chatbot, control structures, roles, contribute 2 | text: 3 | - role: system 4 | contribute: [context] 5 | text: You are Granite, an AI language model developed by IBM in 2024. 6 | - "Type `quit` to exit this chatbot.\n" 7 | - repeat: 8 | text: 9 | - read: 10 | message: ">>> " 11 | def: query 12 | contribute: [context] 13 | - model: ollama_chat/granite3.2:2b 14 | - "\n\n" 15 | until: ${ query == 'quit'} 16 | join: 17 | with: "\n\n" 18 | role: user 19 | -------------------------------------------------------------------------------- /examples/demo/8-tools.pdl: -------------------------------------------------------------------------------- 1 | description: Tool use 2 | defs: 3 | tools: 4 | data: 5 | - name: calc 6 | description: Calculator function 7 | arguments: 8 | expr: 9 | type: string 10 | description: Arithmetic expression to calculate 11 | text: 12 | - role: system 13 | text: You are Granite, developed by IBM. You are a helpful AI assistant with access to the following tools. When a tool is required to answer the user's query, respond with <|tool_call|> followed by a JSON list of tools used. If a tool does not exist in the provided list of tools, notify the user that you do not have the ability to fulfill the request. 14 | contribute: [context] 15 | - role: tools 16 | content: 17 | text: ${ tools } 18 | contribute: [context] 19 | - "Out of 1400 participants, 400 passed the test. What percentage is that?\n" 20 | - def: actions 21 | model: ollama_chat/granite3.2:8b 22 | parser: json 23 | spec: [{ name: string, arguments: { expr: string }}] 24 | parameters: 25 | drop_params: true 26 | - "\n" 27 | - if: ${ actions[0].name == "calc" } 28 | then: 29 | text: 30 | - lang: python 31 | code: result = ${ actions[0].arguments.expr } -------------------------------------------------------------------------------- /examples/demo/data.yaml: -------------------------------------------------------------------------------- 1 | source_code: 2 | | 3 | @SuppressWarnings("unchecked") 4 | public static Map deserializeOffsetMap(String lastSourceOffset) throws IOException { 5 | Map offsetMap; 6 | if (lastSourceOffset == null || lastSourceOffset.isEmpty()) { 7 | offsetMap = new HashMap<>(); 8 | } else { 9 | offsetMap = JSON_MAPPER.readValue(lastSourceOffset, Map.class); 10 | } 11 | return offsetMap; 12 | } 13 | repo_info: 14 | repo: streamsets/datacollector 15 | path: stagesupport/src/main/java/com/.../OffsetUtil.java 16 | function_name: OffsetUtil.deserializeOffsetMap -------------------------------------------------------------------------------- /examples/demo/ground_truth.txt: -------------------------------------------------------------------------------- 1 | The function `deserializeOffsetMap` takes a string as input and returns a map. It first checks if the input string is null or empty. If it is, it creates a new empty map and returns it. Otherwise, it uses the Jackson library to parse the input string into a map and returns it. 2 | 3 | The `@SuppressWarnings("unchecked")` annotation is used to suppress the warning that the type of the parsed map is not checked. This is because the Jackson library is used to parse the input string into a map, but the specific type of the map is not known at compile time. Therefore, the warning is suppressed to avoid potential issues. -------------------------------------------------------------------------------- /examples/demo/qna.yaml: -------------------------------------------------------------------------------- 1 | task_description: to teach a large language model to come up with puns 2 | created_by: mizmo 3 | seed_examples: 4 | - question: Tell me a pun about birds. 5 | answer: |- 6 | Why do birds eat wood? 7 | Because they're peckish! 8 | - question: Tell me a pun about gas. 9 | answer: |- 10 | Why did the car have a belly ache? 11 | Because it had too much gas! 12 | - question: Tell me a pun about waves. 13 | answer: |- 14 | What did the ocean say to the ocean? 15 | Nothing. It just waved! -------------------------------------------------------------------------------- /examples/demos/react_call.pdl: -------------------------------------------------------------------------------- 1 | description: Wikipedia example using the react_fun function definition 2 | text: 3 | - import: react_fun 4 | def: lib 5 | - call: ${ lib.react } 6 | args: 7 | question: "How many years ago was the discoverer of the Hudson River born? Keep in mind we are in 2025. When searching avoid using the words discovery or birthday.\n" 8 | model: ollama_chat/granite3.3:8b 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/demos/repair_main.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import TypedDict, cast 3 | 4 | import pdl.pdl 5 | 6 | PDLScope = TypedDict("PDLScope", {"code_line": str, "error_msg": str}) 7 | ParsedOutput = TypedDict("ParsedOutput", {"thought": str, "code_line": str | None}) 8 | PDLResult = TypedDict("PDLResult", {"before": str, "after": str | None}) 9 | 10 | 11 | def parse_output(raw_output: str) -> ParsedOutput: 12 | print("---- during callback from PDL ----") 13 | match_start = re.search(r"```python\s", raw_output) 14 | if not match_start: 15 | return ParsedOutput(thought=raw_output, code_line=None) 16 | thought = raw_output[: match_start.start()] 17 | rest = raw_output[match_start.end() :] 18 | match_end = re.search(r"\s```", rest) 19 | if not match_end: 20 | return ParsedOutput(thought=thought, code_line=rest) 21 | return ParsedOutput(thought=thought, code_line=rest[: match_end.start()]) 22 | 23 | 24 | if __name__ == "__main__": 25 | pdl_input = PDLScope( 26 | code_line="print('Hello, world!']", 27 | error_msg="SyntaxError: closing parenthesis ']' does not match opening '('", 28 | ) 29 | print("---- before call to PDL ----") 30 | pdl_output: PDLResult = pdl.pdl.exec_file( 31 | "./repair_prompt.pdl", scope=cast(pdl.pdl.ScopeType, pdl_input) 32 | ) 33 | print("---- after return from PDL ----") 34 | print(pdl_output) 35 | -------------------------------------------------------------------------------- /examples/demos/repair_prompt.pdl: -------------------------------------------------------------------------------- 1 | lastOf: 2 | - | 3 | Given the following code: 4 | ```python 5 | ${code_line} 6 | ``` 7 | and the following error: 8 | ${error_msg} 9 | Please repair the code! 10 | 11 | - def: raw_output 12 | model: ollama_chat/granite3.2:2b 13 | parameters: 14 | temperature: 0 15 | 16 | - lang: python 17 | def: parsed_output 18 | spec: {thought: string, code_line: string} 19 | code: | 20 | import repair_main 21 | # (In PDL, set `result` to the output you wish for your code block.) 22 | result = repair_main.parse_output(raw_output) 23 | 24 | - spec: {before: string, after: string} 25 | object: 26 | before: ${code_line} 27 | after: ${parsed_output.code_line} 28 | -------------------------------------------------------------------------------- /examples/demos/wiki.pdl: -------------------------------------------------------------------------------- 1 | description: tool use 2 | defs: 3 | tools: 4 | data: 5 | - name: search 6 | description: Wikipedia search 7 | parameters: 8 | type: object 9 | properties: 10 | topic: 11 | type: string 12 | description: Topic to search 13 | text: 14 | - role: system 15 | content: | 16 | You are a helpful AI assistant with access to the following tools. 17 | If a tool does not exist in the provided list of tools, notify the user 18 | that you do not have the ability to fulfill the request. 19 | contribute: [context] 20 | - role: tools 21 | content: 22 | text: ${ tools } 23 | contribute: [context] 24 | - "What is the circumference of planet Earth?\n" 25 | - def: actions 26 | model: ollama_chat/granite3.3:8b 27 | parser: json 28 | spec: [{ name: string, arguments: { topic: string }}] 29 | - "\n" 30 | - if: ${ actions[0].name == "search" } 31 | then: 32 | lang: python 33 | code: | 34 | import warnings, wikipedia 35 | warnings.simplefilter("ignore") 36 | try: 37 | result = wikipedia.summary("${ actions[0].arguments.topic }") 38 | except wikipedia.WikipediaException as e: 39 | result = str(e) -------------------------------------------------------------------------------- /examples/granite-io/granite_io_openai.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - "Hello!\n" 3 | - model: "granite3.2:2b" 4 | backend: openai 5 | -------------------------------------------------------------------------------- /examples/granite-io/granite_io_thinking.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - | 3 | Find the fastest way for a seller to visit all the cities in their region 4 | >> Response: 5 | - model: "granite3.2:2b" 6 | backend: openai 7 | parameters: 8 | thinking: true 9 | modelResponse: outputs 10 | - "\n" 11 | - | 12 | >> Thoughts: 13 | ${ outputs.results[0].next_message.reasoning_content } 14 | -------------------------------------------------------------------------------- /examples/granite-io/granite_io_transformers.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - "Hello!\n" 3 | - model: ibm-granite/granite-3.2-2b-instruct 4 | backend: 5 | transformers: cpu 6 | processor: granite3.2 7 | -------------------------------------------------------------------------------- /examples/gsm8k/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Grade School Math 3 | 4 | This demo measures success with 5 | [Grade School Math](https://github.com/openai/grade-school-math), 6 | an open source AI dataset from 2021. 7 | 8 | Before running the example, you must download the dataset: 9 | 10 | ```bash 11 | curl https://raw.githubusercontent.com/openai/grade-school-math/refs/heads/master/grade_school_math/data/test.jsonl > test.jsonl 12 | ``` 13 | 14 | To run, do `pdl --stream none gsm8.pdl`. 15 | 16 | The example version attempts to do the first 50 questions in that example 17 | using `ollama/granite3.2:8b`. If you are using Ollama, you should first do 18 | 19 | ```bash 20 | ollama pull granite3.2:8b 21 | ``` 22 | 23 | To get the model. 24 | 25 | You may change the model and model host used, and the number of questions tested, by editing the file. 26 | -------------------------------------------------------------------------------- /examples/input/data.txt: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /examples/input/input_test.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | defs: 3 | file: ./data.txt 4 | text: 5 | - read: ${ file } 6 | def: HELLO 7 | contribute: [] 8 | - get: HELLO -------------------------------------------------------------------------------- /examples/input/input_test1.pdl: -------------------------------------------------------------------------------- 1 | description: PDL code with input block 2 | text: 3 | - "The following will prompt the user on stdin.\n" 4 | - read: 5 | message: "Please provide an input: " 6 | def: STDIN 7 | contribute: [] 8 | - ${ STDIN } 9 | 10 | -------------------------------------------------------------------------------- /examples/input/input_test2.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | text: 3 | - "A multiline stdin input.\n" 4 | - read: 5 | multiline: True 6 | -------------------------------------------------------------------------------- /examples/notebooks/data.yaml: -------------------------------------------------------------------------------- 1 | source_code: 2 | | 3 | @SuppressWarnings("unchecked") 4 | public static Map deserializeOffsetMap(String lastSourceOffset) throws IOException { 5 | Map offsetMap; 6 | if (lastSourceOffset == null || lastSourceOffset.isEmpty()) { 7 | offsetMap = new HashMap<>(); 8 | } else { 9 | offsetMap = JSON_MAPPER.readValue(lastSourceOffset, Map.class); 10 | } 11 | return offsetMap; 12 | } 13 | repo_info: 14 | repo: streamsets/datacollector 15 | path: stagesupport/src/main/java/com/.../OffsetUtil.java 16 | function_name: OffsetUtil.deserializeOffsetMap -------------------------------------------------------------------------------- /examples/notebooks/ground_truth.txt: -------------------------------------------------------------------------------- 1 | The function `deserializeOffsetMap` takes a string as input and returns a map. It first checks if the input string is null or empty. If it is, it creates a new empty map and returns it. Otherwise, it uses the Jackson library to parse the input string into a map and returns it. 2 | 3 | The `@SuppressWarnings("unchecked")` annotation is used to suppress the warning that the type of the parsed map is not checked. This is because the Jackson library is used to parse the input string into a map, but the specific type of the map is not known at compile time. Therefore, the warning is suppressed to avoid potential issues. -------------------------------------------------------------------------------- /examples/optimizer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/examples/optimizer/__init__.py -------------------------------------------------------------------------------- /examples/optimizer/config.yml: -------------------------------------------------------------------------------- 1 | benchmark: "gsm8k" 2 | initial_test_set_size: 1 3 | max_test_set_size: 1 4 | num_candidates: 5 5 | num_demonstrations: 3 6 | parallelism: 1 7 | shuffle_test: false 8 | test_set_name: "test" 9 | train_set_name: "train" 10 | timeout: 120 11 | experiment_prefix: "granite_3_8b_instruct_gsm8k_3_shot_" 12 | variables: 13 | model: 14 | - "watsonx_text/ibm/granite-3-8b-instruct" 15 | prompt_pattern: 16 | - "cot" 17 | num_demonstrations: 18 | - 3 19 | -------------------------------------------------------------------------------- /examples/rag/README.md: -------------------------------------------------------------------------------- 1 | ## pdf_query example 2 | 3 | This example uses [Ollama](../../tutorial/#using-ollama-models). Fetch the models used in this example with 4 | 5 | ```bash 6 | ollama pull mxbai-embed-large 7 | ollama pull granite-code:8b 8 | ``` 9 | 10 | This example requires you to install pypdf, langchain, langchain-community, and milvus. 11 | 12 | ```bash 13 | pip install pypdf milvus langchain langchain-community 14 | ``` 15 | 16 | To run the demo, first load a PDF document into the vector database: 17 | 18 | ```bash 19 | pdl examples/rag/pdf_index.pdl 20 | ``` 21 | 22 | After the data has loaded, the program prints "Success!" 23 | 24 | Next, query the vector database for relevant text and use that text in a query to an LLM: 25 | 26 | ```bash 27 | pdl examples/rag/pdf_query.pdl 28 | ``` 29 | 30 | This PDL program computes a data structure containing all questions and answers. It is printed at the end. 31 | 32 | To cleanup, run `rm pdl-rag-demo.db`. 33 | 34 | ## tdidf_rag example 35 | 36 | This example requires you to install: 37 | ``` 38 | pip install scikit-learn 39 | ``` -------------------------------------------------------------------------------- /examples/rag/pdf_index.pdl: -------------------------------------------------------------------------------- 1 | # Load PDF document into vector database 2 | 3 | description: Load document into vector database 4 | text: 5 | - include: rag_library1.pdl 6 | - call: ${ pdf_parse } 7 | args: 8 | filename: "docs/assets/pdl_quick_reference.pdf" 9 | chunk_size: 400 10 | chunk_overlap: 100 11 | def: input_data 12 | contribute: [] 13 | - call: ${ rag_index } 14 | args: 15 | inp: ${ input_data } 16 | encoder_model: "ollama/mxbai-embed-large" 17 | embed_dimension: 1024 18 | database_name: "./pdl-rag-demo.db" 19 | collection_name: "pdl_rag_collection" 20 | contribute: [] 21 | - "Success!" 22 | -------------------------------------------------------------------------------- /examples/rag/rag_library1.pdl: -------------------------------------------------------------------------------- 1 | # This module can be included from a PDL program to bring in Python functions. 2 | 3 | description: RAG library for PDL 4 | text: 5 | - def: pdf_parse 6 | function: 7 | filename: string 8 | chunk_size: integer 9 | chunk_overlap: integer 10 | return: 11 | lang: python 12 | code: | 13 | import rag 14 | result = rag.parse(filename, chunk_size, chunk_overlap) 15 | - def: rag_index 16 | function: 17 | inp: [string] 18 | encoder_model: string 19 | embed_dimension: integer 20 | database_name: string # optional, could also be URL? 21 | collection_name: string 22 | return: 23 | lang: python 24 | code: | 25 | import rag 26 | result = rag.rag_index(inp, encoder_model, embed_dimension, database_name, collection_name) 27 | - def: rag_retrieve 28 | function: 29 | inp: string 30 | encoder_model: string 31 | limit: integer 32 | collection_name: string 33 | database_name: string # optional, could also be URL? 34 | return: 35 | lang: python 36 | code: | 37 | import rag 38 | result = rag.rag_retrieve(inp, encoder_model, limit, database_name, collection_name) 39 | -------------------------------------------------------------------------------- /examples/react/react_call.pdl: -------------------------------------------------------------------------------- 1 | description: Wikipedia example using the react_fun function definition 2 | text: 3 | - import: react_fun 4 | def: lib 5 | - call: ${ lib.react } 6 | args: 7 | question: "How many years ago was the discoverer of the Hudson River born? Keep in mind we are in 2025. When searching avoid using the words discovery or birthday.\n" 8 | model: ollama_chat/granite3.3:8b 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/sdk/hello.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - "Hello\n" 3 | - model: ollama_chat/granite3.2:2b 4 | parameters: 5 | stop: ['!'] 6 | -------------------------------------------------------------------------------- /examples/sdk/hello_dict.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_dict 2 | 3 | hello = { 4 | "text": [ 5 | "Hello\n", 6 | { 7 | "model": "ollama_chat/granite3.2:2b", 8 | "parameters": { 9 | "stop": ["!"], 10 | }, 11 | }, 12 | ] 13 | } 14 | 15 | 16 | def main(): 17 | result = exec_dict(hello) 18 | print(result) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /examples/sdk/hello_file.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_file 2 | 3 | 4 | def main(): 5 | result = exec_file("./hello.pdl") 6 | print(result) 7 | 8 | 9 | if __name__ == "__main__": 10 | main() 11 | -------------------------------------------------------------------------------- /examples/sdk/hello_prog.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_program 2 | from pdl.pdl_ast import LitellmModelBlock, LitellmParameters, Program, TextBlock 3 | 4 | hello = Program( 5 | TextBlock( 6 | text=[ 7 | "Hello\n", 8 | LitellmModelBlock( 9 | model="ollama_chat/granite3.2:2b", 10 | parameters=LitellmParameters(stop=["!"]), # pyright: ignore 11 | ), 12 | ] 13 | ) 14 | ) 15 | 16 | 17 | def main(): 18 | result = exec_program(hello) 19 | print(result) 20 | 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /examples/sdk/hello_str.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_str 2 | 3 | HELLO = """ 4 | text: 5 | - "Hello\n" 6 | - model: ollama_chat/granite3.2:2b 7 | parameters: 8 | stop: ['!'] 9 | """ 10 | 11 | 12 | def main(): 13 | result = exec_str(HELLO) 14 | print(result) 15 | 16 | 17 | if __name__ == "__main__": 18 | main() 19 | -------------------------------------------------------------------------------- /examples/teacher/qna.yaml: -------------------------------------------------------------------------------- 1 | task_description: to teach a large language model to come up with puns 2 | created_by: mizmo 3 | seed_examples: 4 | - question: Tell me a pun about birds. 5 | answer: |- 6 | Why do birds eat wood? 7 | 8 | Because they're peckish! 9 | - question: Tell me a pun about gas. 10 | answer: |- 11 | Why did the car have a belly ache? 12 | 13 | Because it had too much gas! 14 | - question: Tell me a pun about waves. 15 | answer: |- 16 | What did the ocean say to the ocean? 17 | 18 | Nothing. It just waved! 19 | -------------------------------------------------------------------------------- /examples/tools/calc.pdl: -------------------------------------------------------------------------------- 1 | description: tool use 2 | defs: 3 | tools: 4 | data: 5 | - name: calc 6 | description: Calculator function 7 | arguments: 8 | expr: 9 | type: string 10 | description: Arithmetic expression to calculate 11 | text: 12 | - role: system 13 | text: You are Granite, developed by IBM. You are a helpful AI assistant with access to the following tools. When a tool is required to answer the user's query, respond with <|tool_call|> followed by a JSON list of tools used. If a tool does not exist in the provided list of tools, notify the user that you do not have the ability to fulfill the request. 14 | contribute: [context] 15 | - role: tools 16 | content: 17 | text: ${ tools } 18 | contribute: [context] 19 | - "Out of 1400 participants, 400 passed the test. What percentage is that?\n" 20 | - def: actions 21 | model: ollama_chat/granite3.2:8b 22 | parser: json 23 | spec: [{ name: string, arguments: { expr: string }}] 24 | parameters: 25 | drop_params: true # This is needed because the model does not support structured decoding. It directs LiteLLM to ignore parameters sent for structured decoding. 26 | - "\n" 27 | - if: ${ actions[0].name == "calc" } 28 | then: 29 | text: 30 | - lang: python 31 | code: result = ${ actions[0].arguments.expr } -------------------------------------------------------------------------------- /examples/tools/search.pdl: -------------------------------------------------------------------------------- 1 | description: tool use 2 | defs: 3 | search: 4 | description: Wikipedia search 5 | function: 6 | topic: 7 | type: string 8 | description: Topic to search 9 | return: 10 | lang: python 11 | code: | 12 | import warnings, wikipedia 13 | warnings.simplefilter("ignore") 14 | try: 15 | result = wikipedia.summary("${ topic }") 16 | except wikipedia.WikipediaException as e: 17 | result = str(e) 18 | text: 19 | - role: system 20 | content: | 21 | You are a helpful AI assistant with access to the 22 | following tools. If a tool does not exist in the 23 | provided list of tools, notify the user that you 24 | do not have the ability to fulfill the request. 25 | contribute: [context] 26 | - role: tools 27 | content: 28 | text: ${ [ search.signature ] } 29 | contribute: [context] 30 | - "What is the circumference of planet Earth?\n" 31 | - def: actions 32 | model: ollama_chat/granite3.3:8b 33 | parser: json 34 | spec: [{ name: string, arguments: { topic: string }}] 35 | - "\n" 36 | - if: ${ actions[0].name == "search" } 37 | then: 38 | call: ${ search } 39 | args: 40 | topic: ${ actions[0].arguments.topic } 41 | -------------------------------------------------------------------------------- /examples/tools/wiki.pdl: -------------------------------------------------------------------------------- 1 | description: tool use 2 | defs: 3 | tools: 4 | data: 5 | - name: search 6 | description: Wikipedia search 7 | parameters: 8 | type: object 9 | properties: 10 | topic: 11 | type: string 12 | description: Topic to search 13 | text: 14 | - role: system 15 | content: | 16 | You are a helpful AI assistant with access to the following tools. 17 | If a tool does not exist in the provided list of tools, notify the user 18 | that you do not have the ability to fulfill the request. 19 | contribute: [context] 20 | - role: tools 21 | content: 22 | text: ${ tools } 23 | contribute: [context] 24 | - "What is the circumference of planet Earth?\n" 25 | - def: actions 26 | model: ollama_chat/granite3.3:8b 27 | parser: json 28 | spec: [{ name: string, arguments: { topic: string }}] 29 | - "\n" 30 | - if: ${ actions[0].name == "search" } 31 | then: 32 | lang: python 33 | code: | 34 | import warnings, wikipedia 35 | warnings.simplefilter("ignore") 36 | try: 37 | result = wikipedia.summary("${ actions[0].arguments.topic }") 38 | except wikipedia.WikipediaException as e: 39 | result = str(e) -------------------------------------------------------------------------------- /examples/tutorial/calling_llm.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world calling a model 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | parameters: 6 | stop: ['!'] -------------------------------------------------------------------------------- /examples/tutorial/calling_llm_chaining.pdl: -------------------------------------------------------------------------------- 1 | description: Model chaining 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.3:8b 5 | parameters: 6 | stop: ["!"] 7 | - "\nTranslate the above to French\n" 8 | - model: ollama_chat/granite3.3:8b 9 | parameters: 10 | stop: ["!"] 11 | -------------------------------------------------------------------------------- /examples/tutorial/calling_llm_with_input.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world calling a model 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | input: 6 | Translate the word 'Hello' to French 7 | -------------------------------------------------------------------------------- /examples/tutorial/calling_llm_with_input_messages.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world calling a model 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | input: 6 | array: 7 | - role: system 8 | content: You are a helpful assistant that is fluent in French. 9 | - role: user 10 | content: Translate the word 'Hello' to French 11 | -------------------------------------------------------------------------------- /examples/tutorial/calling_llm_with_input_messages_var.pdl: -------------------------------------------------------------------------------- 1 | description: Model call with explicit messages input 2 | text: 3 | - def: prompt 4 | array: 5 | - role: system 6 | content: You are a helpful software engineer. You write clear, concise, well-commented code. 7 | - role: user 8 | content: Write a Python function that implement merge sort. 9 | contribute: [] 10 | - model: ollama_chat/granite3.2:2b 11 | input: ${ prompt } 12 | 13 | -------------------------------------------------------------------------------- /examples/tutorial/code_command.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to shell command 2 | lang: command 3 | code: | 4 | echo "Hello World!" 5 | -------------------------------------------------------------------------------- /examples/tutorial/code_jinja.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to Jinja 2 | defs: 3 | world: "World" 4 | lang: jinja 5 | code: | 6 | Hello {{ world }}! 7 | -------------------------------------------------------------------------------- /examples/tutorial/code_pdl.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to PDL 2 | lang: pdl 3 | code: | 4 | description: Hello world 5 | text: 6 | - "Hello\n" 7 | - model: ollama_chat/granite3.2:2b 8 | parameters: 9 | temperature: 0 10 | -------------------------------------------------------------------------------- /examples/tutorial/code_python.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call to Python code 2 | text: 3 | - "Hello, " 4 | - lang: python 5 | code: 6 | | 7 | import random 8 | import string 9 | result = random.choice(string.ascii_lowercase) -------------------------------------------------------------------------------- /examples/tutorial/data.txt: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /examples/tutorial/data.yaml: -------------------------------------------------------------------------------- 1 | source_code: 2 | | 3 | @SuppressWarnings("unchecked") 4 | public static Map deserializeOffsetMap(String lastSourceOffset) throws IOException { 5 | Map offsetMap; 6 | if (lastSourceOffset == null || lastSourceOffset.isEmpty()) { 7 | offsetMap = new HashMap<>(); 8 | } else { 9 | offsetMap = JSON_MAPPER.readValue(lastSourceOffset, Map.class); 10 | } 11 | return offsetMap; 12 | } 13 | repo_info: 14 | repo: streamsets/datacollector 15 | path: stagesupport/src/main/java/com/.../OffsetUtil.java 16 | function_name: OffsetUtil.deserializeOffsetMap 17 | -------------------------------------------------------------------------------- /examples/tutorial/data_block_raw.pdl: -------------------------------------------------------------------------------- 1 | description: Raw data block 2 | data: 3 | name: ${ name } 4 | phone: ${ phone } 5 | raw: True -------------------------------------------------------------------------------- /examples/tutorial/defs-hello.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with defs 2 | defs: 3 | hello: 4 | function: 5 | name: string 6 | return: Hello ${ name }! 7 | bye: 8 | "Good bye" 9 | text: 10 | - call: ${ hello } 11 | args: 12 | name: World 13 | - "\n" 14 | - ${ bye } 15 | -------------------------------------------------------------------------------- /examples/tutorial/defs.pdl: -------------------------------------------------------------------------------- 1 | description: Function def and call 2 | defs: 3 | translate: 4 | function: 5 | sentence: string 6 | language: string 7 | return: 8 | lastOf: 9 | - "\nTranslate the sentence '${ sentence }' to ${ language }.\n" 10 | - model: ollama_chat/granite3.2:2b 11 | parameters: 12 | stop: ["\n"] 13 | text: 14 | - call: ${ translate } 15 | args: 16 | sentence: I love Paris! 17 | language: French 18 | - "\n" 19 | - call: ${ translate } 20 | args: 21 | sentence: I love Madrid! 22 | language: Spanish -------------------------------------------------------------------------------- /examples/tutorial/for.pdl: -------------------------------------------------------------------------------- 1 | description: for loop creating a string 2 | for: 3 | i: [1, 2, 3, 4] 4 | repeat: 5 | ${ i } 6 | -------------------------------------------------------------------------------- /examples/tutorial/for_array.pdl: -------------------------------------------------------------------------------- 1 | description: Array comprehension 2 | for: 3 | i: [1, 2, 3, 4] 4 | repeat: 5 | ${ i } 6 | join: 7 | as: array 8 | -------------------------------------------------------------------------------- /examples/tutorial/for_lastOf.pdl: -------------------------------------------------------------------------------- 1 | description: Loop where the result is the result of the last iteration 2 | for: 3 | i: [1, 2, 3, 4] 4 | repeat: 5 | ${ i } 6 | join: 7 | as: lastOf 8 | -------------------------------------------------------------------------------- /examples/tutorial/for_multiple_lists.pdl: -------------------------------------------------------------------------------- 1 | description: for loop over multiple lists 2 | defs: 3 | numbers: 4 | data: [1, 2, 3, 4] 5 | names: 6 | data: ["Bob", "Carol", "David", "Ernest"] 7 | for: 8 | number: ${ numbers } 9 | name: ${ names } 10 | repeat: 11 | "${ name }'s number is ${ number }\n" 12 | -------------------------------------------------------------------------------- /examples/tutorial/for_object.pdl: -------------------------------------------------------------------------------- 1 | description: for loop creating an object 2 | defs: 3 | numbers: 4 | data: [1, 2, 3, 4] 5 | names: 6 | data: ["Bob", "Carol", "David", "Ernest"] 7 | for: 8 | number: ${ numbers } 9 | name: ${ names } 10 | repeat: 11 | data: 12 | ${ name }: ${ number } 13 | join: 14 | as: object -------------------------------------------------------------------------------- /examples/tutorial/for_with.pdl: -------------------------------------------------------------------------------- 1 | description: for loop with new lines between iterations 2 | for: 3 | i: [1, 2, 3, 4] 4 | repeat: 5 | ${ i } 6 | join: 7 | with: "\n" 8 | -------------------------------------------------------------------------------- /examples/tutorial/free_variables.pdl: -------------------------------------------------------------------------------- 1 | # Call with pdl --data '"something": "ABC"' free_variables.pdl 2 | description: Hello world with data 3 | text: 4 | - def: stutter 5 | function: 6 | return: 7 | ${ something } 8 | - "Hello World!\n" 9 | - call: ${ stutter } 10 | - "\n" 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/tutorial/function_alias.pdl: -------------------------------------------------------------------------------- 1 | description: Hello function 2 | defs: 3 | hello: 4 | function: 5 | name: string 6 | return: Hello ${ name }! 7 | alias: ${ hello } 8 | text: 9 | - call: ${ alias } 10 | args: 11 | name: World -------------------------------------------------------------------------------- /examples/tutorial/function_definition.pdl: -------------------------------------------------------------------------------- 1 | description: Function def and call 2 | text: 3 | - def: translate 4 | function: 5 | sentence: string 6 | language: string 7 | return: 8 | lastOf: 9 | - "\nTranslate the sentence '${ sentence }' to ${ language }.\n" 10 | - model: ollama_chat/granite3.2:2b 11 | parameters: 12 | stop: ["\n"] 13 | temperature: 0 14 | - call: ${ translate } 15 | args: 16 | sentence: I love Paris! 17 | language: French 18 | - "\n" 19 | - call: ${ translate } 20 | args: 21 | sentence: I love Madrid! 22 | language: Spanish 23 | -------------------------------------------------------------------------------- /examples/tutorial/function_empty_context.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with function definition and call 2 | text: 3 | - def: hello 4 | function: 5 | name: string 6 | return: 7 | text: 8 | - Hello ${ name }! 9 | - model: ollama_chat/granite3.2:8b 10 | - call: ${ hello } 11 | args: 12 | name: World 13 | pdl_context: [] 14 | -------------------------------------------------------------------------------- /examples/tutorial/function_optional_params.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with function definition and call 2 | text: 3 | - def: hello 4 | function: 5 | name: string 6 | lastName: {optional: string} # optional parameter 7 | return: 8 | if: ${ lastName is defined } 9 | then: Hello ${ name } ${ lastName }! 10 | else: Hello ${ name }! 11 | - call: ${ hello } 12 | args: 13 | name: World 14 | lastName: Universe 15 | -------------------------------------------------------------------------------- /examples/tutorial/if.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with condition 2 | text: 3 | - 'Hello! ' 4 | - lang: python 5 | code: | 6 | import random 7 | result = random.choice([False, True]) 8 | def: QUESTION 9 | contribute: [] 10 | - if: ${ QUESTION } 11 | then: How are you? -------------------------------------------------------------------------------- /examples/tutorial/import.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | lib: 3 | import: import_lib 4 | text: 5 | - call: ${ lib.a } 6 | args: 7 | arg: Bye! 8 | -------------------------------------------------------------------------------- /examples/tutorial/import_lib.pdl: -------------------------------------------------------------------------------- 1 | 2 | defs: 3 | b: 4 | function: 5 | arg: string 6 | return: 7 | ${ arg } 8 | 9 | a: 10 | function: 11 | arg: string 12 | return: 13 | call: ${ b } 14 | args: 15 | pdl_context: [] 16 | arg: ${ arg } -------------------------------------------------------------------------------- /examples/tutorial/independent.pdl: -------------------------------------------------------------------------------- 1 | description: Independent example --- hello * ( (' in French'*g) + (' en Espanol'*g)) * Goodbye! * g 2 | text: 3 | - hello 4 | - context: independent 5 | text: 6 | - text: 7 | - " in French!" 8 | - model: ollama_chat/granite3.2:2b 9 | - text: 10 | - " en Espanol!" 11 | - model: ollama_chat/granite3.2:2b 12 | - "Which language did I use last?" 13 | - model: ollama_chat/granite3.2:2b 14 | -------------------------------------------------------------------------------- /examples/tutorial/independent_docs.pdl: -------------------------------------------------------------------------------- 1 | description: Independent documents 2 | defs: 3 | doc1: "Hello world!" 4 | doc2: "Goodbye world!" 5 | text: 6 | - context: independent 7 | text: 8 | - ${ doc1 } 9 | - ${ doc2 } 10 | - Compare and contrast the above documents. 11 | - model: ollama_chat/granite3.2:2b -------------------------------------------------------------------------------- /examples/tutorial/independent_for.pdl: -------------------------------------------------------------------------------- 1 | description: Independent For loop example 2 | defs: 3 | list: 4 | data: ["in French", "en Espanol"] 5 | text: 6 | - "Hello " 7 | - for: 8 | elem: ${list} 9 | repeat: 10 | text: 11 | - ${ elem } 12 | - model: ollama_chat/granite3.2:2b 13 | context: independent 14 | - "Goodbye!" 15 | - model: ollama_chat/granite3.2:2b 16 | 17 | -------------------------------------------------------------------------------- /examples/tutorial/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bob", 3 | "address": { 4 | "number": 87, 5 | "street": "Smith Road", 6 | "town": "Armonk", 7 | "state": "NY", 8 | "zip": 10504 9 | } 10 | } -------------------------------------------------------------------------------- /examples/tutorial/input_file.pdl: -------------------------------------------------------------------------------- 1 | description: PDL code with input block 2 | text: 3 | - read: ./data.txt 4 | def: HELLO -------------------------------------------------------------------------------- /examples/tutorial/input_file_json.pdl: -------------------------------------------------------------------------------- 1 | description: Input block example with json input 2 | defs: 3 | PERSON: 4 | read: ./input.json 5 | parser: json 6 | text: 7 | - "${ PERSON.name } lives at the following address:\n" 8 | - "${ PERSON.address.number } ${ PERSON.address.street } in the town of ${ PERSON.address.town }, ${ PERSON.address.state }" 9 | -------------------------------------------------------------------------------- /examples/tutorial/input_stdin.pdl: -------------------------------------------------------------------------------- 1 | description: PDL code with input block 2 | text: 3 | - "The following will prompt the user on stdin.\n" 4 | - read: 5 | message: "Please provide an input: " 6 | def: STDIN -------------------------------------------------------------------------------- /examples/tutorial/input_stdin_multiline.pdl: -------------------------------------------------------------------------------- 1 | description: PDL code with input block 2 | text: 3 | - "A multiline stdin input.\n" 4 | - read: 5 | multiline: true -------------------------------------------------------------------------------- /examples/tutorial/loop_index.pdl: -------------------------------------------------------------------------------- 1 | index: i 2 | repeat: 3 | text: ${i + 1} 4 | maxIterations: 3 -------------------------------------------------------------------------------- /examples/tutorial/muting_block_output.pdl: -------------------------------------------------------------------------------- 1 | description: Function def and call 2 | defs: 3 | translate: 4 | function: 5 | sentence: string 6 | language: string 7 | return: 8 | text: 9 | - text: "\nTranslate the sentence '${ sentence }' to ${ language }.\n" 10 | contribute: [context] 11 | - model: ollama_chat/granite3.2:2b 12 | parameters: 13 | stop: ["\n"] 14 | text: 15 | - call: ${ translate } 16 | contribute: [] 17 | def: FRENCH 18 | args: 19 | sentence: I love Paris! 20 | language: French 21 | - "The french sentence was: ${ FRENCH }" -------------------------------------------------------------------------------- /examples/tutorial/parser-regex.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with parser using regex 2 | text: 3 | - model: ollama_chat/granite3.2:2b 4 | input: "Hello," 5 | parameters: 6 | # Tell the LLM to stop after generating an exclamation point. 7 | stop: ['!'] 8 | spec: {"name": string} 9 | parser: 10 | spec: 11 | name: string 12 | regex: '\s*(?P.*)\s*' 13 | -------------------------------------------------------------------------------- /examples/tutorial/parser_findall.pdl: -------------------------------------------------------------------------------- 1 | data: "1 -- 2 -- 3 -- 4" 2 | parser: 3 | regex: '[0-9]+' 4 | mode: findall -------------------------------------------------------------------------------- /examples/tutorial/parser_regex_code.pdl: -------------------------------------------------------------------------------- 1 | description: Parse a block output using a regex 2 | defs: 3 | output: 4 | model: ollama_chat/granite3.2:2b 5 | parameters: 6 | temperature: 0 7 | input: Write a Python function that perform the addition of two numbers. 8 | parser: 9 | spec: 10 | code: string 11 | regex: (.|\n)*```python\n(?P(.|\n)*)```(.|\n)* 12 | text: ${ output.code } -------------------------------------------------------------------------------- /examples/tutorial/programs/chatbot.pdl: -------------------------------------------------------------------------------- 1 | description: Chatbot 2 | text: 3 | # Allow the user to type any question, implicitly adding the question to the context. 4 | - read: 5 | message: "What is your query?\n" 6 | - repeat: 7 | text: 8 | # Send context to Granite model hosted at ollama 9 | - model: ollama_chat/granite3.2:2b 10 | # Allow the user to type 'yes', 'no', or anything else, storing 11 | # the input into a variable named `eval`. The input is also implicitly 12 | # added to the context. 13 | - read: 14 | def: eval 15 | message: "\nIs this a good answer[yes/no]?\n" 16 | - "\n" 17 | # If the user only typed "no", prompt the user for input to add to the context. 18 | - if: ${ eval == 'no' } 19 | then: 20 | text: 21 | - read: 22 | message: "Why not?\n" 23 | # If the user typed only "yes", finish the `repeat` and end the program 24 | until: ${ eval == 'yes'} 25 | -------------------------------------------------------------------------------- /examples/tutorial/programs/code-json.pdl: -------------------------------------------------------------------------------- 1 | description: Code explanation example 2 | defs: 3 | CODE: 4 | read: ../../code/data.yaml 5 | parser: yaml 6 | TRUTH: 7 | read: ../../code/ground_truth.txt 8 | lastOf: 9 | - model: ollama_chat/granite3.2:2b 10 | def: EXPLANATION 11 | input: 12 | | 13 | Here is some info about the location of the function in the repo. 14 | repo: 15 | ${ CODE.repo_info.repo } 16 | path: ${ CODE.repo_info.path } 17 | Function_name: ${ CODE.repo_info.function_name } 18 | 19 | 20 | Explain the following code: 21 | ``` 22 | ${ CODE.source_code }``` 23 | - def: EVAL 24 | lang: python 25 | code: 26 | | 27 | import textdistance 28 | expl = """ 29 | ${ EXPLANATION } 30 | """ 31 | truth = """ 32 | ${ TRUTH } 33 | """ 34 | result = textdistance.levenshtein.normalized_similarity(expl, truth) 35 | - data: 36 | input: ${ CODE } 37 | output: ${ EXPLANATION } 38 | metric: ${ EVAL } 39 | 40 | -------------------------------------------------------------------------------- /examples/tutorial/repeat.pdl: -------------------------------------------------------------------------------- 1 | description: repeat loop with multiple conditions 2 | defs: 3 | numbers: 4 | data: [42, 2, 4012, 27] 5 | names: 6 | data: ["Bob", "Carol", "David", "Ernest"] 7 | for: 8 | number: ${ numbers } 9 | name: ${ names } 10 | index: i 11 | repeat: 12 | "${i}: ${ name }'s number is ${ number }\n" 13 | until: ${ name == "Carol"} 14 | maxIterations: 3 -------------------------------------------------------------------------------- /examples/tutorial/simple_program.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | text: 3 | Hello, world! -------------------------------------------------------------------------------- /examples/tutorial/structured_decoding.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - role: system 3 | text: You are an AI language model developed by IBM Research. You are a cautious assistant. You carefully follow instructions. You are helpful and harmless and you follow ethical guidelines and promote positive behavior. 4 | contribute: [context] 5 | - "\nWhat is the color of the sky? Write it as JSON\n" 6 | - model: watsonx/ibm/granite-34b-code-instruct 7 | parser: json 8 | spec: { color: string } -------------------------------------------------------------------------------- /examples/tutorial/test.pdl: -------------------------------------------------------------------------------- 1 | description: test 2 | defs: 3 | m1: 4 | content: doc1 5 | m2: 6 | content: doc2 7 | m3: 8 | content: Compare the docs 9 | 10 | mycontext: ${ (m1 + m2) * m3 } 11 | 12 | text: 13 | - model: ollama_chat/granite3.2:2b 14 | input: ${ mycontext } 15 | - ${ mycontext } -------------------------------------------------------------------------------- /examples/tutorial/type_checking.pdl: -------------------------------------------------------------------------------- 1 | # Expected not to type check 2 | description: Creating JSON Data 3 | defs: 4 | data: 5 | read: type_checking_data.yaml 6 | parser: yaml 7 | spec: { questions: [string], answers: [object] } 8 | text: 9 | - model: ollama_chat/granite3.2:2b 10 | def: model_output 11 | spec: {name: string, age: integer} 12 | input: 13 | array: 14 | - role: user 15 | content: 16 | text: 17 | - for: 18 | question: ${ data.questions } 19 | answer: ${ data.answers } 20 | repeat: | 21 | ${ question } 22 | ${ answer } 23 | - > 24 | Question: Generate only a JSON object with fields 'name' and 'age' and set them appropriately. Write the age all in letters. Only generate a single JSON object and nothing else. 25 | parser: yaml 26 | parameters: 27 | stop: ["Question"] 28 | temperature: 0 29 | 30 | -------------------------------------------------------------------------------- /examples/tutorial/type_checking_data.yaml: -------------------------------------------------------------------------------- 1 | questions: 2 | - > 3 | Question: Write a YAML object with 2 fields 'a' and 'b' of type int and set to 0. 4 | - > 5 | Question: Write a YAML object with 3 fields 'number' and 'street' and 'town' set to '10', 'Miller Road', 'Armonk' respectively. 6 | 7 | answers: 8 | - { "a": 0, "b": 0 } 9 | 10 | - { "number": 10, "street": "miller Road", "town": "armonk" } -------------------------------------------------------------------------------- /examples/tutorial/type_list.pdl: -------------------------------------------------------------------------------- 1 | # Expected not to type check 2 | description: test 3 | spec: {type: array, minItems: 0, maxItems: 0, items: { type: string }} 4 | data: ["hello", "world"] 5 | -------------------------------------------------------------------------------- /examples/tutorial/variable_def_use.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with variable def and use 2 | text: 3 | - "Hello\n" 4 | - model: ollama_chat/granite3.2:2b 5 | def: GEN 6 | parameters: 7 | stop: ['!'] 8 | - "\nGEN is equal to: ${ GEN }" -------------------------------------------------------------------------------- /examples/tutorial/while.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | i: 0 3 | while: ${ i < 3 } 4 | repeat: 5 | defs: 6 | i: ${i + 1} 7 | text: ${i} -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | python_version = 3.12 3 | ignore_missing_imports = True 4 | 5 | [mypy-requests] 6 | ignore_missing_imports = True 7 | -------------------------------------------------------------------------------- /pdl-live-react/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /pdl-live-react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # Playwright 27 | /test-results/ 28 | /playwright-report/ 29 | /blob-report/ 30 | /playwright/.cache/ 31 | -------------------------------------------------------------------------------- /pdl-live-react/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] 3 | } 4 | -------------------------------------------------------------------------------- /pdl-live-react/demos/demo1.pdl: -------------------------------------------------------------------------------- 1 | description: Simple LLM interaction 2 | text: 3 | - "write a hello world example, and explain to me how to run it" 4 | - model: ollama_chat/granite3.2:2b 5 | # - model: openai/ibm-granite_granite-3.2-2b-instruct 6 | -------------------------------------------------------------------------------- /pdl-live-react/demos/demo2.pdl: -------------------------------------------------------------------------------- 1 | description: Model chaining 2 | text: 3 | - "write a hello world example, and explain to me how to run it" 4 | - model: ollama_chat/granite3.2:2b 5 | parameters: 6 | temperature: 0 7 | - "how about in Rust?" 8 | - model: ollama_chat/granite3.2:2b 9 | parameters: 10 | temperature: 0 11 | -------------------------------------------------------------------------------- /pdl-live-react/demos/error.pdl: -------------------------------------------------------------------------------- 1 | description: Creating JSON Data 2 | defs: 3 | data: 4 | read: ./gen-data.yaml 5 | parser: yaml 6 | spec: { questions: [string], answers: [object] } 7 | text: 8 | - model: ollama_chat/granite3.2:2b 9 | def: model_output 10 | spec: {name: string, age: integer} 11 | input: 12 | text: 13 | - for: 14 | question: ${ data.questions } 15 | answer: ${ data.answers } 16 | repeat: | 17 | ${ question } 18 | ${ answer } 19 | - > 20 | Question: Create a JSON object with fields 'name' and 'age' 21 | and set them appropriately. Write the age in letters. 22 | parser: yaml 23 | parameters: 24 | stop_sequences: "\n" 25 | temperature: 0 -------------------------------------------------------------------------------- /pdl-live-react/demos/gen-data.yaml: -------------------------------------------------------------------------------- 1 | source_code: 2 | | 3 | @SuppressWarnings("unchecked") 4 | public static Map deserializeOffsetMap(String lastSourceOffset) throws IOException { 5 | Map offsetMap; 6 | if (lastSourceOffset == null || lastSourceOffset.isEmpty()) { 7 | offsetMap = new HashMap<>(); 8 | } else { 9 | offsetMap = JSON_MAPPER.readValue(lastSourceOffset, Map.class); 10 | } 11 | return offsetMap; 12 | } 13 | repo_info: 14 | repo: streamsets/datacollector 15 | path: stagesupport/src/main/java/com/.../OffsetUtil.java 16 | function_name: OffsetUtil.deserializeOffsetMap 17 | -------------------------------------------------------------------------------- /pdl-live-react/demos/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPTDIR=$(cd $(dirname "$0") && pwd) 4 | UI="$SCRIPTDIR"/.. # top of react UI 5 | TOP="$UI"/.. # top of repo 6 | T="$UI"/src/demos # place to store traces 7 | 8 | pdl --trace "$T"/demo1.json "$UI"/demos/demo1.pdl 9 | pdl --trace "$T"/demo2.json "$UI"/demos/demo2.pdl 10 | pdl --trace "$T"/demo3.json "$TOP"/examples/fibonacci/fib.pdl 11 | pdl --trace "$T"/demo4.json "$TOP"/examples/chatbot/chatbot.pdl < Result { 5 | let (_, messages, _) = run_string(&program, Default::default(), Default::default()) 6 | .await 7 | .map_err(|err| err.to_string())?; 8 | 9 | Ok(pretty_print(&messages)) 10 | } 11 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod interpreter; 2 | pub mod read_trace; 3 | pub mod replay_prep; 4 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/commands/read_trace.rs: -------------------------------------------------------------------------------- 1 | use std::fs::read; 2 | 3 | // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ 4 | #[tauri::command] 5 | pub fn read_trace(trace_file: &str) -> Result, String> { 6 | let data = read(trace_file).map_err(|e| e.to_string())?; 7 | Ok(data) 8 | } 9 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/compile/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod beeai; 2 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/gui.rs: -------------------------------------------------------------------------------- 1 | use ::std::path::PathBuf; 2 | use tauri::WebviewWindowBuilder; 3 | 4 | pub fn new_window( 5 | app: tauri::AppHandle, 6 | path: Option, 7 | ) -> Result<(), Box> { 8 | WebviewWindowBuilder::new( 9 | &app, 10 | "main", 11 | tauri::WebviewUrl::App(path.unwrap_or("".into())), 12 | ) 13 | .title("Prompt Declaration Language") 14 | .prevent_overflow() 15 | .zoom_hotkeys_enabled(true) 16 | .inner_size(1400.0, 1050.0) 17 | .build()?; 18 | Ok(()) 19 | } 20 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | tauri_app_lib::run() 6 | } 7 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/pdl/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod extract; 3 | pub mod interpreter; 4 | mod interpreter_tests; 5 | pub mod pip; 6 | pub mod pull; 7 | pub mod requirements; 8 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/pdl/pip.rs: -------------------------------------------------------------------------------- 1 | use ::std::fs::{create_dir_all, write}; 2 | use ::std::path::PathBuf; 3 | 4 | use dirs::cache_dir; 5 | use duct::cmd; 6 | 7 | use crate::util::shasum; 8 | 9 | #[cfg(desktop)] 10 | pub async fn pip_install_if_needed( 11 | requirements: &str, 12 | ) -> Result> { 13 | let Some(cache_path) = cache_dir() else { 14 | return Err(Box::from("Could not find user cache directory")); 15 | }; 16 | create_dir_all(&cache_path)?; 17 | 18 | let hash = shasum::sha256sum_str(requirements); 19 | let venv_path = cache_path.join("venvs").join(hash); 20 | let bin_path = venv_path.join(if cfg!(windows) { "Scripts" } else { "bin" }); 21 | 22 | if !venv_path.exists() { 23 | println!("Creating virtual environment..."); 24 | let python = if cfg!(target_os = "macos") { 25 | "python3.12" 26 | } else { 27 | "python3" 28 | }; 29 | cmd!(python, "-mvenv", &venv_path) 30 | .stdout_to_stderr() 31 | .run()?; 32 | 33 | cmd!(bin_path.join("pip"), "install", &requirements) 34 | .stdout_to_stderr() 35 | .run()?; 36 | 37 | let cached_requirements_path = venv_path.join("requirements.txt"); 38 | write(&cached_requirements_path, requirements)?; 39 | } 40 | 41 | Ok(bin_path.to_path_buf()) 42 | } 43 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/pdl/requirements.rs: -------------------------------------------------------------------------------- 1 | pub const BEEAI_FRAMEWORK: &str = "-e git+https://github.com/starpit/bee-agent-framework.git@nick-meta-combo#egg=beeai_framework&subdirectory=python"; 2 | //pub const BEEAI_FRAMEWORK: &str = "beeai_framework==0.1"; 3 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/util.rs: -------------------------------------------------------------------------------- 1 | pub mod shasum; 2 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/src/util/shasum.rs: -------------------------------------------------------------------------------- 1 | use base64ct::{Base64Url, Encoding}; 2 | use sha2::{Digest, Sha256}; 3 | 4 | /* pub fn sha256sum(path: &Path) -> Result { 5 | let mut hasher = Sha256::new(); 6 | let mut file = File::open(path)?; 7 | 8 | copy(&mut file, &mut hasher)?; 9 | let hash_bytes = hasher.finalize(); 10 | 11 | Ok(Base64Url::encode_string(&hash_bytes)) 12 | } */ 13 | 14 | pub fn sha256sum_str(s: &str) -> String { 15 | let mut hasher = Sha256::new(); 16 | hasher.update(s); 17 | let hash_bytes = hasher.finalize(); 18 | 19 | Base64Url::encode_string(&hash_bytes) 20 | } 21 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/call-no-args.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | foo: 3 | function: {} 4 | return: 5 | description: nullary function 6 | text: 7 | - hello world 8 | text: 9 | - call: ${ foo} 10 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/call-with-args.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | foo: 3 | function: 4 | x: integer 5 | return: 6 | description: nullary function 7 | text: 8 | - hello world ${x+1} bye 9 | text: 10 | - call: ${ foo } 11 | args: 12 | x: 3 13 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/code-python.pdl: -------------------------------------------------------------------------------- 1 | lang: python 2 | code: | 3 | import sys # test import stdlib 4 | import os # test import stdlib 5 | print(f"!!! {sys.path}") 6 | #import textdistance # test import from venv 7 | from nested_diff import diff # test import from venv 8 | #from typing import Self 9 | from pydantic import BaseModel, Field, ValidationError 10 | from pydantic_settings import BaseSettings, SettingsConfigDict 11 | # import beeai_framework 12 | # from beeai_framework.tools.search.wikipedia import WikipediaTool # type: ignore 13 | a = {'one': 1, 'two': 2, 'three': 3} 14 | b = {'one': 1, 'two': 3, 'three': 3} 15 | result = {"foo": os.getenv("FOO999999999999999999999999"), "diff": diff(a, b, O=False, U=False)} 16 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/data1.pdl: -------------------------------------------------------------------------------- 1 | lastOf: 2 | - def: x 3 | text: 4 | - xxxx 5 | - def: y 6 | data: 7 | n: 3 8 | x: ${x} 9 | b: true 10 | - ${y.x~y.n~y.b} 11 | 12 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/data2.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | x: 3 | text: 4 | - xxxx 5 | y: 6 | data: 7 | n: 3 8 | x: ${x} 9 | b: true 10 | lastOf: 11 | - ${y.x~y.n~y.b} 12 | 13 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/data3.pdl: -------------------------------------------------------------------------------- 1 | lastOf: 2 | - def: x 3 | text: 4 | - xxxx 5 | - def: y 6 | raw: true 7 | data: 8 | n: 3 9 | x: ${x} 10 | b: true 11 | - ${y.x~y.n~y.b} 12 | 13 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/data4.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | x: 3 | description: Outer x 4 | text: 5 | - xxxx 6 | y: 7 | data: 8 | n: 3 9 | x: ${x} 10 | b: true 11 | lastOf: 12 | - defs: 13 | x: yyyy 14 | description: Inner x 15 | text: 16 | - ${x~y.x~y.n~y.b} 17 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/if1.pdl: -------------------------------------------------------------------------------- 1 | if: true 2 | then: hi 3 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/if2.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | x: 5 3 | if: ${x!=5} 4 | then: bug 5 | else: good 6 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/include1.pdl: -------------------------------------------------------------------------------- 1 | include: ./call-with-args.pdl -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/json-parser-lastOf.pdl: -------------------------------------------------------------------------------- 1 | lastOf: 2 | - text: 3 | - '{"key": "value"}' 4 | parser: json 5 | def: foo 6 | - ${ foo.key } 7 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/json-parser.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - text: 3 | - '{"key": "value"}' 4 | parser: json 5 | def: foo 6 | - ${ foo.key } 7 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/jsonl-parser.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - text: 3 | - | 4 | {"key": "value"} 5 | {"key2": "value2"} 6 | parser: jsonl 7 | def: foo 8 | - ${ foo[0].key } 9 | - ${ foo[1].key2 } 10 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/model-input-array.pdl: -------------------------------------------------------------------------------- 1 | model: ollama/granite3.2:2b 2 | input: 3 | array: 4 | - role: user 5 | content: answer as if you live in europe 6 | - role: user 7 | content: what is the fastest animal where i live? 8 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/model-input-nested.pdl: -------------------------------------------------------------------------------- 1 | description: Nesting inputs to model calls 2 | text: 3 | - role: user 4 | content: answer as if you live in europe 5 | - text: 6 | - role: user 7 | content: what is the fastest animal where i live? 8 | - model: ollama/granite3.2:2b 9 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/model-input-string.pdl: -------------------------------------------------------------------------------- 1 | model: ollama/granite3.2:2b 2 | input: what is the fastest animal? -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/object1.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | obj: 3 | object: 4 | a: 5 | text: 6 | - foo 7 | text: 8 | - ${ obj.a } 9 | 10 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/object2.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | obj: 3 | object: 4 | a: 5 | object: 6 | b: 7 | text: 8 | - foo2 9 | text: 10 | - ${ obj.a.b } 11 | 12 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/read-file.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - read: ../data/struct.yaml 3 | def: struct 4 | parser: yaml 5 | - ${ struct.a.b } 6 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/read-stdin.pdl: -------------------------------------------------------------------------------- 1 | message: How are you? 2 | read: null 3 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/regex-findall.pdl: -------------------------------------------------------------------------------- 1 | data: aaa999bbb888 2 | parser: 3 | regex: '[^0-9]*(?P[0-9]+)[^0-9]*(?P[0-9]+)$' 4 | mode: findall 5 | spec: 6 | answer1: string 7 | answer2: string 8 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/repeat1.pdl: -------------------------------------------------------------------------------- 1 | for: 2 | x: [1,2,3] 3 | repeat: 4 | text: 5 | - "${ x + 1 }" 6 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/repeat2.pdl: -------------------------------------------------------------------------------- 1 | for: 2 | x: [1,2,3] 3 | y: ["a","b","c"] 4 | repeat: 5 | text: 6 | - "${ x ~ y }" 7 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/repeat3.pdl: -------------------------------------------------------------------------------- 1 | for: 2 | x: 3 | - z: 4 4 | - z: 5 5 | - z: 6 6 | y: ["a","b","c"] 7 | repeat: 8 | text: 9 | - "${ x.z ~ y }" 10 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/scoping_1.pdl: -------------------------------------------------------------------------------- 1 | text: 2 | - defs: 3 | x: 3 4 | text: 5 | - ${x~"yo"} 6 | - ${x~"mo"} 7 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/cli/scoping_1_wrapper.pdl: -------------------------------------------------------------------------------- 1 | include: ./scoping_1.pdl 2 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/data/foo.txt: -------------------------------------------------------------------------------- 1 | this should be foo 2 | -------------------------------------------------------------------------------- /pdl-live-react/src-tauri/tests/data/struct.yaml: -------------------------------------------------------------------------------- 1 | a: 2 | b: 3 3 | -------------------------------------------------------------------------------- /pdl-live-react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import useDynamicTitle from "./title" 2 | import PdlRoutes from "./routes/PdlRoutes" 3 | 4 | import "@patternfly/react-core/dist/styles/base.css" 5 | 6 | export default function App() { 7 | useDynamicTitle() 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /pdl-live-react/src/assets/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/pdl-live-react/src/assets/404.png -------------------------------------------------------------------------------- /pdl-live-react/src/demos/README.md: -------------------------------------------------------------------------------- 1 | # Demo Traces 2 | 3 | These demo traces were sourced as follows: 4 | 5 | - demo1: From the top-level README 6 | - demo2: [model_chaining.pdl](../../../examples/tutorial/model_chaining.pdl) 7 | - demo3: [fib.pdl](../../../examples/fibonacci/fib.pdl) 8 | - demo4: [chatbot.pdl](../../../examples/chatbot/chatbot.pdl) 9 | - demo5: [6-code-json.pdl](../../../examples/talk/6-code-json.pdl) 10 | - demo6: [error.pdl](../../demos/error.pdl) 11 | - demo7: [4-talk.pdl](../../../examples/talk/4-function.pdl) 12 | - demo8: [demo-hallucination](../../../examples/intrinsics/demo-hallucination.pdl). To run this currently requires... work. https://github.com/ibm-granite-community/granite-snack-cookbook/blob/main/recipes/Intrinsics/Granite_RAG_LoRA.ipynb 13 | - demo9: [gsm8.pdl](../../../examples/gsm8k/gsm8.pdl) 14 | -------------------------------------------------------------------------------- /pdl-live-react/src/demos/demos.ts: -------------------------------------------------------------------------------- 1 | import demo1 from "./demo1.json" 2 | import demo2 from "./demo2.json" 3 | import demo3 from "./demo3.json" 4 | import demo4 from "./demo4.json" 5 | import demo5 from "./demo5.json" 6 | import demo6 from "./demo6.json" 7 | import demo7 from "./demo7.json" 8 | import demo8 from "./demo8.json" 9 | import demo9 from "./demo9.json" 10 | 11 | export type Demo = { 12 | name: string 13 | trace: string 14 | } 15 | 16 | const demos: Demo[] = [ 17 | demo1, 18 | demo2, 19 | demo3, 20 | demo4, 21 | demo5, 22 | demo6, 23 | demo7, 24 | demo8, 25 | demo9, 26 | ].map((demo) => ({ 27 | name: demo.description, 28 | trace: JSON.stringify(demo), 29 | })) 30 | 31 | export default demos 32 | -------------------------------------------------------------------------------- /pdl-live-react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react" 2 | import { createRoot } from "react-dom/client" 3 | import { HashRouter as Router } from "react-router" 4 | import App from "./App.tsx" 5 | 6 | createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | 11 | , 12 | ) 13 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/DarkModeContext.ts: -------------------------------------------------------------------------------- 1 | const darkModeLocalStorageKey = "pdl-viewer.dark-mode" 2 | 3 | export function getDarkModeUserSetting(): boolean { 4 | return (localStorage.getItem(darkModeLocalStorageKey) || "false") == "true" 5 | } 6 | 7 | export function setDarkModeUserSetting(darkMode: boolean) { 8 | localStorage.setItem(darkModeLocalStorageKey, darkMode ? "true" : "false") 9 | } 10 | 11 | export function setDarkModeForSession(darkMode: boolean) { 12 | if (darkMode) { 13 | document.querySelector("html")?.classList.add("pf-v6-theme-dark") 14 | } else { 15 | document.querySelector("html")?.classList.remove("pf-v6-theme-dark") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/Demo.tsx: -------------------------------------------------------------------------------- 1 | import Page from "./Page" 2 | import PageBreadcrumbDropdown from "./PageBreadcrumbDropdown" 3 | import PageBreadcrumbDropdownItem from "./PageBreadcrumbDropdownItem" 4 | 5 | import demos, { type Demo } from "../demos/demos" 6 | 7 | type Props = { 8 | name: string 9 | value: string 10 | } 11 | 12 | /** current is demo curently being shown */ 13 | function DemosDropdown({ current }: { current: string }) { 14 | return ( 15 | 16 | {demos.map((demo) => ( 17 | 23 | ))} 24 | 25 | ) 26 | } 27 | 28 | export default function Demo({ name, value }: Props) { 29 | return ( 30 | } 32 | breadcrumb2={name} 33 | initialValue={value} 34 | /> 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/DemoNavItems.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router" 2 | import { useCallback, useState, type MouseEvent } from "react" 3 | import { NavExpandable, NavItem } from "@patternfly/react-core" 4 | 5 | import demos from "../demos/demos" 6 | 7 | export default function DemoNavItems({ 8 | hash, 9 | activeItem, 10 | }: { 11 | hash: string 12 | activeItem: string 13 | }) { 14 | const demosExpandedLocalStorageKey = "pdl.sidebar-nav-demos.expanded" 15 | const [isDemosExpanded, setIsDemosExpanded] = useState( 16 | !localStorage.getItem(demosExpandedLocalStorageKey) || 17 | localStorage.getItem(demosExpandedLocalStorageKey) === "true", 18 | ) 19 | const onDemosExpand = useCallback( 20 | (_evt: MouseEvent, val: boolean) => { 21 | setIsDemosExpanded(val) 22 | localStorage.setItem(demosExpandedLocalStorageKey, String(val)) 23 | }, 24 | [setIsDemosExpanded], 25 | ) 26 | 27 | return ( 28 | 34 | {demos.map((demo) => { 35 | const id = "/demos/" + encodeURIComponent(demo.name) 36 | return ( 37 | 38 | {demo.name} 39 | 40 | ) 41 | })} 42 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/Local.tsx: -------------------------------------------------------------------------------- 1 | import { invoke } from "@tauri-apps/api/core" 2 | import { useParams } from "react-router" 3 | import { useEffect, useState } from "react" 4 | 5 | import Page from "./Page" 6 | 7 | type Props = { 8 | traceFile: string 9 | } 10 | 11 | export default function Local() { 12 | const { traceFile } = useParams() 13 | const [value, setValue] = useState("") 14 | 15 | useEffect(() => { 16 | let active = true 17 | load() 18 | return () => { 19 | active = false 20 | } 21 | 22 | async function load() { 23 | if (traceFile) { 24 | const buf = (await invoke("read_trace", { traceFile })) as number[] 25 | let value = "" 26 | for (let i = 0; i < buf.length; i++) { 27 | value += String.fromCharCode(buf[i]) 28 | } 29 | if (!active) { 30 | return 31 | } 32 | setValue(value) 33 | } 34 | } 35 | }, [traceFile, setValue]) 36 | 37 | return ( 38 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/Masthead.css: -------------------------------------------------------------------------------- 1 | .pf-v6-theme-dark .pdl-logo path { 2 | fill: white; 3 | } 4 | .pdl-logo { 5 | height: 2.25em; 6 | } 7 | .pdl-logo path { 8 | fill: black; 9 | } 10 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/MyTrace.tsx: -------------------------------------------------------------------------------- 1 | import Page from "./Page" 2 | import PageBreadcrumbDropdown from "./PageBreadcrumbDropdown" 3 | import PageBreadcrumbDropdownItem from "./PageBreadcrumbDropdownItem" 4 | 5 | import { getMyTraces } from "./MyTraces" 6 | 7 | type Props = { 8 | name: string 9 | value: string 10 | } 11 | 12 | /** current is demo curently being shown */ 13 | function MyTracesDropdown({ current }: { current: string }) { 14 | return ( 15 | 16 | {getMyTraces().map(({ title, filename }) => ( 17 | 23 | ))} 24 | 25 | ) 26 | } 27 | 28 | export default function MyTrace({ name, value }: Props) { 29 | return ( 30 | } 32 | breadcrumb2={name} 33 | initialValue={value} 34 | /> 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/Page.css: -------------------------------------------------------------------------------- 1 | html.web { 2 | font-size: 20px; 3 | } 4 | 5 | .pdl-wrap { 6 | &, 7 | & p { 8 | white-space: pre-wrap; 9 | } 10 | } 11 | 12 | .pdl-mono { 13 | font-family: var(--pf-t--global--font--family--mono); 14 | } 15 | 16 | .pf-v6-c-page__main-container { 17 | margin: 0; 18 | border-radius: 0; 19 | border-radius: none; 20 | max-height: revert; 21 | } 22 | 23 | .pf-v6-c-page__main-body { 24 | flex: 1; 25 | 26 | & > section[data-fill-height] { 27 | height: 100%; 28 | } 29 | } 30 | .pdl-viewer-tab:not([hidden]) { 31 | height: 100%; 32 | overflow: auto; 33 | } 34 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/PageBreadcrumbDropdown.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from "react" 2 | import { 3 | Dropdown, 4 | DropdownList, 5 | MenuToggle, 6 | MenuToggleElement, 7 | } from "@patternfly/react-core" 8 | 9 | export default function PageBreadcrumbDropdown({ 10 | label, 11 | children, 12 | }: { 13 | label: string 14 | children: import("react").ReactNode[] 15 | }) { 16 | const [isOpen, setIsOpen] = useState(false) 17 | const onToggle = () => setIsOpen(!isOpen) 18 | const onSelect = useCallback(() => { 19 | setIsOpen((prevIsOpen: boolean) => !prevIsOpen) 20 | }, [setIsOpen]) 21 | 22 | return ( 23 | setIsOpen(isOpen)} 27 | shouldFocusToggleOnSelect 28 | toggle={(toggleRef: React.Ref) => ( 29 | 37 | {label} 38 | 39 | )} 40 | > 41 | {children} 42 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/PageBreadcrumbDropdownItem.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react" 2 | import { useNavigate, useSearchParams, useLocation } from "react-router" 3 | import { DropdownItem } from "@patternfly/react-core" 4 | 5 | export default function PageBreadcrumbDropdownItem({ 6 | url, 7 | name, 8 | current, 9 | }: { 10 | url: string 11 | name: string 12 | current: string 13 | }) { 14 | const navigate = useNavigate() 15 | const { hash } = useLocation() 16 | const [searchParams] = useSearchParams() 17 | searchParams.delete("id") 18 | searchParams.delete("def") 19 | searchParams.delete("get") 20 | searchParams.delete("type") 21 | searchParams.delete("detail") 22 | const s = searchParams.toString() 23 | const search = s.length > 0 ? "?" + s : "" 24 | 25 | const onClick = useCallback( 26 | () => navigate("/" + url + "/" + name + search + hash), 27 | [name, url, hash, search, navigate], 28 | ) 29 | return ( 30 | 31 | {name} 32 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/PageBreadcrumbs.css: -------------------------------------------------------------------------------- 1 | .pf-v6-c-breadcrumb__dropdown { 2 | margin: 0; 3 | } 4 | .pdl-breadcrumb-menu-toggle { 5 | font-size: var(--pf-v6-c-breadcrumb__item--FontSize); 6 | } 7 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/Run.css: -------------------------------------------------------------------------------- 1 | @import "../view/term/RunTerminal.css"; 2 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/Uploader.css: -------------------------------------------------------------------------------- 1 | .pdl-upload-form { 2 | max-width: 800px; 3 | } 4 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Intro.tsx: -------------------------------------------------------------------------------- 1 | import { Content } from "@patternfly/react-core" 2 | 3 | export default function Intro() { 4 | return ( 5 | 6 | PDL is a declarative language designed for developers to create reliable, 7 | composable LLM prompts and integrate them into software systems. It 8 | provides a structured way to specify prompt templates, enforce validation, 9 | and compose LLM calls with traditional rule-based systems. 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Links.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router" 2 | import { Button, Flex } from "@patternfly/react-core" 3 | 4 | import ExternalLinkSquareAltIcon from "@patternfly/react-icons/dist/esm/icons/external-link-square-alt-icon" 5 | 6 | export default function Links() { 7 | return ( 8 | 9 | 21 | 33 | 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Tile.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren, ReactNode } from "react" 2 | 3 | import { 4 | Card, 5 | CardBody, 6 | CardFooter, 7 | CardHeader, 8 | CardTitle, 9 | Flex, 10 | } from "@patternfly/react-core" 11 | 12 | type Props = PropsWithChildren<{ 13 | className?: string 14 | title: ReactNode 15 | body: ReactNode 16 | icon?: ReactNode 17 | }> 18 | 19 | const gapSm = { default: "gapSm" as const } 20 | const center = { default: "alignItemsCenter" as const } 21 | 22 | export default function Tile({ 23 | className, 24 | title, 25 | body, 26 | children, 27 | icon, 28 | }: Props) { 29 | return ( 30 | 31 | 32 | 33 | 34 | {icon} 35 | {title} 36 | 37 | 38 | 39 | {body} 40 | 41 | {children} 42 | 43 | 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Tiles.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactNode } from "react" 2 | import { Gallery } from "@patternfly/react-core" 3 | 4 | import Demos from "./tiles/Demos" 5 | import MyTraces from "./tiles/MyTraces" 6 | 7 | type Props = { 8 | tiles?: ReactNode | ReactNode[] 9 | } 10 | 11 | const minWidths = { default: "400px" } 12 | 13 | export default function Tiles(props: Props) { 14 | return ( 15 | 16 | {props.tiles ?? ( 17 | <> 18 | 19 | 20 | 21 | )} 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | import { Toolbar, ToolbarGroup, ToolbarContent } from "@patternfly/react-core" 2 | 3 | import DarkModeToggle from "../DarkModeToggle" 4 | 5 | const alignEnd = { default: "alignEnd" as const } 6 | 7 | export default function WelcomeToolbar() { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Welcome.css: -------------------------------------------------------------------------------- 1 | .pdl-welcome-intro { 2 | max-width: 1200px; 3 | } 4 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/Welcome.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactNode } from "react" 2 | import { Flex, FlexItem, PageSection, Title } from "@patternfly/react-core" 3 | 4 | import Page from "../Page" 5 | import Intro from "./Intro" 6 | import Links from "./Links" 7 | import Tiles from "./Tiles" 8 | import Toolbar from "./Toolbar" 9 | 10 | import "./Welcome.css" 11 | 12 | const flex1 = { default: "flex_1" as const } 13 | 14 | type Props = { 15 | breadcrumb1?: string 16 | intro?: ReactNode 17 | tiles?: ReactNode | ReactNode[] 18 | } 19 | 20 | export default function Welcome(props: Props) { 21 | return ( 22 | 23 | 24 | 25 | Prompt Declaration Language (PDL){" "} 26 | 27 | 28 | 29 | 30 | {props.intro ?? } 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /pdl-live-react/src/page/welcome/tiles/Demos.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Flex, Stack, StackItem } from "@patternfly/react-core" 2 | import { Link, useLocation, useSearchParams } from "react-router" 3 | 4 | import Tile from "../Tile" 5 | import demos from "../../../demos/demos" 6 | 7 | import DemoIcon from "@patternfly/react-icons/dist/esm/icons/file-code-icon" 8 | 9 | export default function Demos() { 10 | const { hash } = useLocation() 11 | const [searchParams] = useSearchParams() 12 | const s = searchParams.toString() 13 | 14 | const body = ( 15 | 16 | You may view one of the built-in PDL demos. 17 | 18 | 19 | {demos.map((demo) => ( 20 | 32 | ))} 33 | 34 | 35 | 36 | ) 37 | 38 | return } body={body} /> 39 | } 40 | -------------------------------------------------------------------------------- /pdl-live-react/src/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg?react" { 2 | import React from "react" 3 | const SVG: React.VFC> 4 | export default SVG 5 | } 6 | -------------------------------------------------------------------------------- /pdl-live-react/src/title.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react" 2 | import { useLocation } from "react-router" 3 | 4 | function capitalize(s: string) { 5 | return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1) 6 | } 7 | 8 | export default function useDynamicTitle() { 9 | const { pathname } = useLocation() 10 | 11 | useEffect(() => { 12 | const rest = capitalize( 13 | decodeURIComponent(pathname.replace(/^\/(demos\/)?/, "")), 14 | ) 15 | 16 | document.title = "PDL Viewer" + (rest ? ` - ${rest}` : "") 17 | }, [pathname]) 18 | } 19 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/CopyToClipboard.css: -------------------------------------------------------------------------------- 1 | .pf-v6-c-clipboard-copy .pf-v6-c-form-control { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/CopyToClipboard.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react" 2 | import { ClipboardCopy } from "@patternfly/react-core" 3 | 4 | import "./CopyToClipboard.css" 5 | 6 | export default function CopyToClipboard(props: { children: string }) { 7 | const copy = useCallback( 8 | () => navigator.clipboard.writeText(props.children), 9 | [props.children], 10 | ) 11 | return ( 12 | 13 | Copy 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/Markdown.tsx: -------------------------------------------------------------------------------- 1 | import { Content } from "@patternfly/react-core" 2 | import rehypeStarryNight from "rehype-starry-night" 3 | import { 4 | MarkdownHooks as RMD, 5 | type Options as MarkdownProps, 6 | } from "react-markdown" 7 | 8 | import "./Markdown.css" 9 | 10 | /** Simple wrapper over */ 11 | export default function Markdown(props: MarkdownProps) { 12 | return ( 13 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/Result.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | DescriptionListTerm, 3 | DescriptionListGroup, 4 | DescriptionListDescription, 5 | Panel, 6 | PanelMain, 7 | } from "@patternfly/react-core" 8 | 9 | import Code from "./code/Code" 10 | import Value from "./Value" 11 | 12 | import { type SupportedLanguage } from "./code/Code" 13 | 14 | type Props = { 15 | result: number | string | unknown 16 | lang?: SupportedLanguage 17 | term?: string 18 | limitHeight?: boolean 19 | } 20 | 21 | export default function Result({ 22 | result, 23 | lang, 24 | term = "Result", 25 | limitHeight = false, 26 | }: Props) { 27 | const isCode = 28 | !!lang && 29 | lang !== "plaintext" && 30 | !!result && 31 | typeof result !== "number" && 32 | typeof result !== "boolean" 33 | 34 | const innerContent = isCode ? ( 35 | 36 | ) : ( 37 | {result} 38 | ) 39 | 40 | const content = !limitHeight ? ( 41 | innerContent 42 | ) : ( 43 | 44 | {innerContent} 45 | 46 | ) 47 | 48 | return !term ? ( 49 | content 50 | ) : ( 51 | <> 52 | 53 | {term} 54 | {content} 55 | 56 | 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/Value.tsx: -------------------------------------------------------------------------------- 1 | import Code from "./code/Code" 2 | import Markdown from "./Markdown" 3 | 4 | type Props = { children: boolean | number | string | unknown } 5 | 6 | function isJson(s: string) { 7 | try { 8 | JSON.parse(s) 9 | return true 10 | } catch (_err) { 11 | return false 12 | } 13 | } 14 | 15 | export default function Value({ children: s }: Props) { 16 | return typeof s === "number" ? ( 17 |
{s}
18 | ) : typeof s === "string" ? ( 19 | isJson(s) ? ( 20 | 21 | ) : ( 22 | {s === "\n" ? "**" : s.trim()} 23 | ) 24 | ) : ( 25 | JSON.stringify(s, undefined, 2) 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/breadcrumbs/BreadcrumbBar.tsx: -------------------------------------------------------------------------------- 1 | import "./BreadcrumbBar.css" 2 | 3 | import { type BreadcrumbBarItemComponent } from "./BreadcrumbBarItem" 4 | 5 | type Props = { 6 | children: BreadcrumbBarItemComponent | BreadcrumbBarItemComponent[] 7 | } 8 | 9 | /** Inspiration: https://codepen.io/renaudtertrais/pen/nMGWqm */ 10 | export default function BreadcrumbBar(props: Props) { 11 | return
    {props.children}
12 | } 13 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/breadcrumbs/BreadcrumbBarForBlock.tsx: -------------------------------------------------------------------------------- 1 | import { hasResult, type NonScalarPdlBlock as Block } from "../../helpers" 2 | 3 | import BreadcrumbBarForBlockId from "./BreadcrumbBarForBlockId" 4 | 5 | type Props = { 6 | block: Pick 7 | } 8 | 9 | export default function BreadcrumbBarForBlock({ block }: Props) { 10 | return ( 11 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/breadcrumbs/BreadcrumbBarItem.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | JSXElementConstructor, 3 | PropsWithChildren, 4 | MouseEvent, 5 | ReactElement, 6 | ReactNode, 7 | } from "react" 8 | import { Tooltip } from "@patternfly/react-core" 9 | 10 | type Props = PropsWithChildren<{ 11 | detail?: string 12 | className?: string 13 | onClick?: (evt: MouseEvent) => void 14 | tooltip?: ReactNode 15 | }> 16 | 17 | export type BreadcrumbBarItemComponent = ReactElement< 18 | Props, 19 | JSXElementConstructor 20 | > 21 | 22 | export default function BreadcrumbBarItem({ 23 | className, 24 | children, 25 | detail, 26 | onClick, 27 | tooltip, 28 | }: Props) { 29 | const c = {children} 30 | return ( 31 |
  • 32 | 33 | {!tooltip ? c : {c}} 34 | 35 |
  • 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/breadcrumbs/Def.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react" 2 | import { useLocation, useNavigate } from "react-router" 3 | 4 | import BreadcrumbBarItem from "../breadcrumbs/BreadcrumbBarItem" 5 | 6 | type Props = { 7 | /** Block id */ 8 | id: string 9 | 10 | def: string 11 | value?: import("../../pdl_ast").PdlBlock 12 | supportsDrilldown?: boolean 13 | } 14 | 15 | /** One variable definition */ 16 | export default function Def(props: Props) { 17 | const { id, def, value, supportsDrilldown = true } = props 18 | 19 | const navigate = useNavigate() 20 | const { hash } = useLocation() 21 | const drilldown = useCallback( 22 | (evt: import("react").MouseEvent) => { 23 | evt.stopPropagation() 24 | navigate(`?detail&type=def&id=${id}&def=${def}${hash}`) 25 | }, 26 | [def, id, hash, navigate], 27 | ) 28 | 29 | return ( 30 | 34 |
    This block defines the variable "{def}".
    35 | {value && <>Click to see details.} 36 | 37 | } 38 | onClick={!value || !supportsDrilldown ? undefined : drilldown} 39 | > 40 | ${def} 41 |
    42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/code/Code.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense } from "react" 2 | import { stringify } from "yaml" 3 | 4 | import { tryJsonPrettyPrint } from "../../helpers" 5 | import { type PdlBlock } from "../../pdl_ast" 6 | import { block_code_cleanup } from "../../pdl_code_cleanup" 7 | const PreviewLight = lazy(() => import("./PreviewLight")) 8 | 9 | export type SupportedLanguage = 10 | | "yaml" 11 | | "json" 12 | | "javascript" 13 | | "python" 14 | | "plaintext" 15 | | "ipython" 16 | 17 | type Props = { 18 | block: PdlBlock 19 | language?: SupportedLanguage 20 | showLineNumbers?: boolean 21 | wrap?: boolean 22 | limitHeight?: boolean 23 | raw?: boolean 24 | } 25 | 26 | export default function Code({ 27 | block, 28 | language = "yaml", 29 | showLineNumbers, 30 | wrap, 31 | raw = false, 32 | }: Props) { 33 | const value = 34 | typeof block === "string" 35 | ? language === "json" 36 | ? tryJsonPrettyPrint(block) 37 | : block 38 | : stringify(raw ? block : block_code_cleanup(block)) 39 | 40 | return ( 41 | }> 42 | 48 | 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/code/CodeGroup.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | DescriptionListTerm, 3 | DescriptionListGroup, 4 | DescriptionListDescription, 5 | } from "@patternfly/react-core" 6 | 7 | import Code, { type SupportedLanguage } from "./Code" 8 | 9 | type Props = { 10 | code: string 11 | lang?: SupportedLanguage 12 | term?: string 13 | } 14 | 15 | export default function CodeGroup({ code, lang, term = "Code" }: Props) { 16 | return ( 17 | 18 | {term} 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/code/PreviewLight.css: -------------------------------------------------------------------------------- 1 | .pdl-preview-light { 2 | padding: 1em !important; 3 | font-size: 0.875em; 4 | } 5 | .pf-v6-theme-dark .pdl-preview-light { 6 | background-color: #01172799 !important; 7 | border: 1px solid #29292980; 8 | } 9 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/BlockNotFound.tsx: -------------------------------------------------------------------------------- 1 | export default function BlockNotFound(props: { 2 | pdl__id: string | null 3 | value: string 4 | }) { 5 | console.error("Block not found", props.pdl__id, props.value) 6 | return
    Block not found
    7 | } 8 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/DefContent.css: -------------------------------------------------------------------------------- 1 | .pdl-variable-definition-content { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/DrawerContent.css: -------------------------------------------------------------------------------- 1 | .pf-v6-c-drawer__panel { 2 | padding: 0; 3 | } 4 | 5 | .pdl-drawer-content { 6 | border-radius: 0; 7 | .pdl-breadcrumb-bar { 8 | margin-top: 0.375em; 9 | 10 | .pdl-breadcrumb-bar-item--def:first-child { 11 | margin-left: 1em; 12 | } 13 | } 14 | 15 | .pf-v6-c-card__body { 16 | display: flex; 17 | flex-direction: column; 18 | overflow: hidden; 19 | padding: 0; 20 | } 21 | 22 | .pf-v6-c-tab-content { 23 | flex: 1; 24 | overflow: auto; 25 | 26 | & > .pdl-markdown, 27 | & > .pf-v6-c-description-list { 28 | padding: 1em 2em 0 2em; 29 | } 30 | 31 | & > pre { 32 | overflow-x: unset !important; 33 | 34 | & > code { 35 | white-space: pre-wrap !important; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/Group.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | DescriptionListGroup, 3 | DescriptionListTerm, 4 | DescriptionListDescription, 5 | } from "@patternfly/react-core" 6 | 7 | import Value from "../Value" 8 | 9 | export default function Group({ 10 | term, 11 | description, 12 | }: { 13 | term: string 14 | description: import("react").ReactNode 15 | }) { 16 | return ( 17 | 18 | {term} 19 | 20 | {typeof description !== "object" ? ( 21 | {description} 22 | ) : ( 23 | description 24 | )} 25 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/RawTraceTabContent.tsx: -------------------------------------------------------------------------------- 1 | import Code from "../code/Code" 2 | import { type NonScalarPdlBlock as Model } from "../../helpers" 3 | 4 | export default function RawTraceTabContent({ block }: { block: Model }) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/ResultTabContent.tsx: -------------------------------------------------------------------------------- 1 | import Result from "../Result" 2 | 3 | import { hasParser, type PdlBlockWithResult } from "../../helpers" 4 | 5 | export default function UsageTabContent({ 6 | block, 7 | }: { 8 | block: PdlBlockWithResult 9 | }) { 10 | return ( 11 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/SourceTabContent.tsx: -------------------------------------------------------------------------------- 1 | import Code from "../code/Code" 2 | import { type NonScalarPdlBlock as Model } from "../../helpers" 3 | 4 | export default function SourceTabContent({ block }: { block: Model }) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/find.ts: -------------------------------------------------------------------------------- 1 | import { childrenOf } from "../timeline/model" 2 | 3 | import { 4 | isNonScalarPdlBlock, 5 | nonNullable, 6 | type NonScalarPdlBlock as Block, 7 | } from "../../helpers" 8 | 9 | /** 10 | * Traverse the tree under `block` looking for a sub-block with then 11 | * given `id`. 12 | */ 13 | export default function find( 14 | block: import("../../pdl_ast").PdlBlock, 15 | id: string, 16 | ): null | Block { 17 | if (!isNonScalarPdlBlock(block)) { 18 | return null 19 | } else if (block.pdl__id === id) { 20 | return block 21 | } else { 22 | return ( 23 | childrenOf(block) 24 | .map((child) => find(child, id)) 25 | .filter(nonNullable)[0] || null 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Call.tsx: -------------------------------------------------------------------------------- 1 | import Result from "../../Result" 2 | 3 | export default function ModelItems({ 4 | block: { pdl__result }, 5 | }: { 6 | block: import("../../../pdl_ast").CallBlock 7 | }) { 8 | return ( 9 | <> 10 | 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Code.tsx: -------------------------------------------------------------------------------- 1 | import Group from "../Group" 2 | 3 | import Code from "../../code/Code" 4 | import { isArgs, extractCode } from "../../../helpers" 5 | 6 | export default function CodeItems({ 7 | block, 8 | }: { 9 | block: 10 | | import("../../../pdl_ast").ArgsBlock 11 | | import("../../../pdl_ast").CodeBlock 12 | }) { 13 | const { lang } = block 14 | const code = isArgs(block) ? block.args.join(" ") : extractCode(block) 15 | 16 | return ( 17 | <> 18 | 30 | } 31 | /> 32 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Data.tsx: -------------------------------------------------------------------------------- 1 | import { stringify } from "yaml" 2 | import Result from "../../Result" 3 | 4 | export default function ModelItems({ 5 | block: { def, pdl__result }, 6 | }: { 7 | block: import("../../../pdl_ast").DataBlock 8 | }) { 9 | return ( 10 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Error.tsx: -------------------------------------------------------------------------------- 1 | import Group from "../Group" 2 | 3 | export default function ErrorItems({ 4 | block: { msg }, 5 | }: { 6 | block: import("../../../pdl_ast").ErrorBlock 7 | }) { 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Function.tsx: -------------------------------------------------------------------------------- 1 | import { stringify } from "yaml" 2 | 3 | import Group from "../Group" 4 | import CodeGroup from "../../code/CodeGroup" 5 | import { block_code_cleanup } from "../../../pdl_code_cleanup" 6 | 7 | export default function FunctionItems({ 8 | block: { def, function: func, return: retrn }, 9 | }: { 10 | block: import("../../../pdl_ast").FunctionBlock 11 | }) { 12 | return ( 13 | <> 14 | {def && } 15 | 16 | 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/If.tsx: -------------------------------------------------------------------------------- 1 | import Group from "../Group" 2 | 3 | export default function ModelItems({ 4 | block: { if: condition, if_result }, 5 | }: { 6 | block: import("../../../pdl_ast").IfBlock 7 | }) { 8 | return ( 9 | <> 10 | {typeof condition === "string" && ( 11 | 15 | )} 16 | {if_result !== undefined && ( 17 | 25 | )} 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Model.tsx: -------------------------------------------------------------------------------- 1 | import { stringify } from "yaml" 2 | 3 | import Group from "../Group" 4 | import Result from "../../Result" 5 | import { 6 | capitalizeAndUnSnakeCase, 7 | extractModel, 8 | extractStructuredModelResponse, 9 | hasInput, 10 | ModelBlock, 11 | } from "../../../helpers" 12 | 13 | export default function ModelItems({ block }: { block: ModelBlock }) { 14 | const { platform } = block 15 | const model = extractModel(block) 16 | const input = !hasInput(block) 17 | ? undefined 18 | : String(block.pdl__model_input[block.pdl__model_input.length - 1].content) 19 | const { meta } = extractStructuredModelResponse(block) 20 | 21 | const metaForDisplay = meta?.map(([k, v], idx) => ( 22 | 28 | )) 29 | 30 | return ( 31 | <> 32 | {typeof platform === "string" && ( 33 | 34 | )} 35 | {typeof model === "string" && } 36 | {typeof input === "string" && } 37 | {metaForDisplay} 38 | 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Read.tsx: -------------------------------------------------------------------------------- 1 | import Group from "../Group" 2 | import Result from "../../Result" 3 | 4 | export default function ModelItems({ 5 | block: { message, pdl__result }, 6 | }: { 7 | block: import("../../../pdl_ast").ReadBlock 8 | }) { 9 | return ( 10 | <> 11 | {message && } 12 | 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/detail/kind/Text.tsx: -------------------------------------------------------------------------------- 1 | import Result from "../../Result" 2 | 3 | export default function TextItems({ 4 | block: { pdl__result }, 5 | }: { 6 | block: import("../../../pdl_ast").TextBlock 7 | }) { 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/Duration.css: -------------------------------------------------------------------------------- 1 | .pdl-duration { 2 | font-size: 0.875em; 3 | cursor: default; 4 | } 5 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/Masonry.tsx: -------------------------------------------------------------------------------- 1 | import MasonryTile from "./MasonryTile" 2 | 3 | import "./Masonry.css" 4 | 5 | type Props = import("react").PropsWithChildren<{ 6 | page: number 7 | perPage: number 8 | run: import("./MasonryCombo").Runner 9 | sml: import("./Toolbar").SML 10 | model: import("./Tile").default[] 11 | }> 12 | 13 | export default function Masonry({ 14 | run, 15 | sml, 16 | model, 17 | children, 18 | page, 19 | perPage, 20 | }: Props) { 21 | return ( 22 |
    23 | {(!children ? [] : Array.isArray(children) ? children : [children]) 24 | .filter(Boolean) 25 | .map((child, idx) => ( 26 |
    32 | {child} 33 |
    34 | ))} 35 | {model.slice((page - 1) * perPage, page * perPage).map((props, idx) => ( 36 | 43 | ))} 44 |
    45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/MasonryTileWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardBody, CardFooter, Divider } from "@patternfly/react-core" 2 | 3 | type Props = import("react").PropsWithChildren<{ 4 | kind?: string 5 | variant?: "plain" | "default" 6 | sml: import("./Toolbar").SML 7 | header?: import("react").ReactNode 8 | footer?: import("react").ReactNode 9 | }> 10 | 11 | export default function MasonryTileWrapper({ 12 | sml, 13 | header, 14 | footer, 15 | kind, 16 | variant = "default", 17 | children, 18 | }: Props) { 19 | return ( 20 | 28 | {header} 29 | {children} 30 | {footer && ( 31 | <> 32 | 33 | {footer} 34 | 35 | )} 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/Tile.ts: -------------------------------------------------------------------------------- 1 | type Tile = { 2 | id: string 3 | def?: string | null 4 | kind?: string 5 | message?: string 6 | 7 | start_nanos?: number 8 | end_nanos?: number 9 | timezone?: string 10 | 11 | lang?: import("../code/Code").SupportedLanguage 12 | content: string | number | boolean 13 | 14 | footer1Key?: string 15 | footer1Value?: string | number | boolean 16 | footer2Key?: string 17 | footer2Value?: string | number | boolean 18 | footer3Key?: string 19 | footer3Value?: string | number | boolean 20 | stability?: import("./stability").StabilityMetric[] 21 | 22 | block?: import("../../helpers").NonScalarPdlBlock 23 | actions?: "run"[] 24 | } 25 | 26 | export default Tile 27 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/ToolbarPaginator.tsx: -------------------------------------------------------------------------------- 1 | import { Pagination, type PaginationProps } from "@patternfly/react-core" 2 | 3 | export type Props = Pick< 4 | Required, 5 | "itemCount" | "perPage" | "page" 6 | > & { 7 | setPage(n: number): void 8 | setPerPage(n: number): void 9 | } 10 | 11 | export default function ToolbarPaginator({ 12 | itemCount, 13 | perPage, 14 | page, 15 | setPage, 16 | setPerPage, 17 | }: Props) { 18 | const onPerPageSelect = ( 19 | _event: 20 | | import("react").MouseEvent 21 | | import("react").KeyboardEvent 22 | | MouseEvent, 23 | newPerPage: number, 24 | newPage: number, 25 | ) => { 26 | setPerPage(newPerPage) 27 | setPage(newPage) 28 | } 29 | 30 | const onSetPage = ( 31 | _event: 32 | | import("react").MouseEvent 33 | | import("react").KeyboardEvent 34 | | MouseEvent, 35 | newPage: number, 36 | ) => { 37 | setPage(newPage) 38 | } 39 | 40 | return ( 41 | itemCount > 1 && ( 42 | 51 | ) 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/ToolbarReplayButton.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react" 2 | import { Button, Tooltip } from "@patternfly/react-core" 3 | 4 | type Props = { 5 | run: import("./MasonryCombo").Runner 6 | isRunning: boolean 7 | } 8 | 9 | export default function ToolbarReplayButton({ run, isRunning }: Props) { 10 | const handleClickReplay = useCallback(() => run(), [run]) 11 | 12 | const notLocal = !window.__TAURI_INTERNALS__ 13 | return ( 14 | 15 | 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /pdl-live-react/src/view/masonry/ToolbarShowSourceButton.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react" 2 | import { useLocation, useNavigate, useSearchParams } from "react-router" 3 | 4 | import { Button, Tooltip } from "@patternfly/react-core" 5 | import Icon from "@patternfly/react-icons/dist/esm/icons/code-icon" 6 | 7 | type Props = { 8 | /** Root of the program */ 9 | root: string 10 | } 11 | 12 | export default function ToolbarShowSourceButton({ root }: Props) { 13 | const { hash } = useLocation() 14 | const navigate = useNavigate() 15 | const [searchParams] = useSearchParams() 16 | 17 | const onClick = useCallback(() => { 18 | if (searchParams.has("detail") && searchParams.get("type") === "source") { 19 | // close detail 20 | navigate(hash) 21 | } else { 22 | // open detail 23 | navigate(`?detail&type=block&id=${root}${hash}`) 24 | } 25 | }, [hash, navigate, searchParams, root]) 26 | 27 | return ( 28 | 29 | 32 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /pdl-live-react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /pdl-live-react/src/window.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | __TAURI_INTERNALS__: Record 3 | } 4 | -------------------------------------------------------------------------------- /pdl-live-react/tests/basics.spec.test.ts: -------------------------------------------------------------------------------- 1 | import { join } from "path" 2 | import { test, expect } from "@playwright/test" 3 | ;[ 4 | { path: "#", title: /Viewer/ }, 5 | { path: "#welcome", title: /Welcome/ }, 6 | { path: "#about", title: /About/ }, 7 | { path: "#upload", title: /Upload/ }, 8 | { path: "#demos/Fibonacci", title: /Fibonacci/ }, 9 | ].forEach(({ path, title }) => 10 | test(`${path} has title ${title}`, async ({ page }) => { 11 | await page.goto(join("http://localhost:1420", path)) 12 | 13 | // Expect a title "to contain" a substring. 14 | await expect(page).toHaveTitle(title) 15 | }), 16 | ) 17 | -------------------------------------------------------------------------------- /pdl-live-react/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true 23 | }, 24 | "include": ["src"], 25 | } 26 | -------------------------------------------------------------------------------- /pdl-live-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /pdl-live-react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "composite": true, 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "noEmit": true, 9 | "allowSyntheticDefaultImports": true 10 | }, 11 | "include": ["vite.config.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /pdl-live-react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { createHtmlPlugin } from "vite-plugin-html"; 4 | 5 | const host = process.env.TAURI_DEV_HOST; 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig(async () => ({ 9 | base: "./", 10 | plugins: [ 11 | react(), 12 | createHtmlPlugin({ 13 | inject: { 14 | data: { 15 | htmlClassName: process.env.TAURI_ENV_FAMILY ? "tauri" : "web" 16 | } 17 | } 18 | }), 19 | ], 20 | 21 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 22 | // 23 | // 1. prevent vite from obscuring rust errors 24 | clearScreen: false, 25 | // 2. tauri expects a fixed port, fail if that port is not available 26 | server: { 27 | port: 1420, 28 | strictPort: true, 29 | host: host || false, 30 | hmr: host 31 | ? { 32 | protocol: "ws", 33 | host, 34 | port: 1421, 35 | } 36 | : undefined, 37 | watch: { 38 | // 3. tell vite to ignore watching `src-tauri` 39 | ignored: ["**/src-tauri/**"], 40 | }, 41 | }, 42 | })); 43 | -------------------------------------------------------------------------------- /pylintrc: -------------------------------------------------------------------------------- 1 | [MAIN] 2 | 3 | disable= 4 | # Errors 5 | import-error, 6 | # Warnings 7 | exec-used, 8 | unused-argument, 9 | broad-exception-caught, 10 | fixme, 11 | # Conventions 12 | missing-module-docstring,missing-class-docstring,missing-function-docstring, 13 | use-implicit-booleaness-not-comparison, 14 | too-many-lines, 15 | line-too-long, 16 | # Refactors 17 | too-many-locals, 18 | too-many-branches, 19 | too-many-statements, 20 | too-few-public-methods, 21 | duplicate-code, 22 | wrong-import-position 23 | 24 | load-plugins=pylint.extensions.docparams,pylint.extensions.bad_builtin 25 | -------------------------------------------------------------------------------- /scripts/generate_pdl_examples_runner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script generates another script to run all PDL examples 4 | # Set the name of your pyenv virtualenv for PDL 5 | PDL_VENV=pdl 6 | OUTPUT_FILE=$(pwd)/run_pdl_examples.sh 7 | 8 | # Chdir to parent dir 9 | cd "$(dirname "$0")/.." 10 | 11 | # `set -e` exits the script on first non-zero exit code, 12 | # comment out if behavior is not desired. 13 | set -e 14 | 15 | # PyEnv setup 16 | export PYENV_ROOT="$HOME/.pyenv" 17 | [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" 18 | eval "$(pyenv init -)" 19 | eval "$(pyenv virtualenv-init -)" 20 | pyenv local "$PDL_VENV" 21 | 22 | echo "#!/usr/bin/env bash" > "$OUTPUT_FILE" 23 | echo "cd \"\$(dirname \"\$0\")/..\" || exit" >> "$OUTPUT_FILE" 24 | 25 | for example in examples/**/*.pdl; do 26 | echo "$example" 27 | printf "\necho \"Running %s\"\n" "$example" >> "$OUTPUT_FILE" 28 | printf "python -m pdl.pdl \"%s\"\n" "$example" >> "$OUTPUT_FILE" 29 | done 30 | 31 | echo "echo \"All examples have been run.\"" >> "$OUTPUT_FILE" -------------------------------------------------------------------------------- /src/pdl/__init__.py: -------------------------------------------------------------------------------- 1 | from importlib.metadata import PackageNotFoundError, version 2 | 3 | from ._version import __version__ as hardcoded_version 4 | 5 | 6 | def _get_distribution_version(distribution_name: str) -> str: 7 | """ 8 | This function attempts to retrieve the version of PDL package using 9 | importlib.metadata. 10 | 11 | When the package is not installed, importlib will raise a PackageNotFoundError. 12 | In this case, we fallback to the hardcoded version. 13 | 14 | When the package is installed, but the distribution name does not match, 15 | importlib will return the version of the package that is installed. 16 | """ 17 | try: 18 | return version(distribution_name) 19 | except PackageNotFoundError: 20 | # This is a fallback for when the package is not recognized by importlib.metadata. 21 | # This can happen when the package is not installed. 22 | return ( 23 | hardcoded_version 24 | if distribution_name == "pdl" 25 | else _get_distribution_version( 26 | "pdl" # This is a fallback to maintain the previous behavior. 27 | ) 28 | ) 29 | 30 | 31 | __version__ = _get_distribution_version("prompt-declaration-language") 32 | -------------------------------------------------------------------------------- /src/pdl/optimize/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/src/pdl/optimize/__init__.py -------------------------------------------------------------------------------- /src/pdl/optimize/config_parser.py: -------------------------------------------------------------------------------- 1 | from typing import Literal 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | 6 | class OptimizationConfig(BaseModel): 7 | benchmark: str = Field() 8 | num_candidates: int = Field(default=30) 9 | num_demonstrations: int = Field(default=5) 10 | initial_test_set_size: int = Field(default=10) 11 | max_test_set_size: int = Field(default=1000) 12 | timeout: int = Field(default=120) 13 | budget_growth: Literal["double", "to_max"] = Field(default="double") 14 | shuffle_test: bool = Field(default=False) 15 | budget: str | None = Field(default=None) 16 | parallelism: int = Field(default=4) 17 | train_set_name: str = Field(default="train") 18 | test_set_name: str = Field(default="test") 19 | validation_set_name: str = Field(default="validation") 20 | demonstrations_variable_name: str = Field(default="demonstrations") 21 | variables: dict[str, list] = Field(default={}) 22 | experiment_prefix: str = Field(default="") 23 | 24 | def get_variable_names(self) -> list[str]: 25 | return [self.demonstrations_variable_name, *self.variables.keys()] 26 | -------------------------------------------------------------------------------- /src/pdl/pdl_analysis.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/src/pdl/pdl_analysis.py -------------------------------------------------------------------------------- /src/pdl/pdl_compilers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/src/pdl/pdl_compilers/__init__.py -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/tests/__init__.py -------------------------------------------------------------------------------- /tests/data/call_expression_args.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | get_current_stock: 3 | function: 4 | product_name: string 5 | return: 6 | "FN::get_current_stock:: '${product_name}'\n" 7 | text: 8 | 9 | - def: object_example 10 | text: '{"product_name": "from_object"}' 11 | parser: json 12 | contribute: [] 13 | 14 | - def: simple_call 15 | call: ${ get_current_stock } 16 | args: 17 | product_name: "Simple call!" 18 | 19 | - "${object_example}\n" 20 | 21 | - def: with_object_args 22 | call: ${ get_current_stock } 23 | args: ${object_example} -------------------------------------------------------------------------------- /tests/data/function.pdl: -------------------------------------------------------------------------------- 1 | description: Function definition 2 | defs: 3 | template: 4 | function: 5 | preamble: string 6 | question: string 7 | notes: string 8 | return: | 9 | ${ preamble } 10 | ### Question: ${ question } 11 | 12 | ### Notes: 13 | ${ notes } 14 | 15 | ### Answer: 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/data/hello.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | text: 3 | - Hello, world! 4 | - "\n" 5 | - repeat: 6 | "This is your first PDL program\n" 7 | maxIterations: 2 8 | -------------------------------------------------------------------------------- /tests/data/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bob", 3 | "address": { 4 | "number": 87, 5 | "street": "Smith Road", 6 | "town": "Armonk", 7 | "state": "NY", 8 | "zip": 10504 9 | } 10 | } -------------------------------------------------------------------------------- /tests/data/input1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Carol", 3 | "address": { 4 | "number": 99, 5 | "street": "Miller Road", 6 | "town": "Armonk", 7 | "state": "NY", 8 | "zip": 10504 9 | } 10 | } -------------------------------------------------------------------------------- /tests/data/input_data.txt: -------------------------------------------------------------------------------- 1 | Hello World! 2 | This is a prompt descriptor. 3 | Or is it? 4 | -------------------------------------------------------------------------------- /tests/data/line/hello.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | texts: 3 | Hello, world! -------------------------------------------------------------------------------- /tests/data/line/hello1.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | text: 3 | - Hello, world! 4 | - "\n" 5 | - repeat: 6 | "This is your first PDL program\n" 7 | num_iterations: 3 -------------------------------------------------------------------------------- /tests/data/line/hello10.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - 'Hello! ' 4 | - lang: python 5 | code: | 6 | result = True 7 | defs: QUESTION 8 | contribute: [] 9 | - if: '${ QUESTION }' 10 | then: How are you? 11 | spec: boolean -------------------------------------------------------------------------------- /tests/data/line/hello11.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - 'Hello! ' 4 | - lang: python 5 | code: | 6 | result = True 7 | defss: QUESTION 8 | contribute: [] 9 | - if: '${ QUESTION }' 10 | then: How are you? 11 | spec: boolean -------------------------------------------------------------------------------- /tests/data/line/hello12.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - 'Hello! ' 4 | - lang: python 5 | code: | 6 | result = True 7 | def: QUESTION 8 | contribute: [] 9 | - if: '${ QUESTION }' 10 | then: How are you? 11 | spec: boolean -------------------------------------------------------------------------------- /tests/data/line/hello13.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - def: I 4 | lang: python 5 | code: result = 0 6 | - "\n" 7 | - repeat: 8 | text: 9 | - def: I 10 | lang: python 11 | code: result = ${ I } + 1 12 | spec: string 13 | - "\n" 14 | until: '${ I == 5 }' 15 | -------------------------------------------------------------------------------- /tests/data/line/hello14.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with model chaining 2 | text: 3 | - Hello, 4 | - model: watsonx_text/ibm/granite-34b-code-instruct 5 | def: GEN 6 | parameters: 7 | stop: 8 | - '!' 9 | include_stop_sequence: true 10 | mock_response: " World!" 11 | - def: translate 12 | function: 13 | sentence: string 14 | language: string 15 | spec: integer 16 | return: 17 | lastOf: 18 | - "\nTranslate the sentence '${ sentence }' to ${ language }\n" 19 | - model: watsonx_text/ibm/granite-20b-multilingual 20 | parameters: 21 | stop: 22 | - '!' 23 | include_stop_sequence: true 24 | mock_response: "Bonjour le monde!" 25 | - call: ${ translate } 26 | spec: string 27 | args: 28 | sentence: Hello,${ GEN } 29 | language: French -------------------------------------------------------------------------------- /tests/data/line/hello15.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world 2 | text: 3 | - def: stutter 4 | function: 5 | return: 6 | lastOf: 7 | - get: boolean 8 | - ${ something } 9 | - "Hello World!\n" 10 | - call: ${ stutter } 11 | -------------------------------------------------------------------------------- /tests/data/line/hello16.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world to call into a model 2 | text: 3 | - read: ./hello16_data.json 4 | parser: json 5 | def: data 6 | contribute: [] 7 | spec: { questions: [string], answers: [object] } 8 | - model: watsonx_text/ibm/granite-20b-code-instruct 9 | def: model_output 10 | spec: {bob: integer, "carol": string} 11 | input: 12 | text: 13 | - for: 14 | question: ${ data.questions } 15 | answer: ${ data.answers } 16 | repeat: 17 | | 18 | ${ question } 19 | ${ answer } 20 | - 'Question: Write a JSON object with 2 fields "bob" and "carol" set to "20" and "30" respectively.' 21 | parser: yaml 22 | parameters: 23 | temperature: 0 24 | stop: 25 | - '}' 26 | include_stop_sequence: true 27 | mock_response: '{"bob": 20, "carol": 30}' 28 | -------------------------------------------------------------------------------- /tests/data/line/hello16_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "questions": [ 3 | "Question: Write a JSON object with 2 fields 'a' and 'b' of type int and set to 0.", 4 | "Question: Write a JSON object with 3 fields 'number' and 'street' and 'town' set to '10', 'Miller Road', 'Armonk' respectively." 5 | ], 6 | "answers": [ 7 | {"a": 0, "b": 0}, 8 | {"number": 10, "street": "Miller Road", "town": "Armonk"} 9 | ] 10 | } -------------------------------------------------------------------------------- /tests/data/line/hello17.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code 2 | text: 3 | - lang: python 4 | spec: integer 5 | code: | 6 | import string 7 | result = "hello" 8 | -------------------------------------------------------------------------------- /tests/data/line/hello18.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - def: I 4 | lang: python 5 | code: result = 0 6 | - "\n" 7 | - repeat: 8 | text: 9 | - def: I 10 | lang: python 11 | code: result = ${ I } + 1 12 | - "\n" 13 | until: '${ J == 5 }' 14 | -------------------------------------------------------------------------------- /tests/data/line/hello19.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world to call into a model 2 | defs: 3 | model: watsonx_text/ibm/granite-34b-code-instruct 4 | text: 5 | - Hello, 6 | - model: ${ models } 7 | spec: integer 8 | parameters: 9 | decoding_method: greedy 10 | stop: 11 | - '!' 12 | include_stop_sequence: true 13 | mock_response: " World!" -------------------------------------------------------------------------------- /tests/data/line/hello20.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing model chaining 2 | text: 3 | - Who is${ NAME }? 4 | -------------------------------------------------------------------------------- /tests/data/line/hello21.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - if: '${ QUESTION }' 4 | then: How are you? -------------------------------------------------------------------------------- /tests/data/line/hello22.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - if: ${ true } 4 | then: ${ I } -------------------------------------------------------------------------------- /tests/data/line/hello23.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - if: ${ false } 4 | then: "hello" 5 | else: ${ I } -------------------------------------------------------------------------------- /tests/data/line/hello24.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with model chaining 2 | text: 3 | - Hello, 4 | - model: watsonx_text/ibm/granite-34b-code-instruct 5 | def: GEN 6 | parameters: 7 | stop: 8 | - '!' 9 | include_stop_sequence: true 10 | mock_response: " World!" 11 | - def: translate 12 | function: 13 | sentence: string 14 | language: string 15 | spec: integer 16 | return: 17 | lastOf: 18 | - "\nTranslate the sentence '${ sentence }' to ${ language }\n" 19 | - model: watsonx_text/ibm/granite-34b-code-instruct 20 | parameters: 21 | mock_response: " World!" 22 | - call: ${ translate } 23 | spec: string 24 | args: 25 | sentence: Hello,${ GEN1 } 26 | language: ${ GEN2 } -------------------------------------------------------------------------------- /tests/data/line/hello25.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world with model chaining 2 | text: 3 | - Hello, 4 | - model: watsonx_text/ibm/granite-34b-code-instruct 5 | def: GEN 6 | parameters: 7 | stop: 8 | - '!' 9 | include_stop_sequence: true 10 | - def: translate 11 | function: 12 | sentence: string 13 | language: string 14 | return: 15 | lastOf: 16 | - "\nTranslate the sentence '${ sentence1 }' to ${ language }\n" 17 | - model: watsonx_text/ibm/granite-20b-multilingual 18 | parameters: 19 | stop: 20 | - "!" 21 | - "\n" 22 | include_stop_sequence: true 23 | - call: ${ translate } 24 | spec: string 25 | args: 26 | sentence: Hello,${ GEN } 27 | language: French -------------------------------------------------------------------------------- /tests/data/line/hello26.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world to call into a model 2 | text: 3 | - read: hello16_data.json 4 | parser: json 5 | def: data 6 | contribute: [] 7 | spec: { questions: [string], answers: [object] } 8 | - model: watsonx_text/ibm/granite-34b-code-instruct 9 | def: model_output 10 | input: 11 | text: 12 | - for: 13 | question: "Hello" 14 | answer: ${ data.answers } 15 | repeat: 16 | text: 17 | - ${ question } 18 | - ${ answer } 19 | - 'Question: Write a JSON object with 2 fields "bob" and "carol" set to "20" and "30" respectively.' 20 | parameters: 21 | decoding_method: greedy 22 | stop: 23 | - '}' 24 | include_stop_sequence: true 25 | mock_response: 26 | | 27 | Here is the code: 28 | ```json 29 | { 30 | "bob": "20", 31 | "carol": "30" 32 | } -------------------------------------------------------------------------------- /tests/data/line/hello27.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world to call into a model 2 | text: 3 | - read: hello16_data.json 4 | parser: json 5 | def: data 6 | contribute: [] 7 | spec: { questions: [string], answers: [object] } 8 | - model: watsonx_text/ibm/granite-34b-code-instruct 9 | def: model_output 10 | input: 11 | text: 12 | - for: 13 | question: ${ [ ] } 14 | answer: ${ data.answers } 15 | repeat: 16 | text: 17 | - ${ question } 18 | - ${ answer } 19 | - 'Question: Write a JSON object with 2 fields "bob" and "carol" set to "20" and "30" respectively.' 20 | parameters: 21 | decoding_method: greedy 22 | stop: 23 | - '}' 24 | include_stop_sequence: true 25 | mock_response: 26 | | 27 | Here is the code: 28 | ```json 29 | { 30 | "bob": "20", 31 | "carol": "30" 32 | } -------------------------------------------------------------------------------- /tests/data/line/hello28.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - 'Hello! ' 4 | - lang: python 5 | code: | 6 | result = True 7 | def: QUESTION 8 | contribute: [] 9 | - ${ QUESTION1 } -------------------------------------------------------------------------------- /tests/data/line/hello29.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code with condition 2 | text: 3 | - 'Hello! ' 4 | - lang: python 5 | code: | 6 | result = True 7 | def: QUESTION 8 | contribute: [] 9 | - data: 10 | x: ${ QUESTION1 } 11 | y: ${ QUESTION2 } 12 | z: 13 | a: ${ QUESTION3 } 14 | b: 15 | c: ${ QUESTION4 } -------------------------------------------------------------------------------- /tests/data/line/hello3.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world to call into a model 2 | defs: 3 | model: watsonx_text/ibm/granite-20b-code-instruct 4 | text: 5 | - Hello, 6 | - model: ${ model } 7 | spec: integer 8 | parameters: 9 | temperature: 0 10 | stop: 11 | - '!' 12 | mock_response: " World!" -------------------------------------------------------------------------------- /tests/data/line/hello30.pdl: -------------------------------------------------------------------------------- 1 | description: hello with bad for loop 2 | defs: 3 | val: 4 | data: 5 | p: 1 6 | for: 7 | k: ${ val } 8 | repeat: 9 | hello 10 | -------------------------------------------------------------------------------- /tests/data/line/hello31.pdl: -------------------------------------------------------------------------------- 1 | defs: 2 | 3 | # ... several other defs, ~85 lines 4 | get_current_weather: 5 | function: 6 | subject: string 7 | return: 8 | text: hello 9 | show_result: false -------------------------------------------------------------------------------- /tests/data/line/hello4.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world! 2 | text: 3 | - Hello, world! 4 | - "\n" 5 | - repeats: 6 | "This is your first PDL program\n" 7 | maxIterations: 3 -------------------------------------------------------------------------------- /tests/data/line/hello7.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code 2 | text: 3 | - 'Hello, ' 4 | - lans: python 5 | code: | 6 | import random 7 | import string 8 | result = random.choice(string.ascii_lowercase) 9 | - '!' -------------------------------------------------------------------------------- /tests/data/line/hello8.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code 2 | text: 3 | - 'Hello, ' 4 | - lang: python 5 | codea: | 6 | import random 7 | import string 8 | result = random.choice(string.ascii_lowercase) 9 | - '!' -------------------------------------------------------------------------------- /tests/data/line/hello9.pdl: -------------------------------------------------------------------------------- 1 | description: Hello world showing call out to python code 2 | text: 3 | - lang: python 4 | spec: integer 5 | code: | 6 | import string 7 | result = "hello" -------------------------------------------------------------------------------- /tests/results/contrib/prompt_library/CoT.0.result: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/results/contrib/prompt_library/ReAct.0.result: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/results/contrib/prompt_library/ReWoo.0.result: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/results/contrib/prompt_library/tools.0.result: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/results/examples/demo/1-hello.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello -------------------------------------------------------------------------------- /tests/results/examples/demo/11-repeat.0.result: -------------------------------------------------------------------------------- 1 | Bob's number is 1 2 | {"name": "Bob", "number": 1} 3 | Carol's number is 2 4 | {"name": "Carol", "number": 2} 5 | David's number is 3 6 | {"name": "David", "number": 3} 7 | Ernest's number is 4 8 | {"name": "Ernest", "number": 4} -------------------------------------------------------------------------------- /tests/results/examples/demo/2-model-chaining.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello 3 | Did you just say Hello? 4 | Yes, I did. It's a common greeting, similar to how humans might respond when they first interact with an artificial intelligence like me. How can I assist you today? -------------------------------------------------------------------------------- /tests/results/examples/demo/3-def-use.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello 3 | Hello translates to "Bonjour" in French. -------------------------------------------------------------------------------- /tests/results/examples/demo/3-def-use.1.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello 3 | Hello in French is "Bonjour". -------------------------------------------------------------------------------- /tests/results/examples/demo/4-function.0.result: -------------------------------------------------------------------------------- 1 | 'J'aime Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid!" -------------------------------------------------------------------------------- /tests/results/examples/demo/4-function.1.result: -------------------------------------------------------------------------------- 1 | 'J'aime Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid." -------------------------------------------------------------------------------- /tests/results/examples/demo/7-chatbot-roles.0.result: -------------------------------------------------------------------------------- 1 | Type `quit` to exit this chatbot. 2 | APR stands for Annual Percentage Rate. It's a measure of the annual cost of borrowing money, expressed as a percentage. This includes not only interest but also any fees charged by lenders. APR is used for many types of loans and credit cards to help consumers compare different offers more effectively. 3 | 4 | 5 | 6 | I'm sorry for any confusion, but it seems like your message "quit" was intended as a command rather than a statement. As an AI, I don't have the capability to exit conversations or processes on my own. My purpose is to provide information and engage in text-based interactions. If you want our conversation to end, you can simply close this window or tab on your device. 7 | 8 | -------------------------------------------------------------------------------- /tests/results/examples/demo/7-chatbot-roles.1.result: -------------------------------------------------------------------------------- 1 | Type `quit` to exit this chatbot. 2 | APR stands for Annual Percentage Rate. It's a measure of the annual cost of borrowing money, expressed as a percentage. This includes not only interest but also any fees associated with the loan. APR is used for many types of loans, including mortgages and credit cards, to help consumers compare different lending options more effectively. 3 | 4 | 5 | 6 | I'm sorry for any confusion, but as an AI, I don't have the ability to interpret "quit" as a command to end our conversation. If you want to exit, feel free to type "quit" or simply stop sending messages. I'm here to assist you until then. 7 | 8 | -------------------------------------------------------------------------------- /tests/results/examples/demo/8-tools.0.result: -------------------------------------------------------------------------------- 1 | Out of 1400 participants, 400 passed the test. What percentage is that? 2 | [{"name": "calc", "arguments": {"expr": "(400 / 1400) * 100"}}] 3 | 28.57142857142857 -------------------------------------------------------------------------------- /tests/results/examples/demos/react_fun.0.result: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/results/examples/input/input_test.0.result: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /tests/results/examples/input/input_test1.0.result: -------------------------------------------------------------------------------- 1 | The following will prompt the user on stdin. 2 | Hello -------------------------------------------------------------------------------- /tests/results/examples/input/input_test2.0.result: -------------------------------------------------------------------------------- 1 | A multiline stdin input. 2 | Hello 3 | -------------------------------------------------------------------------------- /tests/results/examples/intrinsics/demo-hallucination.0.result: -------------------------------------------------------------------------------- 1 | Did Faith Hill take a break from recording after releasing her second album, It Matters to Me? 2 | 3 | The answer is: Yes, Faith Hill took a three-year break from recording after releasing her second album, It Matters to Me. 4 | I am not hallucinating, promise! 5 | The citation is: After discovering that Hill was 6 | pregnant with their first child, the couple married on October 6, 1996. The 7 | couple have three daughters together: Gracie Katherine (born 1997), Maggie Elizabeth (born 1998) 8 | and Audrey Caroline (born 2001). Since their marriage, Hill and McGraw have endeavored 9 | never to be apart for more than three consecutive days. After the release of It Matters to Me, 10 | Hill took a three-year break from recording to give herself a rest from four years of touring 11 | and to begin a family with McGraw. During her break, she joined forces with her husband 12 | for their first duet, "It's Your Love". 13 | -------------------------------------------------------------------------------- /tests/results/examples/prompt_library/gsm8k_cot.0.result: -------------------------------------------------------------------------------- 1 | Answer the questions to the best of your abilities. 2 | 3 | Result: {'answer': '1. Jacob earns $6 per hour.\n2. Jake earns thrice what Jacob does, so Jake earns 3 * $6 = $18 per hour.\n3. Jake works 8 hours a day, so he earns $18 * 8 = $144 per day.\n4. Jake works 5 days, so he earns $144 * 5 = $720 in 5 days.\nThe answer is $720.'} 4 | -------------------------------------------------------------------------------- /tests/results/examples/prompt_library/gsm8k_react.0.result: -------------------------------------------------------------------------------- 1 | Result: {'answer': '$720'} 2 | -------------------------------------------------------------------------------- /tests/results/examples/prompt_library/gsm8k_rewoo.0.result: -------------------------------------------------------------------------------- 1 | Result: {'answer': 'Jake earns $18 per hour. In 5 days, working 8 hours a day, Jake works 5 * 8 = 40 hours. Therefore, Jake earns 40 * $18 = $720 in 5 days.\n\nAnswer: $720'} 2 | -------------------------------------------------------------------------------- /tests/results/examples/react/react_fun.0.result: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/tests/results/examples/react/react_fun.0.result -------------------------------------------------------------------------------- /tests/results/examples/sdk/hello.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello -------------------------------------------------------------------------------- /tests/results/examples/tools/calc.0.result: -------------------------------------------------------------------------------- 1 | Out of 1400 participants, 400 passed the test. What percentage is that? 2 | [{"name": "calc", "arguments": {"expr": "(400 / 1400) * 100"}}] 3 | 28.57142857142857 -------------------------------------------------------------------------------- /tests/results/examples/tutorial/calling_llm.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello -------------------------------------------------------------------------------- /tests/results/examples/tutorial/calling_llm_chaining.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello 3 | Did you just say Hello? 4 | Yes, I did. It's a common greeting, similar to how humans might respond when they first interact with an artificial intelligence like me. How can I assist you today? -------------------------------------------------------------------------------- /tests/results/examples/tutorial/calling_llm_with_input.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | The translation of "Hello" in French is "Bonjour". -------------------------------------------------------------------------------- /tests/results/examples/tutorial/calling_llm_with_input_messages.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | The translation of 'Hello' into French is 'Bonjour'. -------------------------------------------------------------------------------- /tests/results/examples/tutorial/code_command.0.result: -------------------------------------------------------------------------------- 1 | Hello World! 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/code_jinja.0.result: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /tests/results/examples/tutorial/code_pdl.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello! How can I assist you today? Let's chat about anything you'd like. Whether it's general knowledge, explanations on various topics, or just a casual conversation, I'm here to help. What's on your mind? -------------------------------------------------------------------------------- /tests/results/examples/tutorial/code_python.0.result: -------------------------------------------------------------------------------- 1 | Hello, o -------------------------------------------------------------------------------- /tests/results/examples/tutorial/code_python.1.result: -------------------------------------------------------------------------------- 1 | Hello, r -------------------------------------------------------------------------------- /tests/results/examples/tutorial/data_block_raw.0.result: -------------------------------------------------------------------------------- 1 | {'name': '${ name }', 'phone': '${ phone }'} -------------------------------------------------------------------------------- /tests/results/examples/tutorial/defs-hello.0.result: -------------------------------------------------------------------------------- 1 | Hello World! 2 | Good bye -------------------------------------------------------------------------------- /tests/results/examples/tutorial/defs.0.result: -------------------------------------------------------------------------------- 1 | 'J'aime Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid!" -------------------------------------------------------------------------------- /tests/results/examples/tutorial/defs.1.result: -------------------------------------------------------------------------------- 1 | 'J'aime Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid." 3 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/for.0.result: -------------------------------------------------------------------------------- 1 | 1234 -------------------------------------------------------------------------------- /tests/results/examples/tutorial/for_array.0.result: -------------------------------------------------------------------------------- 1 | [1, 2, 3, 4] -------------------------------------------------------------------------------- /tests/results/examples/tutorial/for_lastOf.0.result: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /tests/results/examples/tutorial/for_multiple_lists.0.result: -------------------------------------------------------------------------------- 1 | Bob's number is 1 2 | Carol's number is 2 3 | David's number is 3 4 | Ernest's number is 4 5 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/for_object.0.result: -------------------------------------------------------------------------------- 1 | {'Bob': 1, 'Carol': 2, 'David': 3, 'Ernest': 4} -------------------------------------------------------------------------------- /tests/results/examples/tutorial/for_with.0.result: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 -------------------------------------------------------------------------------- /tests/results/examples/tutorial/free_variables.0.result: -------------------------------------------------------------------------------- 1 | Hello World! 2 | ABC 3 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_alias.0.result: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_definition.0.result: -------------------------------------------------------------------------------- 1 | 'J'aime Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid!" -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_definition.1.result: -------------------------------------------------------------------------------- 1 | 'J'aime Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid." -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_definition.2.result: -------------------------------------------------------------------------------- 1 | 'J'adore Paris !' 2 | The translation of "I love Madrid!" into Spanish is: "Me encanta Madrid!" -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_empty_context.0.result: -------------------------------------------------------------------------------- 1 | Hello World!Greetings! I am Granite, a language model developed by IBM in 2024. How may I assist you today? -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_empty_context.1.result: -------------------------------------------------------------------------------- 1 | Hello World!Hello there! How can I assist you today? If you have any questions or need information on a particular topic, feel free to ask. I'm here to help. -------------------------------------------------------------------------------- /tests/results/examples/tutorial/function_optional_params.0.result: -------------------------------------------------------------------------------- 1 | Hello World Universe! -------------------------------------------------------------------------------- /tests/results/examples/tutorial/if.0.result: -------------------------------------------------------------------------------- 1 | Hello! How are you? -------------------------------------------------------------------------------- /tests/results/examples/tutorial/import.0.result: -------------------------------------------------------------------------------- 1 | Bye! -------------------------------------------------------------------------------- /tests/results/examples/tutorial/import_lib.0.result: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/prompt-declaration-language/f4fbdb850c2f3374d701cce9e4abd5a69e2798a4/tests/results/examples/tutorial/import_lib.0.result -------------------------------------------------------------------------------- /tests/results/examples/tutorial/independent.0.result: -------------------------------------------------------------------------------- 1 | hello in French!Bonjour! (Hello!) en Espanol!¡Hola! ¿En qué puedo ayudarte hoy? (Hello! How can I assist you today?)Goodbye!¡Adiós! (Goodbye!) 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/independent.1.result: -------------------------------------------------------------------------------- 1 | hello in French!Bonjour! (Hello!) en Espanol!¡Hola! ¿En qué puedo ayudarte hoy? (Hello! How can I assist you today?)Which language did I use last?You used Spanish in your previous message. Here's a quick summary: 2 | 3 | - Your first message was in English. 4 | - The second message was in Spanish. 5 | 6 | So, the languages you've used are English and Spanish. -------------------------------------------------------------------------------- /tests/results/examples/tutorial/independent_docs.0.result: -------------------------------------------------------------------------------- 1 | Hello world!Goodbye world!Hello and goodbye to you too! It seems like you've just greeted the world and bid it farewell in quick succession. I'm here to help, so if you have any questions or need information on a specific topic, feel free to ask. How can I assist you today? 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/independent_docs.1.result: -------------------------------------------------------------------------------- 1 | Hello world!Goodbye world!Hello and goodbye! It seems like you've greeted and bid farewell in quick succession. I'm here to help with any questions or tasks you have, so feel free to ask me anything. How can I assist you today? 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/independent_for.0.result: -------------------------------------------------------------------------------- 1 | Hello in FrenchBonjour! (Hello!)en Espanol¡Hola! ¿En qué puedo ayudarte hoy? (Translation: Hello! How can I assist you today?)Goodbye!¡Adiós! (Goodbye!) 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/input_file.0.result: -------------------------------------------------------------------------------- 1 | Hello World! -------------------------------------------------------------------------------- /tests/results/examples/tutorial/input_file_json.0.result: -------------------------------------------------------------------------------- 1 | Bob lives at the following address: 2 | 87 Smith Road in the town of Armonk, NY -------------------------------------------------------------------------------- /tests/results/examples/tutorial/input_stdin.0.result: -------------------------------------------------------------------------------- 1 | The following will prompt the user on stdin. 2 | What is APR? -------------------------------------------------------------------------------- /tests/results/examples/tutorial/input_stdin_multiline.0.result: -------------------------------------------------------------------------------- 1 | A multiline stdin input. 2 | Hello 3 | Bye 4 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/loop_index.0.result: -------------------------------------------------------------------------------- 1 | 123 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/muting_block_output.0.result: -------------------------------------------------------------------------------- 1 | The french sentence was: 'J'aime Paris !' -------------------------------------------------------------------------------- /tests/results/examples/tutorial/muting_block_output.1.result: -------------------------------------------------------------------------------- 1 | The french sentence was: 'J'adore Paris !' 2 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/parser-regex.0.result: -------------------------------------------------------------------------------- 1 | {"name": "Hello"} -------------------------------------------------------------------------------- /tests/results/examples/tutorial/parser_findall.0.result: -------------------------------------------------------------------------------- 1 | ['1', '2', '3', '4'] -------------------------------------------------------------------------------- /tests/results/examples/tutorial/parser_regex_code.0.result: -------------------------------------------------------------------------------- 1 | result = add_two_numbers(3, 5) 2 | print(result) # Output will be: 8 3 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/parser_regex_code.1.result: -------------------------------------------------------------------------------- 1 | result = add_two_numbers(3, 5) 2 | print(result) # Output: 8 3 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/programs/demo-hallucination.0.result: -------------------------------------------------------------------------------- 1 | Did Faith Hill take a break from recording after releasing her second album, It Matters to Me? 2 | 3 | The answer is: Yes, Faith Hill took a three-year break from recording after releasing her second album, It Matters to Me. 4 | I am not hallucinating, promise! 5 | The citation is: After discovering that Hill was 6 | pregnant with their first child, the couple married on October 6, 1996. The 7 | couple have three daughters together: Gracie Katherine (born 1997), Maggie Elizabeth (born 1998) 8 | and Audrey Caroline (born 2001). Since their marriage, Hill and McGraw have endeavored 9 | never to be apart for more than three consecutive days. After the release of It Matters to Me, 10 | Hill took a three-year break from recording to give herself a rest from four years of touring 11 | and to begin a family with McGraw. During her break, she joined forces with her husband 12 | for their first duet, "It's Your Love". 13 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/repeat.0.result: -------------------------------------------------------------------------------- 1 | 0: Bob's number is 42 2 | 1: Carol's number is 2 3 | 4 | -------------------------------------------------------------------------------- /tests/results/examples/tutorial/simple_program.0.result: -------------------------------------------------------------------------------- 1 | Hello, world! -------------------------------------------------------------------------------- /tests/results/examples/tutorial/variable_def_use.0.result: -------------------------------------------------------------------------------- 1 | Hello 2 | Hello 3 | GEN is equal to: Hello -------------------------------------------------------------------------------- /tests/results/examples/tutorial/while.0.result: -------------------------------------------------------------------------------- 1 | 123 -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/call-no-args.0.result: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/call-with-args.0.result: -------------------------------------------------------------------------------- 1 | hello world 4 bye 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/code-python.0.result: -------------------------------------------------------------------------------- 1 | {'foo': 3} -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/data1.0.result: -------------------------------------------------------------------------------- 1 | xxxx3True 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/data2.0.result: -------------------------------------------------------------------------------- 1 | xxxx3True 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/data3.0.result: -------------------------------------------------------------------------------- 1 | ${x}3True 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/data4.0.result: -------------------------------------------------------------------------------- 1 | yyyyxxxx3True 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/if1.0.result: -------------------------------------------------------------------------------- 1 | hi 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/if2.0.result: -------------------------------------------------------------------------------- 1 | good 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/include1.0.result: -------------------------------------------------------------------------------- 1 | hello world 4 bye 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/json-parser-lastOf.0.result: -------------------------------------------------------------------------------- 1 | value 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/json-parser.0.result: -------------------------------------------------------------------------------- 1 | {"key": "value"}value 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/jsonl-parser.0.result: -------------------------------------------------------------------------------- 1 | [{"key": "value"}, {"key2": "value2"}]valuevalue2 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/model-input-array.0.result: -------------------------------------------------------------------------------- 1 | As an assistant living in Europe, I'd be happy to share that the fastest land animal native to this continent is actually the Greyhound. These dogs are renowned for their incredible speed and can reach top speeds of around 43-45 miles per hour (70 km/h). They were originally bred for hunting, particularly for their ability to chase down prey at high velocities. -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/model-input-nested.0.result: -------------------------------------------------------------------------------- 1 | {"role": "user", "content": "answer as if you live in europe", "defsite": "text.0.message"}{"role": "user", "content": "what is the fastest animal where i live?", "defsite": "text.1.text.0.message"}As an assistant living in Europe, I'd be happy to share that the fastest land animal native to this continent is actually the Greyhound dog breed. These dogs are renowned for their incredible speed and agility on the ground. They can reach top speeds of around 45-48 miles per hour (72-77 kilometers per hour), making them one of the fastest animals in Europe. 2 | 3 | However, if we consider wild animals, the Cheetah is the fastest land animal globally and can be found in parts of Africa, including regions near the European border with North African countries like Libya and Tunisia. Cheetahs typically reach speeds up to 60-70 miles per hour (97-113 kilometers per hour), but they are not native to Europe. 4 | 5 | For a truly European animal, the Greyhound remains the fastest land creature in our region. -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/model-input-nested.1.result: -------------------------------------------------------------------------------- 1 | {'role': 'user', 'content': 'answer as if you live in europe', 'defsite': 'text.0.message'}{'role': 'user', 'content': 'what is the fastest animal where i live?', 'defsite': 'text.1.text.0.message'}As an assistant living in Europe, I'd be happy to share that the fastest land animal native to this continent is actually the Greyhound dog breed. These dogs are renowned for their incredible speed and agility on the ground. They can reach top speeds of around 45-48 miles per hour (72-77 kilometers per hour), making them one of the fastest animals in Europe. 2 | 3 | However, if we consider wild animals, the Cheetah is the fastest land animal globally and can be found in parts of Africa, including regions near the European border with North African countries like Libya and Tunisia. Cheetahs typically reach speeds up to 60-70 miles per hour (97-113 kilometers per hour), but they are not native to Europe. 4 | 5 | For a truly European animal, the Greyhound remains the fastest land creature in our region. -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/object1.0.result: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/object2.0.result: -------------------------------------------------------------------------------- 1 | foo2 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/read-file.0.result: -------------------------------------------------------------------------------- 1 | {"a": {"b": 3}}3 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/regex-findall.0.result: -------------------------------------------------------------------------------- 1 | [(999, 888)] 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/regex-findall.1.result: -------------------------------------------------------------------------------- 1 | [('999', '888')] 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/repeat1.0.result: -------------------------------------------------------------------------------- 1 | 234 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/repeat2.0.result: -------------------------------------------------------------------------------- 1 | 1a2b3c 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/repeat3.0.result: -------------------------------------------------------------------------------- 1 | 4a5b6c 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/scoping_1.0.result: -------------------------------------------------------------------------------- 1 | 3yo3mo 2 | -------------------------------------------------------------------------------- /tests/results/pdl-live-react/src-tauri/tests/cli/scoping_1_wrapper.0.result: -------------------------------------------------------------------------------- 1 | 3yo3mo 2 | -------------------------------------------------------------------------------- /tests/results/tests/data/call_expression_args.12.result: -------------------------------------------------------------------------------- 1 | FN::get_current_stock:: 'Simple call!' 2 | {'product_name': 'from_object'} 3 | FN::get_current_stock:: 'from_object' 4 | 5 | -------------------------------------------------------------------------------- /tests/results/tests/data/function.0.result: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/results/tests/data/hello.0.result: -------------------------------------------------------------------------------- 1 | Hello, world! 2 | This is your first PDL program 3 | This is your first PDL program 4 | 5 | -------------------------------------------------------------------------------- /tests/results/tests/data/optimizer_gsm8k.0.result: -------------------------------------------------------------------------------- 1 | Answer the questions to the best of your abilities. 2 | 3 | 4 | The answer is 144 5 | -------------------------------------------------------------------------------- /tests/test_array.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_dict 2 | 3 | array_data = {"description": "Array", "array": ["1", "2", "3", "4"]} 4 | 5 | 6 | def test_array_data(): 7 | result = exec_dict(array_data) 8 | assert result == ["1", "2", "3", "4"] 9 | 10 | 11 | for_data = { 12 | "description": "For block example", 13 | "for": { 14 | "i": [1, 2, 3, 4], 15 | }, 16 | "repeat": "${ i }", 17 | "join": {"as": "array"}, 18 | } 19 | 20 | 21 | def test_for_data(): 22 | result = exec_dict(for_data) 23 | assert result == [1, 2, 3, 4] 24 | 25 | 26 | repeat_until_data = { 27 | "description": "Repeat until", 28 | "lastOf": [ 29 | { 30 | "def": "I", 31 | "text": {"lang": "python", "code": "result = 0"}, 32 | }, 33 | { 34 | "repeat": { 35 | "def": "I", 36 | "lang": "python", 37 | "code": "result = ${ I } + 1", 38 | }, 39 | "until": "${ I == 5 }", 40 | "join": {"as": "array"}, 41 | }, 42 | ], 43 | } 44 | 45 | 46 | def test_repeat_until(): 47 | result = exec_dict(repeat_until_data) 48 | assert result == [1, 2, 3, 4, 5] 49 | -------------------------------------------------------------------------------- /tests/test_include.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from pdl.pdl import InterpreterConfig, exec_dict 4 | 5 | include_data = { 6 | "description": "Include test", 7 | "text": [ 8 | "Start\n", 9 | {"include": "./data/hello.pdl"}, 10 | "End", 11 | ], 12 | } 13 | 14 | 15 | def test_include(): 16 | config = InterpreterConfig(cwd=Path(__file__).parent) 17 | text = exec_dict(include_data, config=config) 18 | assert ( 19 | text 20 | == """Start 21 | Hello, world! 22 | This is your first PDL program 23 | This is your first PDL program 24 | End""" 25 | ) 26 | 27 | 28 | biz = { 29 | "description": "Include test", 30 | "text": [ 31 | {"include": "data/function.pdl"}, 32 | { 33 | "call": "${ template }", 34 | "args": { 35 | "preamble": "preamble data", 36 | "question": "question data", 37 | "notes": "notes data", 38 | }, 39 | }, 40 | ], 41 | } 42 | 43 | 44 | def test_biz(): 45 | config = InterpreterConfig(cwd=Path(__file__).parent) 46 | text = exec_dict(biz, config=config) 47 | assert ( 48 | text 49 | == "preamble data\n### Question: question data\n\n### Notes:\nnotes data\n\n### Answer:\n" 50 | ) 51 | -------------------------------------------------------------------------------- /tests/test_lib_version.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | import pdl 4 | 5 | 6 | def test_version(): 7 | # Make sure the __version__ attribute is available. 8 | assert pdl.__version__ is not None 9 | 10 | # Since pdl is not installed, the version returned will be the dev version. 11 | # NOTE: For some reason, the version is not the same as the hardcoded version. 12 | assert pdl.__version__.startswith("0.1.dev") 13 | 14 | 15 | if __name__ == "__main__": 16 | pytest.main(["-v", "--tb=short", __file__]) 17 | -------------------------------------------------------------------------------- /tests/test_object.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_str 2 | 3 | 4 | def test_direct_object(): 5 | prog_str = """ 6 | object: 7 | a: 1 8 | b: hello 9 | c: 10 | text: 11 | - bye 12 | - "!" 13 | """ 14 | result = exec_str(prog_str) 15 | assert result == {"a": 1, "b": "hello", "c": "bye!"} 16 | 17 | 18 | def test_composed_object(): 19 | prog_str = """ 20 | object: 21 | - object: 22 | a: 1 23 | b: hello 24 | - data: 25 | c: "bye!" 26 | """ 27 | result = exec_str(prog_str) 28 | assert result == {"a": 1, "b": "hello", "c": "bye!"} 29 | -------------------------------------------------------------------------------- /tests/test_parse.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_dict 2 | 3 | regex_data = { 4 | "description": "Parsing using regex", 5 | "text": "Malcolm Reynolds", 6 | "parser": { 7 | "spec": {"first_name": "string", "last_name": "string"}, 8 | "regex": "(?P\\w+) (?P\\w+)", 9 | }, 10 | } 11 | 12 | 13 | def test_model(): 14 | result = exec_dict(regex_data) 15 | assert result == {"first_name": "Malcolm", "last_name": "Reynolds"} 16 | -------------------------------------------------------------------------------- /tests/test_role.py: -------------------------------------------------------------------------------- 1 | from pdl.pdl import exec_str 2 | from pdl.pdl_context import SerializeMode 3 | 4 | 5 | def test_role1(): 6 | prog_str = """ 7 | description: Test role 8 | text: 9 | - defs: 10 | ctx1: ${pdl_context} 11 | text: A 12 | role: A 13 | - Hi 14 | - defs: 15 | ctx2: ${pdl_context} 16 | text: B 17 | role: B 18 | role: Top 19 | """ 20 | result = exec_str(prog_str, output="all") 21 | scope = result["scope"] 22 | assert result["result"] == "AHiB" 23 | assert scope["pdl_context"].serialize(SerializeMode.LITELLM) == [ 24 | {"role": "A", "content": "A", "defsite": "text.0.text"}, 25 | {"role": "Top", "content": "Hi", "defsite": "text.1"}, 26 | {"role": "B", "content": "B", "defsite": "text.2.text"}, 27 | ] 28 | assert scope["ctx1"].serialize(SerializeMode.LITELLM) == [] 29 | assert scope["ctx2"].serialize(SerializeMode.LITELLM) == [ 30 | {"role": "A", "content": "A", "defsite": "text.0.text"}, 31 | {"role": "Top", "content": "Hi", "defsite": "text.1"}, 32 | ] 33 | -------------------------------------------------------------------------------- /tests/test_schema.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | from pydantic.json_schema import models_json_schema 5 | 6 | import pdl.pdl 7 | from pdl.pdl_ast import PdlBlock, Program 8 | 9 | 10 | def test_saved_schema(): 11 | top, current_schema = models_json_schema( 12 | [ 13 | (Program, "validation"), 14 | (PdlBlock, "validation"), 15 | ], 16 | title="PDL Schemas", 17 | ) 18 | current_schema["anyOf"] = list(top.values()) 19 | pdl_schema_file = Path(pdl.pdl.__file__).parent / "pdl-schema.json" 20 | with open(pdl_schema_file, "r", encoding="utf-8") as fd: 21 | saved_schema = json.load(fd) 22 | assert current_schema == saved_schema 23 | --------------------------------------------------------------------------------