diff --git a/docs/home/calling/ai/pom/_category_.yaml b/docs/home/calling/ai/pom/_category_.yaml new file mode 100644 index 00000000..9b7d12e5 --- /dev/null +++ b/docs/home/calling/ai/pom/_category_.yaml @@ -0,0 +1 @@ +label: Prompt Object Model (POM) \ No newline at end of file diff --git a/docs/home/calling/ai/pom/_schema.mdx b/docs/home/calling/ai/pom/_schema.mdx new file mode 100644 index 00000000..a3af1ecd --- /dev/null +++ b/docs/home/calling/ai/pom/_schema.mdx @@ -0,0 +1,33 @@ +```json +{ + "$schema": "https://json-schema.org/draft-07/schema", + "$id": "https://example.com/pom.schema.json", + "title": "Prompt Object Model", + "type": "array", + "items": { "$ref": "#/$defs/section" }, + "$defs": { + "section": { + "type": "object", + "properties": { + "title": { "type": "string" }, + "body": { "type": "string" }, + "bullets": { + "type": "array", + "items": { "type": "string" } + }, + "subsections": { + "type": "array", + "items": { "$ref": "#/$defs/section" } + }, + "numbered": { "type": "boolean" }, + "numberedBullets": { "type": "boolean" } + }, + "anyOf": [ + { "required": ["body"] }, + { "required": ["bullets"] } + ], + "additionalProperties": false + } + } +} +``` diff --git a/docs/home/calling/ai/pom/index.mdx b/docs/home/calling/ai/pom/index.mdx new file mode 100644 index 00000000..36486481 --- /dev/null +++ b/docs/home/calling/ai/pom/index.mdx @@ -0,0 +1,341 @@ +--- +title: 'Prompt object model (POM)' +description: 'A lightweight Python library for structured prompt management with LLMs' +sidebar_position: 0 +slug: /ai/pom +--- + +[technical-reference]: /ai/pom/technical-reference +[sw-ai-services]: /ai + +## What is the prompt object model? + +The prompt object model (POM) is a structured data format and accompanying Python SDK for composing, organizing, +and rendering prompt instructions for large language models (LLMs). + +It provides a tree-based representation of a prompt document composed of nested sections, each of which can include: + +- A title. +- A body of explanatory or instructional text. +- An optional list of bullet points, which are additional formatting instructions for the body. +- Optional nested sections, which act as sub-instructions. + +:::important +To learn more about how to use the Prompt Object Model, see the [technical reference][technical-reference]. +::: + +POM supports both machine-readability (via JSON) and structured rendering (via Markdown), making it ideal for prompt templating, +modular editing, and traceable documentation - whether you're using [SignalWire's AI services][sw-ai-services] or another LLM provider. + +--- + +## Why structured prompts matter + +Creating effective prompts for LLMs is more than just writing good instructions - the structure and organization of those instructions +significantly impact how well the model responds. Having a poor structured prompt can lead to +inconsistent results, hallucinations, and the AI agent not following the instructions you provided. + +### The challenge of prompt engineering + +When working with large language models, the structure of your prompts significantly impacts model performance. +Well-structured prompts lead to better results, but maintaining this structure manually becomes challenging. + +Manual prompt management introduces formatting inconsistencies, resulting in prompt variability across different application components. +Complex prompt modifications frequently produce formatting errors or unintended behavioral changes. +Development efficiency suffers as common prompt patterns require reimplementation across multiple projects. +Standard version control systems struggle to effectively track changes to complex text prompts, complicating collaborative development. + +### How POM solves these challenges + +The Prompt Object Model abstracts away the structural maintenance of prompts, allowing you to focus on the content. + +POM implements automatic formatting that generates properly structured markdown or JSON, ensuring adherence to prompt engineering +best practices. The framework provides modular organization capabilities that enable logical section and subsection arrangement +mirroring design intent. Programmatic manipulation functions allow targeted modifications to specific prompt elements without +affecting surrounding content. The structured format enhances version control integration, facilitating meaningful change +tracking throughout development cycles. + +### Benefits for evolving prompts + +As prompt engineering grows more sophisticated, POM provides several key advantages. The framework enables clarity through +logical separation of instruction types (system, task-specific, constraints). Its architecture supports scalability, +allowing engineers to effortlessly add, remove, or reorder sections as prompt complexity increases. + +POM furnishes granular control for precise adjustments to specific prompt components while enforcing consistency across multiple prompts. +The model's template system facilitates reusability, enabling customization for diverse contexts. Additionally, +POM's markdown rendering capabilities enhance auditability, supporting both human review and direct LLM consumption of prompt documents. + +--- + +## Getting started + +### Installation + +To get started, install the `signalwire-pom` package using pip: + +```bash +pip install signalwire-pom +``` + +### Basic usage + +The following example demonstrates how to create a new POM and add a section with a title and body with a list of bullets. + +```python +from signalwire_pom import PromptObjectModel + +# Create a new POM +pom = PromptObjectModel() + +# Add a section with title and body +section = pom.add_section( + "System instructions", + body="You are a helpful AI assistant." +) + +# Add bullet points +section.add_bullets([ + "Answer user questions accurately", + "Be concise and clear" +]) + +# Render as markdown +markdown = pom.render_markdown() +print(markdown) +``` + +The above code will produce the following output: + +```markdown +## System instructions + +You are a helpful AI assistant. + +- Answer user questions accurately +- Be concise and clear +``` + +### Complete example + +Here's a more complete example showing how to create a structured prompt for an AI assistant: + +```python +from signalwire_pom import PromptObjectModel + +# Create a new POM +pom = PromptObjectModel() + +# Create main sections for an LLM prompt +objective = pom.add_section( + "Objective", + body="You are an AI assistant built to help users draft professional emails." +) +objective.add_bullets([ + "Listen carefully to the user's requirements", + "Draft concise, clear, and professional emails", + "Provide options when appropriate" +]) + +# Add personality section +personality = pom.add_section( + "Personality", + body="You should present yourself with these traits:" +) +personality.add_bullets([ + "Professional but approachable", + "Clear and concise in communication", + "Helpful without being overly verbose" +]) + +# Add capabilities section with nested subsections +capabilities = pom.add_section( + "Capabilities", + body="You can perform the following email-related tasks:" +) + +# Add subsections +drafting = capabilities.add_subsection( + "Email drafting", + body="Create email drafts based on user specifications." +) +drafting.add_bullets([ + "Format emails properly with greeting, body, and signature", + "Adjust tone based on recipient and purpose", + "Include necessary information while being concise" +]) + +reviewing = capabilities.add_subsection( + "Email review", + body="Analyze and improve existing email drafts." +) +reviewing.add_bullets([ + "Check for grammar and spelling issues", + "Suggest improvements for clarity and tone", + "Identify missing information" +]) + +# Generate markdown +markdown = pom.render_markdown() +print(markdown) + +json = pom.to_json() +print(json) +``` + +#### Output + +The above code will produce the two outputs, depending on whether you call `render_markdown()` or `to_json()`: + + + + +```markdown +## Objective + +You are an AI assistant built to help users draft professional emails. + +- Listen carefully to the user's requirements +- Draft concise, clear, and professional emails +- Provide options when appropriate + +## Personality + +You should present yourself with these traits: + +- Professional but approachable +- Clear and concise in communication +- Helpful without being overly verbose + +## Capabilities + +You can perform the following email-related tasks: + +### Email drafting + +Create email drafts based on user specifications. + +- Format emails properly with greeting, body, and signature +- Adjust tone based on recipient and purpose +- Include necessary information while being concise + +### Email review + +Analyze and improve existing email drafts. + +- Check for grammar and spelling issues +- Suggest improvements for clarity and tone +- Identify missing information +``` + + + + + +```json +[ + { + "title": "Objective", + "body": "You are an AI assistant built to help users draft professional emails.", + "bullets": [ + "Listen carefully to the user's requirements", + "Draft concise, clear, and professional emails", + "Provide options when appropriate" + ], + "subsections": [] + }, + { + "title": "Personality", + "body": "You should present yourself with these traits:", + "bullets": [ + "Professional but approachable", + "Clear and concise in communication", + "Helpful without being overly verbose" + ], + "subsections": [] + }, + { + "title": "Capabilities", + "body": "You can perform the following email-related tasks:", + "bullets": [], + "subsections": [ + { + "title": "Email drafting", + "body": "Create email drafts based on user specifications.", + "bullets": [ + "Format emails properly with greeting, body, and signature", + "Adjust tone based on recipient and purpose", + "Include necessary information while being concise" + ], + "subsections": [] + }, + { + "title": "Email review", + "body": "Analyze and improve existing email drafts.", + "bullets": [ + "Check for grammar and spelling issues", + "Suggest improvements for clarity and tone", + "Identify missing information" + ], + "subsections": [] + } + ] + } +] +``` + + + + +```xml + + +
+ Objective + You are an AI assistant built to help users draft professional emails. + + Listen carefully to the user's requirements + Draft concise, clear, and professional emails + Provide options when appropriate + +
+
+ Personality + You should present yourself with these traits: + + Professional but approachable + Clear and concise in communication + Helpful without being overly verbose + +
+
+ Capabilities + You can perform the following email-related tasks: + +
+ Email drafting + Create email drafts based on user specifications. + + Format emails properly with greeting, body, and signature + Adjust tone based on recipient and purpose + Include necessary information while being concise + +
+
+ Email review + Analyze and improve existing email drafts. + + Check for grammar and spelling issues + Suggest improvements for clarity and tone + Identify missing information + +
+
+
+
+``` +
+
+ +## Next steps + + diff --git a/docs/home/calling/ai/pom/technical-reference.mdx b/docs/home/calling/ai/pom/technical-reference.mdx new file mode 100644 index 00000000..6476b149 --- /dev/null +++ b/docs/home/calling/ai/pom/technical-reference.mdx @@ -0,0 +1,803 @@ +--- +title: "POM technical reference" +description: "Learn more about the Prompt Object Model" +sidebar_position: 1 +slug: /ai/pom/technical-reference +sidebar_label: "Technical reference" +--- + +import Schema from './_schema.mdx'; + + +[pom-page]: /ai/pom +[pom-class]: #promptobjectmodel-class +[section-class]: #section-class +[add-section]: #add_section +[find-section]: #find_section +[to-json]: #to_json +[render-markdown-pom]: #render_markdown_pom +[render-xml-pom]: #render_xml_pom +[from-json]: #from_json +[add-body]: #add_body +[add-bullets]: #add_bullets +[add-subsection]: #add_subsection +[to-dict]: #to_dict +[render-markdown-section]: #render_markdown_section +[render-xml-section]: #render_xml_section +[json-schema]: https://json-schema.org/understanding-json-schema/about +[pom-pypi]: https://pypi.org/project/signalwire-pom/ +[to_yaml]: #to_yaml +[to_dict_pom]: #to-dict-pom +[from_yaml]: #from_yaml +[add_pom_as_subsection]: #add_pom_as_subsection + +Learn how to use the Prompt Object Model + +## Introduction + +This technical reference provides comprehensive documentation for developers working with the [Prompt Object Model (POM) library][pom-pypi]. +To learn more about what the Prompt Object Model is, see the [POM overview][pom-page]. + +## POM format specification + +The POM is a JSON array of section objects with specific requirements based on position and nesting: + +| Field | Required | Description | +|-------|----------|-------------| +| `title` | No | Heading text | +| `body` | One of `body` or `bullets` required | Paragraph or long-form instruction text | +| `bullets` | One of `body` or `bullets` required | Non-empty array of short statements/rules | +| `subsections` | No | Nested list of sections | +| `numbered` | No | Boolean indicating if section should be numbered | +| `numberedBullets` | No | Boolean indicating if bullets should be numbered | + +### JSON schema for POM + +Users can refer to the following [JSON schema][json-schema] and basic example below for the POM structure: + + + + + + + + +```json +[ + { + "body": "You are a helpful AI assistant with specific capabilities.", + "bullets": [ + "Follow user instructions carefully", + "Maintain professional tone" + ], + "numbered": true, + "subsections": [ + { + "title": "Communication Style", + "body": "When communicating, follow these guidelines:", + "numberedBullets": true, + "bullets": [ + "Be clear and concise", + "Use professional language" + ] + } + ] + }, + { + "title": "Task Execution", + "body": "When executing tasks, follow this process:", + "bullets": [ + "Understand the requirements fully", + "Plan the approach", + "Execute carefully" + ], + "numbered": true + } +] +``` + + + + +## Core classes + +The library consists of two main classes: + +| Class | Description | +| ----- | ----------- | +| [`PromptObjectModel`][pom-class] | The main container that holds all sections and provides top-level functionality | +| [`Section`][section-class] | Represents a single section in the prompt hierarchy with content and structure | + +--- + +## PromptObjectModel class + +The `PromptObjectModel` class is the main entry point for creating and managing prompt objects. + +### Constructing a new POM + +```python +from signalwire_pom import PromptObjectModel + +# Create a new POM +pom = PromptObjectModel() +``` + +### Methods + +| Method | Description | +| ------ | ----------- | +| [`add_section`][add-section] | Adds a top-level section to the prompt POM. | +| [`find_section`][find-section] | Finds a section by its title, searching recursively through all sections and subsections. | +| [`to_json`][to-json] | Converts the entire POM to a JSON string. | +| [`to_yaml`][to_yaml] | Converts the entire POM to a YAML string. | +| [`to_dict`][to_dict_pom] | Converts the entire POM to a list of dictionaries. | +| [`render_markdown`][render-markdown-pom] | Renders the entire POM as markdown. | +| [`render_xml`][render-xml-pom] | Renders the entire POM as XML. | +| [`from_json`][from-json] | Creates a `PromptObjectModel` instance from JSON data. | +| [`from_yaml`][from_yaml] | Creates a `PromptObjectModel` instance from YAML data. | +| [`add_pom_as_subsection`][add_pom_as_subsection] | Adds another POM as a subsection to a specified section. | + +--- + +#### add_section + +Adds a top-level section to the prompt POM. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `title`Optional | `Optional[str]` | - | The title of the section | +| `body`Optional | `str` | `''` | Body text for the section | +| `bullets`Optional | `Union[List[str], str]` | - | List of bullet points or a single string (which will be converted to a single-item list) | +| `numbered`Optional | `Optional[bool]` | `None` | Whether this section should be numbered | +| `numberedBullets`Optional | `bool` | `False` | Whether bullets should be numbered instead of using bullet points | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `Section` | The newly created section object | + +**Example:** +```python +# Create a section with a title and body +rules = pom.add_section( + "Rules", + body="Follow these important guidelines:" +) + +# Add bullet points +rules.add_bullets([ + "Never send emails on behalf of the user", + "Maintain user privacy and confidentiality" +]) +``` + +--- + +#### find_section + +Finds a section by its title, searching recursively through all sections and subsections. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `title`Required | `str` | - | The title to search for | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `Optional[Section]` | The found section or `None` if not found | + +**Example:** +```python +# Find a section by its title +rules_section = pom.find_section("Rules") +if rules_section: + # Modify the found section + rules_section.add_bullets(["Always suggest proofreading before sending"]) +``` + +--- + +#### to_json + +Converts the entire POM to a JSON string. + +**Parameters:** None + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `str` | JSON string representation of the POM | + +**Example:** +```python +# Generate JSON representation +json_data = pom.to_json() +print(json_data) +``` + +--- + +#### to_yaml + +Converts the entire POM to a YAML string. + +**Parameters:** None + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `str` | YAML string representation of the POM | + +**Example:** +```python +# Generate YAML representation +yaml_data = pom.to_yaml() +print(yaml_data) +``` + +--- + +#### to_dict {#to-dict-pom} + +Converts the entire POM to a list of dictionaries. + +**Parameters:** None + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `List[dict]` | List of dictionaries representing each section in the POM | + +**Example:** +```python +# Convert POM to dictionary representation +dict_data = pom.to_dict() +print(dict_data) +``` + +--- + +#### render_markdown {#render_markdown_pom} + +Renders the entire POM as markdown. +The method will follow the below logic when rendering the POM as markdown: + +**Rendering Logic:** +- Top-level sections with titles are rendered as `##` (h2 headings) +- Each level of nesting increases the heading level (h3, h4, etc.) +- Body text appears after the heading +- Bullet points are rendered as markdown list items with `-` prefix +- Proper line spacing is maintained between elements + +**Parameters:** None + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `str` | Markdown representation of the POM | + +**Example:** +```python +from signalwire_pom import PromptObjectModel + +# Create a new POM +pom = PromptObjectModel() + +# Add a section with title and body +section = pom.add_section( + "System instructions", + body="You are a helpful AI assistant." +) + +# Add bullet points +section.add_bullets([ + "Answer user questions accurately", + "Be concise and clear" +]) + +sub_section = section.add_subsection( + "Subsection 1", + body="This is the body of the subsection." +) + +sub_section.add_bullets([ + "Answer user questions accurately", + "Be concise and clear" +]) + +# Render as markdown +markdown = pom.render_markdown() +print(markdown) +``` + +**Output:** +```markdown +## System instructions + +You are a helpful AI assistant. + +- Answer user questions accurately +- Be concise and clear + +### Subsection 1 + +This is the body of the subsection. + +- Answer user questions accurately +- Be concise and clear +``` + +--- + +#### render_xml {#render_xml_pom} + +Renders the entire POM as XML. +The method will follow the below logic when rendering the POM as XML: + +**Rendering Logic:** +- The POM is wrapped in a root `` element +- Each section is represented as a `
` element +- Section properties are rendered as child elements: + - `` for the section title + - `<body>` for the section body text + - `<bullets>` containing individual `<bullet>` elements + - `<subsections>` containing nested `<section>` elements + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `indent`<span className="optional-arg">Optional</span> | `int` | `0` | The indentation level to start with (default: 0) | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `str` | XML representation of the POM | + +**Example:** +```python +# Using the same POM from the previous example +xml = pom.render_xml() +print(xml) +``` + +**Output:** +```xml +<?xml version="1.0" encoding="UTF-8"?> +<prompt> + <section> + <title>System instructions + You are a helpful AI assistant. + + Answer user questions accurately + Be concise and clear + + +
+ Subsection 1 + This is the body of the subsection. + + Answer user questions accurately + Be concise and clear + +
+
+
+
+``` + +--- + +#### from_json + +Creates a PromptObjectModel instance from JSON data. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `json_data`Required | `Union[str, dict]` | - | Either a JSON string or a parsed dictionary | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `PromptObjectModel` | A new instance populated with data from the JSON | + +**Example:** +```python +# Create a POM from JSON +json_string = ''' +[ + { + "title": "Knowledge", + "body": "You have the following specific knowledge:", + "bullets": ["Email etiquette", "Business terminology"], + "subsections": [] + } +] +''' +knowledge_pom = PromptObjectModel.from_json(json_string) +``` + +--- + +#### from_yaml + +Creates a PromptObjectModel instance from YAML data. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `yaml_data`Required | `Union[str, dict]` | - | Either a YAML string or a parsed dictionary | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `PromptObjectModel` | A new instance populated with data from the YAML | + +**Example:** +```python +# Create a POM from YAML +yaml_string = ''' +- title: Knowledge + body: You have the following specific knowledge + bullets: + - Email etiquette + - Business terminology + subsections: [] +''' +knowledge_pom = PromptObjectModel.from_yaml(yaml_string) +``` + +--- + +#### add_pom_as_subsection + +Adds another PromptObjectModel as a subsection to a section with the given title or section object. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `target`Required | `Union[str, Section]` | - | The title of the section or the Section object to add to | +| `pom_to_add`Required | `PromptObjectModel` | - | The PromptObjectModel to add as a subsection | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `None` | This method doesn't return a value | + +**Raises:** + +- `ValueError`: If no section with the target title is found (when target is a string) +- `TypeError`: If target is neither a string nor a Section object + +**Example:** +```python +# Create two POMs +base_pom = PromptObjectModel() +base_section = base_pom.add_section("Base Section", body="Main content") + +additional_pom = PromptObjectModel() +additional_pom.add_section("Additional Content", body="Extra information") + +# Add the additional POM as a subsection +base_pom.add_pom_as_subsection("Base Section", additional_pom) +``` + +--- + +## Section class + +The `Section` class represents a single section in the POM hierarchy and provides methods for managing content and structure. +A section can be accessed through a instance of the `PromptObjectModel` class. + +### Constructing a new Section + +```python +from signalwire_pom import PromptObjectModel + +# Create a new POM +pom = PromptObjectModel() + +# Add a section to the POM +section = pom.add_section("Section title", body="This is the main content of my section.") +``` + +### Methods + +| Method | Description | +| :------ | :----------- | +| [`add_body`][add-body] | Adds or replaces the body text for this section. | +| [`add_bullets`][add-bullets] | Adds bullet points to this section. | +| [`add_subsection`][add-subsection] | Adds a subsection to this section. | +| [`to_dict`][to-dict] | Converts the section to a dictionary representation. | +| [`render_markdown`][render-markdown-section] | Renders this section and all its subsections as markdown. | +| [`render_xml`][render-xml-section] | Renders this section and all its subsections as XML. | + +--- + +#### add_body + +Adds or replaces the body text for this section. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `body`Required | `str` | - | The text to set as the section body | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `None` | This method doesn't return a value | + +**Example:** +```python +section = pom.add_section("Section title") +section.add_body("This is the main content of my section.") +``` + +--- + +#### add_bullets + +Adds bullet points to this section. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `bullets`Required | `List[str]` | - | List of bullet points to add | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `None` | This method doesn't return a value | + +**Example:** +```python +section = pom.add_section("Guidelines") +section.add_bullets([ + "First important point", + "Second important point", + "Third important point" +]) +``` + +--- + +#### add_subsection + +Adds a subsection to this section. + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `title`Optional | `str` | - | The title of the subsection | +| `body`Optional | `str` | - | Optional body text for the subsection | +| `bullets`Optional | `Optional[List[str]]` | - | Optional list of bullet points | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `Section` | The newly created subsection | + +**Example:** +```python +capabilities = pom.add_section("Capabilities") +drafting = capabilities.add_subsection( + "Email drafting", + body="Create email drafts based on user specifications." +) +drafting.add_bullets([ + "Format emails properly with greeting, body, and signature", + "Adjust tone based on recipient and purpose" +]) +``` + +--- + +#### to_dict + +Converts the section to a dictionary representation. + +**Parameters:** None + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `dict` | Dictionary representation of the section | + +**Example:** +```python +section = pom.add_section("Test section") +section_dict = section.to_dict() +``` + +--- + +#### render_markdown {#render_markdown_section} + +Renders this section and all its subsections as markdown. +The method will follow the below logic when rendering the section as markdown: + +**Rendering Logic:** +- The section title is rendered as a heading, with heading level based on nesting depth +- The heading level starts at the provided `level` parameter (default: 2, which is `##`) +- Body text appears after the heading with a blank line +- Bullet points are rendered as markdown list items with `-` prefix +- Subsections are rendered with incremented heading levels to show hierarchy +- If a section has no title (only valid at root level), its content is rendered directly + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `level`Optional | `int` | `2` | The heading level to start with (default: 2, which corresponds to ##) | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `str` | Markdown representation of the section | + +**Example:** +```python +# Using a section from the previous example +section_markdown = section.render_markdown() +print(section_markdown) +``` + +**Output:** +```markdown +## System instructions + +You are a helpful AI assistant. + +- Answer user questions accurately +- Be concise and clear + +### Subsection 1 + +This is the body of the subsection. + +- Answer user questions accurately +- Be concise and clear +``` + +--- + +#### render_xml {#render_xml_section} + +Renders this section and all its subsections as XML. +The method will follow the below logic when rendering the section as XML: + +**Rendering Logic:** +- The section is represented as a `
` element +- Section properties are rendered as child elements: + - `` for the section title (if present) + - `<body>` for the section body text (if present) + - `<bullets>` containing individual `<bullet>` elements (if present) + - `<subsections>` containing nested `<section>` elements (if present) + +**Parameters:** + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------ | ----------- | +| `indent`<span className="optional-arg">Optional</span> | `int` | `0` | The indentation level to start with (default: 0) | + +**Returns:** + +| Type | Description | +| ---- | ----------- | +| `str` | XML representation of the section | + +**Example:** +```python +# Using a section from the previous example +section_xml = section.render_xml() +print(section_xml) +``` + +**Output:** +```xml +<section> + <title>System instructions + You are a helpful AI assistant. + + Answer user questions accurately + Be concise and clear + + +
+ Subsection 1 + This is the body of the subsection. + + Answer user questions accurately + Be concise and clear + +
+
+
+``` + +--- + +## Command line interface + +The POM library includes a command-line interface (CLI) tool for working with POM files. The CLI allows you to convert between different formats and merge POM files. + +### Usage + +```bash +pom_tool [--output=] [--outfile=] [--merge_pom="
:"] +``` + +### Arguments + +| Argument | Description | +|----------|-------------| +| `input_file`Required | Path to the input POM file (JSON or YAML format) | + +### Options + +| Option | Default | Description | +|--------|---------|-------------| +| `-h, --help`Optional | - | Show help message | +| `--output=`Optional | `md` | Output format: `md`, `xml`, `json`, `yaml` | +| `--outfile=`Optional | - | Output file path (if not specified, prints to stdout) | +| `--merge_pom=`Optional | - | Merge another POM file into a section: `"
:"` | + + +### Error handling + +The tool handles several error conditions: + +1. **Invalid output format**: Returns an error if the specified output format is not one of: `md`, `xml`, `json`, `yaml` +2. **File parsing errors**: Reports JSON/YAML parsing errors with descriptive messages +3. **Section not found**: When using `--merge_pom`, reports if the target section is not found +4. **Invalid merge syntax**: Validates the `section:filename` format for the merge option + +### Examples + +1. Convert a JSON POM file to Markdown: +```bash +pom_tool input.json --output=md +``` + +2. Convert a YAML POM file to XML and save to file: +```bash +pom_tool input.yaml --output=xml --outfile=output.xml +``` + +3. Merge two POM files: +```bash +pom_tool base.json --merge_pom="System Instructions:additional.json" --output=json +``` + +4. Show help message: +```bash +pom_tool --help +``` diff --git a/docs/swml/methods/ai/prompt/contexts/_category_.yaml b/docs/swml/methods/ai/prompt/contexts/_category_.yaml index 2b11c3a0..b1019111 100644 --- a/docs/swml/methods/ai/prompt/contexts/_category_.yaml +++ b/docs/swml/methods/ai/prompt/contexts/_category_.yaml @@ -1,2 +1,4 @@ collapsible: true -collapsed: false \ No newline at end of file +collapsed: false +label: prompt.contexts +position: 1 diff --git a/docs/swml/methods/ai/prompt/contexts/index.mdx b/docs/swml/methods/ai/prompt/contexts/index.mdx index 9a8d3e6f..ee3f770f 100644 --- a/docs/swml/methods/ai/prompt/contexts/index.mdx +++ b/docs/swml/methods/ai/prompt/contexts/index.mdx @@ -1,6 +1,4 @@ --- -sidebar_label: prompt.contexts -sidebar_position: 1 slug: /swml/methods/ai/prompt/contexts title: prompt.contexts description: An object that defines the context steps for the AI. The contexts are used to define the flow of the conversation. diff --git a/docs/swml/methods/ai/prompt/index.mdx b/docs/swml/methods/ai/prompt/index.mdx index 318227c8..0a850a05 100644 --- a/docs/swml/methods/ai/prompt/index.mdx +++ b/docs/swml/methods/ai/prompt/index.mdx @@ -8,22 +8,27 @@ description: Establish the set of rules and instructions for the AI agent throug tags: ['swml'] --- +[contexts]: /swml/methods/ai/prompt/contexts +[pom]: /swml/methods/ai/prompt/pom +[prompt-parameters]: #prompt-parameters + Establishes the initial set of instructions and settings to configure the agent. | Name | Type | Default | Description | |:-------------------------------------------------------|:---------|:--------|:----------------------------------------------------------------------| -| `prompt`Required | `object` | - | An object that accepts the [`prompt parameters`](#prompt-parameters). | +| `prompt`Required | `object` | - | An object that accepts the [`prompt parameters`][prompt-parameters]. | ## **prompt Parameters** | Name | Type | Default | Description | |:---------------------------------------------------------------------------------|:---------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `text`Required | `string` | - | The instructions to send to the agent. | -| [`contexts`](./contexts/index.mdx)Optional | `object` | - | An object that defines the contexts for the AI. The contexts are used to define the flow of the conversation. Every context object requires a `default` key, which is the default context that's used at the beginning of the conversation. Additionally, more contexts can be defined as any other key in the object. | +| [`contexts`][contexts]Optional | `object` | - | An object that defines the contexts for the AI. The contexts are used to define the flow of the conversation. Every context object requires a `default` key, which is the default context that's used at the beginning of the conversation. Additionally, more contexts can be defined as any other key in the object. | | `temperature`Optional | `number` | 1.0 | Randomness setting. Float value between 0.0 and 1.5. Closer to 0 will make the output less random. | | `top_p`Optional | `number` | 1.0 | Randomness setting. Alternative to `temperature`. Float value between 0.0 and 1.0. Closer to 0 will make the output less random. | | `confidence`Optional | `number` | 0.6 | Threshold to fire a speech-detect event at the end of the utterance. Float value between 0.0 and 1.0. Decreasing this value will reduce the pause after the user speaks, but may introduce false positives. | | `presence_penalty`Optional | `number` | 0 | Aversion to staying on topic. Float value between -2.0 and 2.0. Positive values increase the model's likelihood to talk about new topics. | +| [`pom`][pom]Optional | `object[]` | - | An array of objects that defines the prompt object model (POM) for the AI. The POM is a structured data format for organizing, and rendering prompt instructions for AI agents. If `text` is present while using `pom`, the `pom` prompt will be used instead of `text`. See the [POM technical reference][pom] for more information. | | `frequency_penalty`Optional | `number` | 0 | Aversion to repeating lines. Float value between -2.0 and 2.0. Positive values decrease the model's likelihood to repeat the same line verbatim. | diff --git a/docs/swml/methods/ai/prompt/pom/_category_.yaml b/docs/swml/methods/ai/prompt/pom/_category_.yaml new file mode 100644 index 00000000..46e32818 --- /dev/null +++ b/docs/swml/methods/ai/prompt/pom/_category_.yaml @@ -0,0 +1,4 @@ +label: prompt.pom +position: 1 +collapsible: true +collapsed: false diff --git a/docs/swml/methods/ai/prompt/pom/index.mdx b/docs/swml/methods/ai/prompt/pom/index.mdx new file mode 100644 index 00000000..edae2d4b --- /dev/null +++ b/docs/swml/methods/ai/prompt/pom/index.mdx @@ -0,0 +1,110 @@ +--- +slug: /swml/methods/ai/prompt/pom +title: prompt.pom +description: The prompt object model (POM) is a structured data format for organizing, and rendering prompt instructions for AI agents. +tags: ['swml'] +--- + +[pom-ref]: /ai/pom +[section]: #section + +## Prompt Object Model (POM) + + +The prompt object model (POM) is a structured data format designed for composing, organizing, and rendering prompt instructions for AI agents. +POM helps users create prompts that are clearly structured and easy to understand. +It allows for efficient editing, management, and maintenance of prompts. +By breaking prompts into sections, users can manage each section independently and then combine them into a single cohesive prompt. + +SignalWire will render the prompt into a markdown document. + +If the `text` parameter is present while using `pom`, the `pom` prompt will be used instead of `text`. + +:::important Want a library for working with the POM? +SignalWire provides a Python library for working with the POM. +More information can be found in the [POM reference][pom-ref]. +::: + +| Name | Type | Default | Description | +| :----------------------------------------------------- | :------- | :------ | :-------------------------------------------------------------------- | +| `pom`Optional | `object[]` | - | An array of objects that defines the prompt object model (POM) for the AI. Each object represents a [`section`][section] in the POM. | + + +## Section parameters {#section} + +Each seciton can contain one of the two valid objects. One of `body` or `bullets` or pass both is required. + + +| Name | Type | Default | Description | +| :----------------------------------------------------- | :------- | :------ | :-------------------------------------------------------------------- | +| `title`Optional | `string` | - | The title of the section. Will be a heading in the rendered prompt. | +| `body`Conditionally Required | `string` | - | The body of the section. This will be a paragraph in the rendered prompt. This parameter is required if `bullets` is not present. | +| `bullets`Conditionally Required | `string[]` | - | An array of strings that represent the bullets of the section. This will be a list of short statements/rules in the rendered prompt. This parameter is `optional` if `body` is present. | +| `subsections`Optional | `object[]` | - | An array of objects that defines the prompt object model (POM) for the AI. Each object represents a `section` in the POM allowing the users to nest sections within sections. | +| `numbered`Optional | `boolean` | `false` | If `true`, the section will be numbered in the rendered prompt. | +| `numberedBullets`Optional | `boolean` | `false` | If `true`, the bullets will be numbered in the rendered prompt. | + + +## Example + +Below is an example of using the POM to create a prompt. + +```yaml andJson +version: 1.0.0 +sections: + main: + - ai: + prompt: + text: "Prompt is defined in pom" + pom: + - title: "Agent Personality" + body: "You are a friendly and engaging assistant. Keep the conversation light and fun." + subsections: + - title: "Personal Information" + numberedBullets: true + bullets: + - "You are a AI Agent" + - "Your name is Frank" + - "You work at SignalWire" + - title: "Task" + body: "You are to ask the user a series of questions to gather information." + bullets: + - "Ask the user to provide their name" + - "Ask the user to provide their favorite color" + - "Ask the user to provide their favorite food" + - "Ask the user to provide their favorite movie" + - "Ask the user to provide their favorite TV show" + - "Ask the user to provide their favorite music" + - "Ask the user to provide their favorite sport" + - "Ask the user to provide their favorite animal" +``` + + +### Rendered Prompt + +The above example will render the following prompt: + +```markdown +## Agent Personality + +You are a friendly and engaging assistant. Keep the conversation light and fun. + +### Personal Information + +1. You are a AI Agent +2. Your name is Frank +3. You work at SignalWire + +## Task + +You are to ask the user a series of questions to gather information. + +- Ask the user to provide their name +- Ask the user to provide their favorite color +- Ask the user to provide their favorite food +- Ask the user to provide their favorite movie +- Ask the user to provide their favorite TV show +- Ask the user to provide their favorite music +- Ask the user to provide their favorite sport +- Ask the user to provide their favorite animal +``` diff --git a/package-lock.json b/package-lock.json index e21ad383..cb5ad06c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7199,49 +7199,75 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/bare-events": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", - "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", "dev": true, "optional": true }, "node_modules/bare-fs": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", - "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.2.tgz", + "integrity": "sha512-8wSeOia5B7LwD4+h465y73KOdj5QHsbbuoUfPBi+pXgFJIPuG7SsiOdJuijWMyfid49eD+WivpfY7KT8gbAzBA==", "dev": true, "optional": true, "dependencies": { - "bare-events": "^2.0.0", - "bare-path": "^2.0.0", - "bare-stream": "^2.0.0" + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } } }, "node_modules/bare-os": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", - "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", "dev": true, - "optional": true + "optional": true, + "engines": { + "bare": ">=1.14.0" + } }, "node_modules/bare-path": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", - "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "dev": true, "optional": true, "dependencies": { - "bare-os": "^2.1.0" + "bare-os": "^3.0.1" } }, "node_modules/bare-stream": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.1.tgz", - "integrity": "sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==", + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", "dev": true, "optional": true, "dependencies": { "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } } }, "node_modules/base64-js": { @@ -11467,9 +11493,9 @@ } }, "node_modules/estree-util-value-to-estree": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.2.1.tgz", - "integrity": "sha512-Vt2UOjyPbNQQgT5eJh+K5aATti0OjCIAGc9SgMdOFYbohuifsWclR74l0iZTJwePMgWYdX1hlVS+dedH9XV8kw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.3.3.tgz", + "integrity": "sha512-Db+m1WSD4+mUO7UgMeKkAwdbfNWwIxLt48XF2oFU9emPfXkIu+k5/nlOj313v7wqtAPo0f9REhUvznFrPkG8CQ==", "dependencies": { "@types/estree": "^1.0.0" }, @@ -13375,9 +13401,9 @@ } }, "node_modules/image-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz", - "integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", "dependencies": { "queue": "6.0.2" }, @@ -19646,9 +19672,9 @@ } }, "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", "dev": true, "dependencies": { "chownr": "^1.1.1", @@ -23300,17 +23326,17 @@ } }, "node_modules/tar-fs": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", - "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", "dev": true, "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.0" + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" } }, "node_modules/tar-stream": { diff --git a/src/css/customizations/_articles.scss b/src/css/customizations/_articles.scss index 8b3129c3..ee905985 100644 --- a/src/css/customizations/_articles.scss +++ b/src/css/customizations/_articles.scss @@ -62,7 +62,7 @@ These styles target the appearance of elements inside docs/articles only. table .optional-arg { display: block; font-size: 13px; - color: #999; + color: #a8a8a8 !important; } table .required-arg { @@ -73,13 +73,19 @@ These styles target the appearance of elements inside docs/articles only. table .deprecated-arg { display: block; text-decoration: line-through; - color: #999; + color: #6e6e6e; } table .deprecated-desc { color: #fa383e; font-size: 13px; } + + table .conditionally-arg { + display: block; + font-size: 13px; + color: var(--ifm-color-warning-dark); + } } /** Custom table of contents styling **/ @@ -94,9 +100,18 @@ These styles target the appearance of elements inside docs/articles only. } [data-theme="dark"] .required-arg { - color: var(--ifm-color-primary) !important; + color: var(--ifm-color-primary); } +[data-theme="dark"] .conditionally-arg { + color: var(--ifm-warning-color); +} + +[data-theme="dark"] .optional-arg { + color: #4f4f4f; +} + + figure { text-align: center; figcaption { diff --git a/tsconfig.json b/tsconfig.json index 09a56312..9c40c464 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,8 @@ "strict": true, "skipLibCheck": true, "importsNotUsedAsValues": "remove", - "types": ["jest", "@types/react", "node"], + "resolveJsonModule": true, + "types": ["jest", "@types/react", "node", "@docusaurus/module-type-aliases", "@docusaurus/theme-classic" ], "jsx": "react", "paths": { "@site/*": ["../*"],