structai 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structai
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A utility package for AI development
5
5
  Author-email: Wanghan Xu <xu_wanghan@sjtu.edu.cn>
6
6
  Project-URL: Homepage, https://github.com/black-yt/structai
@@ -41,9 +41,15 @@ cd structai
41
41
  pip install -e .
42
42
  ```
43
43
 
44
- ## API Reference & Usage
44
+ ## Usage
45
45
 
46
- ### `load_file(path)`
46
+ > **Note:** Before using LLM-related features, please ensure you have set the necessary environment variables:
47
+ > ```bash
48
+ > export LLM_API_KEY="your-api-key"
49
+ > export LLM_BASE_URL="your-api-base-url"
50
+ > ```
51
+
52
+ #### `load_file(path)`
47
53
 
48
54
  Automatically reads a file based on its extension.
49
55
 
@@ -62,7 +68,7 @@ df = load_file("data.csv")
62
68
  image = load_file("photo.jpg")
63
69
  ```
64
70
 
65
- ### `save_file(data, path)`
71
+ #### `save_file(data, path)`
66
72
 
67
73
  Automatically saves data to a file based on the extension.
68
74
 
@@ -78,7 +84,7 @@ save_file(data, "output.json")
78
84
  save_file(data, "backup.pkl")
79
85
  ```
80
86
 
81
- ### `print_once(msg)`
87
+ #### `print_once(msg)`
82
88
 
83
89
  Prints a message to stdout only the first time it is called. Useful for logging inside loops.
84
90
 
@@ -90,7 +96,7 @@ for i in range(10):
90
96
  # process(i)
91
97
  ```
92
98
 
93
- ### `make_print_once()`
99
+ #### `make_print_once()`
94
100
 
95
101
  Returns a new function that prints a message only once. This allows for creating local "print once" scopes.
96
102
 
@@ -106,7 +112,7 @@ logger1("Hello") # Does nothing
106
112
  logger2("World") # Prints "World"
107
113
  ```
108
114
 
109
- ### `LLMAgent`
115
+ #### `LLMAgent`
110
116
 
111
117
  A powerful wrapper class for interacting with OpenAI-compatible LLM APIs. It handles retries, timeouts, and structured output validation.
112
118
 
@@ -129,9 +135,9 @@ agent = LLMAgent(
129
135
  **Basic Usage (`__call__` or `safe_api`):**
130
136
 
131
137
  ```python
132
- response = agent("What is the capital of France?")
138
+ response = agent("Generate a random number.", n=3, temperature=1)
133
139
  print(response)
134
- # Output: "Paris"
140
+ # Output: ["Sure! Here's a random number for you: 738", "Sure! Here's a random number: 7382", "Sure! Here's a random number: 487."]
135
141
  ```
136
142
 
137
143
  **Structured Output Validation:**
@@ -141,7 +147,7 @@ You can enforce the output format (List, Dict, or specific types) using `return_
141
147
  ```python
142
148
  # Enforce a list of integers
143
149
  numbers = agent(
144
- "Generate 3 random numbers",
150
+ "Generate 3 random numbers, for example, [1, 2, 3].",
145
151
  return_example=[1],
146
152
  list_len=3
147
153
  )
@@ -149,7 +155,7 @@ numbers = agent(
149
155
 
150
156
  # Enforce a dictionary with specific keys
151
157
  profile = agent(
152
- "Create a user profile for Alice",
158
+ "Create a user profile for Alice, for example, {'name': Alice, 'age': 1, 'city': 'shanghai'}.",
153
159
  return_example={"name": "str", "age": 1, "city": "str"}
154
160
  )
155
161
  # Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}
@@ -165,7 +171,20 @@ description = agent(
165
171
  )
166
172
  ```
167
173
 
168
- ### `sanitize_text(text)`
174
+ **Memory Context:**
175
+
176
+ ```python
177
+ history = [
178
+ {"role": "user", "content": "My name is Bob."},
179
+ {"role": "assistant", "content": "Hello Bob."}
180
+ ]
181
+ answer = agent(
182
+ "What is my name?",
183
+ history=history,
184
+ )
185
+ ```
186
+
187
+ #### `sanitize_text(text)`
169
188
 
