Skip to content

Commit f3ec5ab

Browse files
author
Matt Carey
committed
fix: openai create and write files
1 parent 13575ea commit f3ec5ab

14 files changed

Lines changed: 914 additions & 347 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
description:
3+
globs:
4+
---
5+
# Examples Standards
6+
7+
Standards for creating and maintaining examples in the StackOne repository.
8+
9+
<rule>
10+
name: examples_standards
11+
description: Standards for creating and maintaining examples for all functionality
12+
13+
filters:
14+
- type: path
15+
pattern: "^examples/.*"
16+
- type: path
17+
pattern: "^packages/.*/.*"
18+
19+
actions:
20+
- type: suggest
21+
message: |
22+
When working with examples:
23+
24+
1. Location Requirements:
25+
```
26+
examples/
27+
├── basic_usage/
28+
│ ├── basic_tool_usage.py # Basic usage examples
29+
│ └── error_handling.py # Error handling examples
30+
├── integrations/ # Integration examples
31+
│ ├── openai_integration.py
32+
│ └── other_integration.py
33+
└── README.md # Examples documentation
34+
```
35+
36+
2. Example Requirements:
37+
- Every public function/class needs at least one example
38+
- Examples should be runnable Python scripts
39+
- Include error handling cases
40+
- Load credentials from .env
41+
- Include type hints
42+
- Follow the same code style as the main codebase
43+
- Always use "gpt-4o-mini" as the model name in LLM examples
44+
- Keep examples minimal and focused on demonstrating specific functionality
45+
46+
3. Documentation:
47+
- Each example file should start with a docstring explaining its purpose
48+
- Include expected output in comments
49+
- Document any prerequisites (environment variables, etc)
50+
51+
4. Testing:
52+
- Examples should be tested as part of CI
53+
- Examples should work with the latest package version
54+
- Include sample responses in comments
55+
56+
examples:
57+
- input: |
58+
# Good example structure
59+
import os
60+
from dotenv import load_dotenv
61+
from stackone_ai import StackOneToolSet
62+
from openai import OpenAI
63+
64+
def main():
65+
"""Example showing basic usage of StackOneToolSet with OpenAI."""
66+
load_dotenv()
67+
68+
api_key = os.getenv("STACKONE_API_KEY")
69+
if not api_key:
70+
raise ValueError("STACKONE_API_KEY not found")
71+
72+
client = OpenAI()
73+
response = client.chat.completions.create(
74+
model="gpt-4o-mini", # Always use gpt-4o-mini in examples
75+
messages=[{"role": "user", "content": "Hello"}]
76+
)
77+
78+
# Example code...
79+
80+
if __name__ == "__main__":
81+
main()
82+
output: "Correctly structured example"
83+
84+
- input: |
85+
# Bad example - missing error handling, docs, types, wrong model name
86+
from stackone_ai import StackOneToolSet
87+
from openai import OpenAI
88+
89+
toolset = StackOneToolSet("hardcoded_key")
90+
client = OpenAI()
91+
response = client.chat.completions.create(
92+
model="gpt-4", # Wrong - should use gpt-4o-mini
93+
messages=[{"role": "user", "content": "Hello"}]
94+
)
95+
output: "Incorrectly structured example"
96+
97+
metadata:
98+
priority: high
99+
version: 1.0
100+
tags:
101+
- examples
102+
- documentation
103+
- testing
104+
</rule>

.cursor/rules/examples-standards.mdc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
---
2-
description:
3-
globs:
4-
---
51
# Examples Standards
62

73
Standards for creating and maintaining examples in the StackOne repository.
@@ -40,6 +36,8 @@ actions:
4036
- Load credentials from .env
4137
- Include type hints
4238
- Follow the same code style as the main codebase
39+
- Always use "gpt-4o-mini" as the model name in LLM examples
40+
- Keep examples minimal and focused on demonstrating specific functionality
4341

4442
3. Documentation:
4543
- Each example file should start with a docstring explaining its purpose
@@ -57,14 +55,21 @@ examples:
5755
import os
5856
from dotenv import load_dotenv
5957
from stackone_ai import StackOneToolSet
58+
from openai import OpenAI
6059

6160
def main():
62-
"""Example showing basic usage of StackOneToolSet."""
61+
"""Example showing basic usage of StackOneToolSet with OpenAI."""
6362
load_dotenv()
6463

6564
api_key = os.getenv("STACKONE_API_KEY")
6665
if not api_key:
6766
raise ValueError("STACKONE_API_KEY not found")
67+
68+
client = OpenAI()
69+
response = client.chat.completions.create(
70+
model="gpt-4o-mini", # Always use gpt-4o-mini in examples
71+
messages=[{"role": "user", "content": "Hello"}]
72+
)
6873

6974
# Example code...
7075

@@ -73,12 +78,16 @@ examples:
7378
output: "Correctly structured example"
7479