170
189
  Sanitizes text by keeping only ASCII English characters, digits, and common punctuation. Removes control characters and ANSI codes.
171
190
 
@@ -176,7 +195,7 @@ clean = sanitize_text("Hello \x1b[31mWorld\x1b[0m!")
176
195
  print(clean) # "Hello World!"
177
196
  ```
178
197
 
179
- ### `str2dict(s)`
198
+ #### `str2dict(s)`
180
199
 
181
200
  Robustly converts a string representation of a dictionary to a Python `dict`. It handles common formatting errors and uses `json_repair` as a fallback.
182
201
 
@@ -187,7 +206,7 @@ d = str2dict("{'a': 1, 'b': 2}")
187
206
  print(d['a']) # 1
188
207
  ```
189
208
 
190
- ### `str2list(s)`
209
+ #### `str2list(s)`
191
210
 
192
211
  Robustly converts a string representation of a list to a Python `list`.
193
212
 
@@ -198,7 +217,7 @@ l = str2list("[1, 2, 3]")
198
217
  print(len(l)) # 3
199
218
  ```
200
219
 
201
- ### `add_no_proxy_if_private(url)`
220
+ #### `add_no_proxy_if_private(url)`
202
221
 
203
222
  Checks if the hostname in the URL is a private IP address. If so, it adds it to the `no_proxy` environment variable to bypass proxies.
204
223
 
@@ -208,7 +227,7 @@ from structai import add_no_proxy_if_private
208
227
  add_no_proxy_if_private("http://192.168.1.100:8080/v1")
209
228
  ```
210
229
 
211
- ### `read_image(image_path)`
230
+ #### `read_image(image_path)`
212
231
 
213
232
  Reads an image from a path and returns a PIL Image object.
214
233
 
@@ -218,7 +237,7 @@ from structai import read_image
218
237
  img = read_image("photo.jpg")
219
238
  ```
220
239
 
221
- ### `encode_image(image_obj)`
240
+ #### `encode_image(image_obj)`
222
241
 
223
242
  Encodes a PIL Image object into a base64 string.
224
243
 
@@ -228,7 +247,7 @@ from structai import encode_image
228
247
  b64_str = encode_image(img)
229
248
  ```
230
249
 
231
- ### `messages_to_responses_input(messages)`
250
+ #### `messages_to_responses_input(messages)`
232
251
 
233
252
  Converts standard Chat Completions `messages` format (list of dicts) to the input format required by the Responses API.
234
253
 
@@ -239,7 +258,7 @@ messages = [{"role": "user", "content": "Hello"}]
239
258
  system_prompt, input_blocks = messages_to_responses_input(messages)
240
259
  ```
241
260
 
242
- ### `extract_text_outputs(result)`
261
+ #### `extract_text_outputs(result)`
243
262
 
244
263
  Extracts the text content from an LLM API response object (supports both Chat Completions and Responses API formats).
245
264
 
@@ -251,7 +270,7 @@ texts = extract_text_outputs(response)
251
270
  print(texts[0])
252
271
  ```
253
272
 
254
- ### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
273
+ #### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
255
274
 
256
275
  Executes a function concurrently for each item in `inp_list` using a thread pool.
257
276
 
@@ -267,7 +286,7 @@ results = multi_thread(inputs, square, max_workers=4)
267
286
  print(results) # [0, 1, 4, 9, ...]
268
287
  ```
269
288
 
270
- ### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
289
+ #### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
271
290
 
272
291
  Executes a function concurrently for each item in `inp_list` using a process pool. Ideal for CPU-bound tasks.
273
292
 
@@ -281,7 +300,7 @@ inputs = [{"n": 1000000} for _ in range(5)]
281
300
  results = multi_process(inputs, heavy_computation)
282
301
  ```
283
302
 
284
- ### `run_server(host="0.0.0.0", port=8001)`
303
+ #### `run_server(host="0.0.0.0", port=8001)`
285
304
 
286
305
  Starts a FastAPI server that acts as a proxy to an OpenAI-compatible LLM provider.
287
306
 
@@ -292,7 +311,7 @@ if __name__ == "__main__":
292
311
  run_server()
293
312
  ```
294
313
 
295
- ### `timeout_limit(timeout=None)`
314
+ #### `timeout_limit(timeout=None)`
296
315
 
297
316
  A decorator that enforces a maximum execution time on a function. Raises `TimeoutError` if the limit is exceeded.
298
317
 
@@ -308,7 +327,7 @@ def task():
308
327
  task()
309
328
  ```
310
329
 
311
- ### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
330
+ #### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
312
331
 
313
332
  Runs a function with a specified timeout without using a decorator.
314
333
 
@@ -321,7 +340,7 @@ def task(x):
321
340
  result = run_with_timeout(task, args=(10,), timeout=1.0)
322
341
  ```
323
342
 
324
- ### `parse_think_answer(text)`
343
+ #### `parse_think_answer(text)`
325
344
 
326
345
  Parses a string containing Chain-of-Thought tags (`<think>...</think>` and `<answer>...</answer>`) and returns the content of both.
327
346
 
@@ -334,7 +353,7 @@ print(f"Reasoning: {think}")
334
353
  print(f"Result: {answer}")
335
354
  ```
336
355
 
337
- ### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
356
+ #### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
338
357
 
339
358
  Extracts the substring found between two specific tags.
340
359
 
@@ -345,7 +364,7 @@ text = "Result: <json>{...}</json>"
345
364
  json_str = extract_within_tags(text, "<json>", "</json>")
346
365
  ```
347
366
 
348
- ### `get_all_file_paths(directory, suffix='')`
367
+ #### `get_all_file_paths(directory, suffix='')`
349
368
 
350
369
  Recursively retrieves all file paths in a directory that match a given suffix.
351
370
 
@@ -357,7 +376,7 @@ py_files = get_all_file_paths(".", suffix=".py")
357
376
  print(py_files)
358
377
  ```
359
378
 
360
- ### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
379
+ #### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
361
380
 
362
381
  Removes specified tags from a string, replacing them with a separator (default newline).
363
382
 
@@ -369,4 +388,4 @@ clean_text = remove_tag("<think>...</think> Answer")
369
388
 
370
389
  ## License
371
390
 
372
- MIT License
391
+ [MIT License](LICENSE)
@@ -17,9 +17,15 @@ cd structai
17
17
  pip install -e .
18
18
  ```
19
19
 
20
- ## API Reference & Usage
20
+ ## Usage
21
21
 
22
- ### `load_file(path)`
22
+ > **Note:** Before using LLM-related features, please ensure you have set the necessary environment variables:
23
+ > ```bash
24
+ > export LLM_API_KEY="your-api-key"
25
+ > export LLM_BASE_URL="your-api-base-url"
26
+ > ```
27
+
28
+ #### `load_file(path)`
23
29
 
24
30
  Automatically reads a file based on its extension.
25
31
 
@@ -38,7 +44,7 @@ df = load_file("data.csv")
38
44
  image = load_file("photo.jpg")
39
45
  ```
40
46
 
41
- ### `save_file(data, path)`
47
+ #### `save_file(data, path)`
42
48
 
43
49
  Automatically saves data to a file based on the extension.
44
50
 
@@ -54,7 +60,7 @@ save_file(data, "output.json")
54
60
  save_file(data, "backup.pkl")
55
61
  ```
56
62
 
57
- ### `print_once(msg)`
63
+ #### `print_once(msg)`
58
64
 
59
65
  Prints a message to stdout only the first time it is called. Useful for logging inside loops.
60
66
 
@@ -66,7 +72,7 @@ for i in range(10):
66
72
  # process(i)
67
73
  ```
68
74
 
69
- ### `make_print_once()`
75
+ #### `make_print_once()`
70
76
 