7580
- input: |
76-
# Bad example - missing error handling, docs, types
81+
# Bad example - missing error handling, docs, types, wrong model name
7782
from stackone_ai import StackOneToolSet
83+
from openai import OpenAI
7884

7985
toolset = StackOneToolSet("hardcoded_key")
80-
tools = toolset.get_tools("crm")
81-
result = tools["some_tool"].execute()
86+
client = OpenAI()
87+
response = client.chat.completions.create(
88+
model="gpt-4", # Wrong - should use gpt-4o-mini
89+
messages=[{"role": "user", "content": "Hello"}]
90+
)
8291
output: "Incorrectly structured example"
8392

8493
metadata:

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"python.analysis.ignore": ["scripts/**"]
2+
"python.analysis.ignore": ["scripts/**"],
3+
"makefile.configureOnOpen": false
34
}

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,11 @@ lint:
88
test:
99
uv run pytest
1010

11+
test-tools:
12+
uv run pytest packages/stackone-ai
13+
14+
test-examples:
15+
uv run pytest examples
16+
1117
mypy:
1218
uv run mypy packages/stackone-ai/stackone_ai

examples/error_handling.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
from dotenv import load_dotenv
22
from stackone_ai import StackOneToolSet
3+
from stackone_ai.toolset import ToolsetConfigError, ToolsetLoadError
34

45
load_dotenv()
56

67

78
def error_handling() -> None:
9+
try:
10+
# Example 1: Handle missing API key
11+
invalid_toolset = StackOneToolSet(api_key=None)
12+
except ToolsetConfigError as e:
13+
print("Config Error:", e)
14+
# Config Error: API key must be provided either through api_key parameter or STACKONE_API_KEY environment variable
15+
816
toolset = StackOneToolSet()
917

10-
# Example 1: Handle unknown vertical
11-
tools = toolset.get_tools(vertical="unknown_vertical")
12-
print("Tools for unknown vertical:", tools._tool_map)
13-
# {}
18+
# Example 2: Handle unknown vertical
19+
try:
20+
tools = toolset.get_tools(vertical="unknown_vertical")
21+
except ToolsetLoadError as e:
22+
print("Vertical Load Error:", e)
23+
# Vertical Load Error: No spec file found for vertical: unknown_vertical
1424

15-
# Example 2: Handle API errors with account_id
25+
# Example 3: Handle API errors with account_id
1626
tools = toolset.get_tools(vertical="crm", account_id="test_id")
1727
try:
1828
# Try with invalid ID
@@ -21,9 +31,9 @@ def error_handling() -> None:
2131
result = contacts_tool.execute({"id": "invalid_id"})
2232
except Exception as e:
2333
print(f"API Error: {e}")
24-
# 400 Client Error: Bad Request for url: https://api.stackone.com/unified/crm/contacts/invalid_id
34+
# API Error: 400 Client Error: Bad Request for url: https://api.stackone.com/unified/crm/contacts/invalid_id
2535

26-
# Example 3: Handle missing account ID
36+
# Example 4: Handle missing account ID
2737
tools_no_account = toolset.get_tools(vertical="crm", account_id=None)
2838
try:
2939
list_contacts_tool = tools_no_account.get_tool("list_contacts")
@@ -32,7 +42,7 @@ def error_handling() -> None:
3242
print("Result without account ID:", result)
3343
except Exception as e:
3444
print(f"Error when account ID is missing: {e}")
35-
# 501 Server Error: Not Implemented for url: https://api.stackone.com/unified/crm/contacts
45+
# Error when account ID is missing: 501 Server Error: Not Implemented for url: https://api.stackone.com/unified/crm/contacts
3646

3747

3848
if __name__ == "__main__":

examples/openai_integration.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""
22
This example demonstrates how to use StackOne tools with OpenAI's function calling.
33
4+
This example is runnable with the following command:
45
```bash
56
uv run examples/openai_integration.py
67
```
8+
9+
You can find out more about the OpenAI Function Calling API format [here](https://platform.openai.com/docs/guides/function-calling).
710
"""
811

912
from dotenv import load_dotenv
@@ -28,7 +31,20 @@ def handle_tool_calls(tools, tool_calls) -> list[dict]:
2831
def openai_integration() -> None:
2932
client = OpenAI()
3033
toolset = StackOneToolSet()
31-
tools = toolset.get_tools(vertical="hris", account_id=account_id)
34+
35+
# Get all tools but only convert the ones we need for this example
36+
all_tools = toolset.get_tools(vertical="hris", account_id=account_id)
37+
38+
# Only use the employee-related tools we need
39+
needed_tool_names = [
40+
"hris_get_employee",
41+
"hris_list_employee_employments",
42+
"hris_get_employee_employment",
43+
]
44+
45+
# Filter tools to only the ones we need
46+
filtered_tools = [tool for tool in all_tools.tools if tool.name in needed_tool_names]
47+
tools = type(all_tools)(filtered_tools) # Create new Tools instance with filtered list
3248
openai_tools = tools.to_openai()
3349

3450
messages = [

0 commit comments

Comments
 (0)