71
77
  Returns a new function that prints a message only once. This allows for creating local "print once" scopes.
72
78
 
@@ -82,7 +88,7 @@ logger1("Hello") # Does nothing
82
88
  logger2("World") # Prints "World"
83
89
  ```
84
90
 
85
- ### `LLMAgent`
91
+ #### `LLMAgent`
86
92
 
87
93
  A powerful wrapper class for interacting with OpenAI-compatible LLM APIs. It handles retries, timeouts, and structured output validation.
88
94
 
@@ -105,9 +111,9 @@ agent = LLMAgent(
105
111
  **Basic Usage (`__call__` or `safe_api`):**
106
112
 
107
113
  ```python
108
- response = agent("What is the capital of France?")
114
+ response = agent("Generate a random number.", n=3, temperature=1)
109
115
  print(response)
110
- # Output: "Paris"
116
+ # Output: ["Sure! Here's a random number for you: 738", "Sure! Here's a random number: 7382", "Sure! Here's a random number: 487."]
111
117
  ```
112
118
 
113
119
  **Structured Output Validation:**
@@ -117,7 +123,7 @@ You can enforce the output format (List, Dict, or specific types) using `return_
117
123
  ```python
118
124
  # Enforce a list of integers
119
125
  numbers = agent(
120
- "Generate 3 random numbers",
126
+ "Generate 3 random numbers, for example, [1, 2, 3].",
121
127
  return_example=[1],
122
128
  list_len=3
123
129
  )
@@ -125,7 +131,7 @@ numbers = agent(
125
131
 
126
132
  # Enforce a dictionary with specific keys
127
133
  profile = agent(
128
- "Create a user profile for Alice",
134
+ "Create a user profile for Alice, for example, {'name': Alice, 'age': 1, 'city': 'shanghai'}.",
129
135
  return_example={"name": "str", "age": 1, "city": "str"}
130
136
  )
131
137
  # Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}
@@ -141,7 +147,20 @@ description = agent(
141
147
  )
142
148
  ```
143
149
 
144
- ### `sanitize_text(text)`
150
+ **Memory Context:**
151
+
152
+ ```python
153
+ history = [
154
+ {"role": "user", "content": "My name is Bob."},
155
+ {"role": "assistant", "content": "Hello Bob."}
156
+ ]
157
+ answer = agent(
158
+ "What is my name?",
159
+ history=history,
160
+ )
161
+ ```
162
+
163
+ #### `sanitize_text(text)`
145
164
 
146
165
  Sanitizes text by keeping only ASCII English characters, digits, and common punctuation. Removes control characters and ANSI codes.
147
166
 
@@ -152,7 +171,7 @@ clean = sanitize_text("Hello \x1b[31mWorld\x1b[0m!")
152
171
  print(clean) # "Hello World!"
153
172
  ```
154
173
 
155
- ### `str2dict(s)`
174
+ #### `str2dict(s)`
156
175
 
157
176
  Robustly converts a string representation of a dictionary to a Python `dict`. It handles common formatting errors and uses `json_repair` as a fallback.
158
177
 
@@ -163,7 +182,7 @@ d = str2dict("{'a': 1, 'b': 2}")
163
182
  print(d['a']) # 1
164
183
  ```
165
184
 
166
- ### `str2list(s)`
185
+ #### `str2list(s)`
167
186
 
168
187
  Robustly converts a string representation of a list to a Python `list`.
169
188
 
@@ -174,7 +193,7 @@ l = str2list("[1, 2, 3]")
174
193
  print(len(l)) # 3
175
194
  ```
176
195
 
177
- ### `add_no_proxy_if_private(url)`
196
+ #### `add_no_proxy_if_private(url)`
178
197
 
179
198
  Checks if the hostname in the URL is a private IP address. If so, it adds it to the `no_proxy` environment variable to bypass proxies.
180
199
 
@@ -184,7 +203,7 @@ from structai import add_no_proxy_if_private
184
203
  add_no_proxy_if_private("http://192.168.1.100:8080/v1")
185
204
  ```
186
205
 
187
- ### `read_image(image_path)`
206
+ #### `read_image(image_path)`
188
207
 
189
208
  Reads an image from a path and returns a PIL Image object.
190
209
 
@@ -194,7 +213,7 @@ from structai import read_image
194
213
  img = read_image("photo.jpg")
195
214
  ```
196
215
 
197
- ### `encode_image(image_obj)`
216
+ #### `encode_image(image_obj)`
198
217
 
199
218
  Encodes a PIL Image object into a base64 string.
200
219
 
@@ -204,7 +223,7 @@ from structai import encode_image
204
223
  b64_str = encode_image(img)
205
224
  ```
206
225
 
207
- ### `messages_to_responses_input(messages)`
226
+ #### `messages_to_responses_input(messages)`
208
227
 
209
228
  Converts standard Chat Completions `messages` format (list of dicts) to the input format required by the Responses API.
210
229
 
@@ -215,7 +234,7 @@ messages = [{"role": "user", "content": "Hello"}]
215
234
  system_prompt, input_blocks = messages_to_responses_input(messages)
216
235
  ```
217
236
 
218
- ### `extract_text_outputs(result)`
237
+ #### `extract_text_outputs(result)`
219
238
 
220
239
  Extracts the text content from an LLM API response object (supports both Chat Completions and Responses API formats).
221
240
 
@@ -227,7 +246,7 @@ texts = extract_text_outputs(response)
227
246
  print(texts[0])
228
247
  ```
229
248
 
230
- ### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
249
+ #### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
231
250
 
232
251
  Executes a function concurrently for each item in `inp_list` using a thread pool.
233
252
 
@@ -243,7 +262,7 @@ results = multi_thread(inputs, square, max_workers=4)
243
262
  print(results) # [0, 1, 4, 9, ...]
244
263
  ```
245
264
 
246
- ### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
265
+ #### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
247
266
 
248
267
  Executes a function concurrently for each item in `inp_list` using a process pool. Ideal for CPU-bound tasks.
249
268
 
@@ -257,7 +276,7 @@ inputs = [{"n": 1000000} for _ in range(5)]
257
276
  results = multi_process(inputs, heavy_computation)
258
277
  ```
259
278
 
260
- ### `run_server(host="0.0.0.0", port=8001)`
279
+ #### `run_server(host="0.0.0.0", port=8001)`
261
280
 
262
281
  Starts a FastAPI server that acts as a proxy to an OpenAI-compatible LLM provider.
263
282
 
@@ -268,7 +287,7 @@ if __name__ == "__main__":
268
287
  run_server()
269
288
  ```
270
289
 
271
- ### `timeout_limit(timeout=None)`
290
+ #### `timeout_limit(timeout=None)`
272
291
 
273
292
  A decorator that enforces a maximum execution time on a function. Raises `TimeoutError` if the limit is exceeded.
274
293
 
@@ -284,7 +303,7 @@ def task():
284
303
  task()
285
304
  ```
286
305
 
287
- ### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
306
+ #### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
288
307
 
289
308
  Runs a function with a specified timeout without using a decorator.
290
309
 
@@ -297,7 +316,7 @@ def task(x):
297
316
  result = run_with_timeout(task, args=(10,), timeout=1.0)
298
317
  ```
299
318
 
300
- ### `parse_think_answer(text)`
319
+ #### `parse_think_answer(text)`
301
320
 
302
321
  Parses a string containing Chain-of-Thought tags (`<think>...</think>` and `<answer>...</answer>`) and returns the content of both.
303
322
 
@@ -310,7 +329,7 @@ print(f"Reasoning: {think}")
310
329
  print(f"Result: {answer}")
311
330
  ```
312
331
 
313
- ### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
332
+ #### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
314
333
 
315
334
  Extracts the substring found between two specific tags.
316
335
 
@@ -321,7 +340,7 @@ text = "Result: <json>{...}</json>"
321
340
  json_str = extract_within_tags(text, "<json>", "</json>")
322
341
  ```
323
342
 
324
- ### `get_all_file_paths(directory, suffix='')`
343
+ #### `get_all_file_paths(directory, suffix='')`
325
344
 
326
345
  Recursively retrieves all file paths in a directory that match a given suffix.
327
346
 
@@ -333,7 +352,7 @@ py_files = get_all_file_paths(".", suffix=".py")
333
352
  print(py_files)
334
353
  ```
335
354
 
336
- ### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
355
+ #### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
337
356
 
338
357
  Removes specified tags from a string, replacing them with a separator (default newline).
339
358
 
@@ -345,4 +364,4 @@ clean_text = remove_tag("<think>...</think> Answer")
345
364
 
346
365
  ## License
347
366
 
348
- MIT License
367
+ [MIT License](LICENSE)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "structai"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  authors = [
9
9
  { name="Wanghan Xu", email="xu_wanghan@sjtu.edu.cn" },
10
10
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structai
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A utility package for AI development
5
5
  Author-email: Wanghan Xu <xu_wanghan@sjtu.edu.cn>
6
6
  Project-URL: Homepage, https://github.com/black-yt/structai
@@ -41,9 +41,15 @@ cd structai
41
41
  pip install -e .
42
42
  ```
43
43
 
44
- ## API Reference & Usage
44
+ ## Usage
45
45
 
46
- ### `load_file(path)`
46
+ > **Note:** Before using LLM-related features, please ensure you have set the necessary environment variables:
47
+ > ```bash
48
+ > export LLM_API_KEY="your-api-key"
49
+ > export LLM_BASE_URL="your-api-base-url"
50
+ > ```
51
+
52
+ #### `load_file(path)`
47
53
 
48
54
  Automatically reads a file based on its extension.
49
55
 
@@ -62,7 +68,7 @@ df = load_file("data.csv")
62
68
  image = load_file("photo.jpg")
63
69
  ```
64
70
 
65
- ### `save_file(data, path)`
71
+ #### `save_file(data, path)`
66
72
 
67
73
  Automatically saves data to a file based on the extension.
68
74
 
@@ -78,7 +84,7 @@ save_file(data, "output.json")
78
84
  save_file(data, "backup.pkl")
79
85
  ```
80
86
 
81
- ### `print_once(msg)`
87
+ #### `print_once(msg)`
82
88
 
83
89
  Prints a message to stdout only the first time it is called. Useful for logging inside loops.
84
90
 
@@ -90,7 +96,7 @@ for i in range(10):
90
96
  # process(i)
91
97
  ```
92
98
 
93
- ### `make_print_once()`
99
+ #### `make_print_once()`
94
100
 
95
101
  Returns a new function that prints a message only once. This allows for creating local "print once" scopes.
96
102
 
@@ -106,7 +112,7 @@ logger1("Hello") # Does nothing
106
112
  logger2("World") # Prints "World"
107
113
  ```
108
114
 
109
- ### `LLMAgent`
115
+ #### `LLMAgent`
110
116
 
111
117
  A powerful wrapper class for interacting with OpenAI-compatible LLM APIs. It handles retries, timeouts, and structured output validation.
112
118
 
@@ -129,9 +135,9 @@ agent = LLMAgent(
129
135
  **Basic Usage (`__call__` or `safe_api`):**
130
136
 
131
137
  ```python
132
- response = agent("What is the capital of France?")
138
+ response = agent("Generate a random number.", n=3, temperature=1)
133
139
  print(response)
134
- # Output: "Paris"
140
+ # Output: ["Sure! Here's a random number for you: 738", "Sure! Here's a random number: 7382", "Sure! Here's a random number: 487."]
135
141
  ```
136
142
 
137
143
  **Structured Output Validation:**
@@ -141,7 +147,7 @@ You can enforce the output format (List, Dict, or specific types) using `return_
141
147
  ```python
142
148
  # Enforce a list of integers
143
149
  numbers = agent(
144
- "Generate 3 random numbers",
150
+ "Generate 3 random numbers, for example, [1, 2, 3].",
145
151
  return_example=[1],
146
152
  list_len=3
147
153
  )
@@ -149,7 +155,7 @@ numbers = agent(
149
155
 
150
156
  # Enforce a dictionary with specific keys
151
157
  profile = agent(
152
- "Create a user profile for Alice",
158
+ "Create a user profile for Alice, for example, {'name': Alice, 'age': 1, 'city': 'shanghai'}.",
153
159
  return_example={"name": "str", "age": 1, "city": "str"}
154
160
  )
155
161
  # Output: {'name': 'Alice', 'age': 25, 'city': 'New York'}
@@ -165,7 +171,20 @@ description = agent(
165
171
  )
166
172
  ```
167
173
 
168
- ### `sanitize_text(text)`
174
+ **Memory Context:**
175
+
176
+ ```python
177
+ history = [
178
+ {"role": "user", "content": "My name is Bob."},
179
+ {"role": "assistant", "content": "Hello Bob."}
180
+ ]
181
+ answer = agent(
182
+ "What is my name?",
183
+ history=history,
184
+ )
185
+ ```
186
+
187
+ #### `sanitize_text(text)`
169
188
 
170
189
  Sanitizes text by keeping only ASCII English characters, digits, and common punctuation. Removes control characters and ANSI codes.
171
190
 
@@ -176,7 +195,7 @@ clean = sanitize_text("Hello \x1b[31mWorld\x1b[0m!")
176
195
  print(clean) # "Hello World!"
177
196
  ```
178
197
 
179
- ### `str2dict(s)`
198
+ #### `str2dict(s)`
180
199
 
181
200
  Robustly converts a string representation of a dictionary to a Python `dict`. It handles common formatting errors and uses `json_repair` as a fallback.
182
201
 
@@ -187,7 +206,7 @@ d = str2dict("{'a': 1, 'b': 2}")
187
206
  print(d['a']) # 1
188
207
  ```
189
208
 
190
- ### `str2list(s)`
209
+ #### `str2list(s)`
191
210
 
192
211
  Robustly converts a string representation of a list to a Python `list`.
193
212
 
@@ -198,7 +217,7 @@ l = str2list("[1, 2, 3]")
198
217
  print(len(l)) # 3
199
218
  ```
200
219
 
201
- ### `add_no_proxy_if_private(url)`
220
+ #### `add_no_proxy_if_private(url)`
202
221
 
203
222
  Checks if the hostname in the URL is a private IP address. If so, it adds it to the `no_proxy` environment variable to bypass proxies.
204
223
 
@@ -208,7 +227,7 @@ from structai import add_no_proxy_if_private
208
227
  add_no_proxy_if_private("http://192.168.1.100:8080/v1")
209
228
  ```
210
229
 
211
- ### `read_image(image_path)`
230
+ #### `read_image(image_path)`
212
231
 
213
232
  Reads an image from a path and returns a PIL Image object.
214
233
 
@@ -218,7 +237,7 @@ from structai import read_image
218
237
  img = read_image("photo.jpg")
219
238
  ```
220
239
 
221
- ### `encode_image(image_obj)`
240
+ #### `encode_image(image_obj)`
222
241
 
223
242
  Encodes a PIL Image object into a base64 string.
224
243
 
@@ -228,7 +247,7 @@ from structai import encode_image
228
247
  b64_str = encode_image(img)
229
248
  ```
230
249
 
231
- ### `messages_to_responses_input(messages)`
250
+ #### `messages_to_responses_input(messages)`
232
251
 
233
252
  Converts standard Chat Completions `messages` format (list of dicts) to the input format required by the Responses API.
234
253
 
@@ -239,7 +258,7 @@ messages = [{"role": "user", "content": "Hello"}]
239
258
  system_prompt, input_blocks = messages_to_responses_input(messages)
240
259
  ```
241
260
 
242
- ### `extract_text_outputs(result)`
261
+ #### `extract_text_outputs(result)`
243
262
 
244
263
  Extracts the text content from an LLM API response object (supports both Chat Completions and Responses API formats).
245
264
 
@@ -251,7 +270,7 @@ texts = extract_text_outputs(response)
251
270
  print(texts[0])
252
271
  ```
253
272
 
254
- ### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
273
+ #### `multi_thread(inp_list, function, max_workers=40, use_tqdm=True)`
255
274
 
256
275
  Executes a function concurrently for each item in `inp_list` using a thread pool.
257
276
 
@@ -267,7 +286,7 @@ results = multi_thread(inputs, square, max_workers=4)
267
286
  print(results) # [0, 1, 4, 9, ...]
268
287
  ```
269
288
 
270
- ### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
289
+ #### `multi_process(inp_list, function, max_workers=40, use_tqdm=True)`
271
290
 
272
291
  Executes a function concurrently for each item in `inp_list` using a process pool. Ideal for CPU-bound tasks.
273
292
 
@@ -281,7 +300,7 @@ inputs = [{"n": 1000000} for _ in range(5)]
281
300
  results = multi_process(inputs, heavy_computation)
282
301
  ```
283
302
 
284
- ### `run_server(host="0.0.0.0", port=8001)`
303
+ #### `run_server(host="0.0.0.0", port=8001)`
285
304
 
286
305
  Starts a FastAPI server that acts as a proxy to an OpenAI-compatible LLM provider.
287
306
 
@@ -292,7 +311,7 @@ if __name__ == "__main__":
292
311
  run_server()
293
312
  ```
294
313
 
295
- ### `timeout_limit(timeout=None)`
314
+ #### `timeout_limit(timeout=None)`
296
315
 
297
316
  A decorator that enforces a maximum execution time on a function. Raises `TimeoutError` if the limit is exceeded.
298
317
 
@@ -308,7 +327,7 @@ def task():
308
327
  task()
309
328
  ```
310
329
 
311
- ### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
330
+ #### `run_with_timeout(func, args=(), kwargs=None, timeout=None)`
312
331
 
313
332
  Runs a function with a specified timeout without using a decorator.
314
333
 
@@ -321,7 +340,7 @@ def task(x):
321
340
  result = run_with_timeout(task, args=(10,), timeout=1.0)
322
341
  ```
323
342
 
324
- ### `parse_think_answer(text)`
343
+ #### `parse_think_answer(text)`
325
344
 
326
345
  Parses a string containing Chain-of-Thought tags (`<think>...</think>` and `<answer>...</answer>`) and returns the content of both.
327
346
 
@@ -334,7 +353,7 @@ print(f"Reasoning: {think}")
334
353
  print(f"Result: {answer}")
335
354
  ```
336
355
 
337
- ### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
356
+ #### `extract_within_tags(content, start_tag='<answer>', end_tag='</answer>', default_return=None)`
338
357
 
339
358
  Extracts the substring found between two specific tags.
340
359
 
@@ -345,7 +364,7 @@ text = "Result: <json>{...}</json>"
345
364
  json_str = extract_within_tags(text, "<json>", "</json>")
346
365
  ```
347
366
 
348
- ### `get_all_file_paths(directory, suffix='')`
367
+ #### `get_all_file_paths(directory, suffix='')`
349
368
 
350
369
  Recursively retrieves all file paths in a directory that match a given suffix.
351
370
 
@@ -357,7 +376,7 @@ py_files = get_all_file_paths(".", suffix=".py")
357
376
  print(py_files)
358
377
  ```
359
378
 
360
- ### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
379
+ #### `remove_tag(s, tags=["<think>", "</think>", "<answer>", "</answer>"], r="\n")`
361
380
 
362
381
  Removes specified tags from a string, replacing them with a separator (default newline).
363
382
 
@@ -369,4 +388,4 @@ clean_text = remove_tag("<think>...</think> Answer")
369
388
 
370
389
  ## License
371
390
 
372
- MIT License
391
+ [MIT License](LICENSE)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes