onetool-mcp 1.0.0b1__py3-none-any.whl → 1.0.0rc2__py3-none-any.whl
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.
- onetool/cli.py +63 -4
- onetool_mcp-1.0.0rc2.dist-info/METADATA +266 -0
- onetool_mcp-1.0.0rc2.dist-info/RECORD +129 -0
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/LICENSE.txt +1 -1
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/NOTICE.txt +54 -64
- ot/__main__.py +6 -6
- ot/config/__init__.py +48 -46
- ot/config/global_templates/__init__.py +2 -2
- ot/config/{defaults → global_templates}/diagram-templates/api-flow.mmd +33 -33
- ot/config/{defaults → global_templates}/diagram-templates/c4-context.puml +30 -30
- ot/config/{defaults → global_templates}/diagram-templates/class-diagram.mmd +87 -87
- ot/config/{defaults → global_templates}/diagram-templates/feature-mindmap.mmd +70 -70
- ot/config/{defaults → global_templates}/diagram-templates/microservices.d2 +81 -81
- ot/config/{defaults → global_templates}/diagram-templates/project-gantt.mmd +37 -37
- ot/config/{defaults → global_templates}/diagram-templates/state-machine.mmd +42 -42
- ot/config/global_templates/diagram.yaml +167 -0
- ot/config/global_templates/onetool.yaml +3 -1
- ot/config/{defaults → global_templates}/prompts.yaml +102 -97
- ot/config/global_templates/security.yaml +31 -0
- ot/config/global_templates/servers.yaml +93 -12
- ot/config/global_templates/snippets.yaml +5 -26
- ot/config/{defaults → global_templates}/tool_templates/__init__.py +7 -7
- ot/config/loader.py +221 -105
- ot/config/mcp.py +5 -1
- ot/config/secrets.py +192 -190
- ot/decorators.py +116 -116
- ot/executor/__init__.py +35 -35
- ot/executor/base.py +16 -16
- ot/executor/fence_processor.py +83 -83
- ot/executor/linter.py +142 -142
- ot/executor/pep723.py +288 -288
- ot/executor/runner.py +20 -6
- ot/executor/simple.py +163 -163
- ot/executor/validator.py +603 -164
- ot/http_client.py +145 -145
- ot/logging/__init__.py +37 -37
- ot/logging/entry.py +213 -213
- ot/logging/format.py +191 -188
- ot/logging/span.py +349 -349
- ot/meta.py +236 -14
- ot/paths.py +32 -49
- ot/prompts.py +218 -218
- ot/proxy/manager.py +14 -2
- ot/registry/__init__.py +189 -189
- ot/registry/parser.py +269 -269
- ot/server.py +330 -315
- ot/shortcuts/__init__.py +15 -15
- ot/shortcuts/aliases.py +87 -87
- ot/shortcuts/snippets.py +258 -258
- ot/stats/__init__.py +35 -35
- ot/stats/html.py +2 -2
- ot/stats/reader.py +354 -354
- ot/stats/timing.py +57 -57
- ot/support.py +63 -63
- ot/tools.py +1 -1
- ot/utils/batch.py +161 -161
- ot/utils/cache.py +120 -120
- ot/utils/exceptions.py +23 -23
- ot/utils/factory.py +178 -179
- ot/utils/format.py +65 -65
- ot/utils/http.py +202 -202
- ot/utils/platform.py +45 -45
- ot/utils/truncate.py +69 -69
- ot_tools/__init__.py +4 -4
- ot_tools/_convert/__init__.py +12 -12
- ot_tools/_convert/pdf.py +254 -254
- ot_tools/diagram.yaml +167 -167
- ot_tools/scaffold.py +2 -2
- ot_tools/transform.py +124 -19
- ot_tools/web_fetch.py +94 -43
- onetool_mcp-1.0.0b1.dist-info/METADATA +0 -163
- onetool_mcp-1.0.0b1.dist-info/RECORD +0 -132
- ot/config/defaults/bench.yaml +0 -4
- ot/config/defaults/onetool.yaml +0 -25
- ot/config/defaults/servers.yaml +0 -7
- ot/config/defaults/snippets.yaml +0 -4
- ot_tools/firecrawl.py +0 -732
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/WHEEL +0 -0
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/entry_points.txt +0 -0
- /ot/config/{defaults → global_templates}/tool_templates/extension.py +0 -0
- /ot/config/{defaults → global_templates}/tool_templates/isolated.py +0 -0
ot_tools/diagram.yaml
CHANGED
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
# Diagram tool configuration
|
|
2
|
-
# Load via: include: [diagram.yaml]
|
|
3
|
-
|
|
4
|
-
tools:
|
|
5
|
-
diagram:
|
|
6
|
-
backend:
|
|
7
|
-
type: kroki
|
|
8
|
-
remote_url: https://kroki.io
|
|
9
|
-
self_hosted_url: http://localhost:8000
|
|
10
|
-
prefer: self_hosted # remote | self_hosted | auto
|
|
11
|
-
timeout: 30.0
|
|
12
|
-
|
|
13
|
-
policy:
|
|
14
|
-
rules: |
|
|
15
|
-
NEVER use ASCII art or text-based diagrams in markdown.
|
|
16
|
-
Use the diagram tools for all visual representations.
|
|
17
|
-
Save output as SVG and reference in markdown.
|
|
18
|
-
Always generate source first, then render.
|
|
19
|
-
Choose the provider based on diagram type - see instructions.
|
|
20
|
-
preferred_format: svg
|
|
21
|
-
preferred_providers:
|
|
22
|
-
- mermaid
|
|
23
|
-
- d2
|
|
24
|
-
- plantuml
|
|
25
|
-
|
|
26
|
-
output:
|
|
27
|
-
dir: ../diagrams # Relative to config dir (.onetool/../diagrams)
|
|
28
|
-
naming: "{provider}_{name}_{timestamp}"
|
|
29
|
-
default_format: svg
|
|
30
|
-
save_source: true
|
|
31
|
-
|
|
32
|
-
instructions:
|
|
33
|
-
mermaid:
|
|
34
|
-
when_to_use: |
|
|
35
|
-
- Flowcharts and decision trees
|
|
36
|
-
- Sequence diagrams for API flows
|
|
37
|
-
- Class diagrams for data models
|
|
38
|
-
- State diagrams for workflows
|
|
39
|
-
- Gantt charts for project timelines
|
|
40
|
-
- Mindmaps for brainstorming
|
|
41
|
-
style_tips: |
|
|
42
|
-
Use subgraphs to group related nodes.
|
|
43
|
-
Keep flowcharts top-to-bottom (TD) for readability.
|
|
44
|
-
Limit sequence diagrams to 5-7 participants.
|
|
45
|
-
|
|
46
|
-
QUOTING RULES (critical):
|
|
47
|
-
- Sequence diagrams: NO quotes after 'as' (they appear literally)
|
|
48
|
-
Use: participant WS as Web Server
|
|
49
|
-
NOT: participant WS as "Web Server"
|
|
50
|
-
- Flowcharts/class: USE quotes for labels with spaces
|
|
51
|
-
Use: A["Start Process"], B{"Decision?"}
|
|
52
|
-
- Never put spaces in node/participant IDs
|
|
53
|
-
syntax_guide: https://mermaid.js.org/syntax/
|
|
54
|
-
example: |
|
|
55
|
-
sequenceDiagram
|
|
56
|
-
participant C as Client
|
|
57
|
-
participant S as Server
|
|
58
|
-
C->>S: Request
|
|
59
|
-
S-->>C: Response
|
|
60
|
-
|
|
61
|
-
plantuml:
|
|
62
|
-
when_to_use: |
|
|
63
|
-
- Complex UML diagrams (class, component, deployment)
|
|
64
|
-
- C4 architecture diagrams (use stdlib)
|
|
65
|
-
- Detailed sequence diagrams with notes
|
|
66
|
-
- Diagrams requiring themes and skinparams
|
|
67
|
-
style_tips: |
|
|
68
|
-
Use skinparam for consistent theming.
|
|
69
|
-
Leverage !include for reusable components.
|
|
70
|
-
Use packages to organise large diagrams.
|
|
71
|
-
Add notes for context on complex relationships.
|
|
72
|
-
|
|
73
|
-
QUOTING RULES (critical):
|
|
74
|
-
- Always quote display names BEFORE 'as':
|
|
75
|
-
participant "Web Server" as WS
|
|
76
|
-
- Never put spaces in aliases (the ID after 'as')
|
|
77
|
-
- Use stereotypes for interfaces: <<interface>>
|
|
78
|
-
syntax_guide: https://plantuml.com/
|
|
79
|
-
example: |
|
|
80
|
-
@startuml
|
|
81
|
-
actor User
|
|
82
|
-
participant "API Gateway" as GW
|
|
83
|
-
database DB
|
|
84
|
-
|
|
85
|
-
User -> GW: Login request
|
|
86
|
-
GW -> DB: Check credentials
|
|
87
|
-
DB --> GW: User record
|
|
88
|
-
GW --> User: 200 OK
|
|
89
|
-
@enduml
|
|
90
|
-
|
|
91
|
-
d2:
|
|
92
|
-
when_to_use: |
|
|
93
|
-
- Clean architecture diagrams
|
|
94
|
-
- System context diagrams
|
|
95
|
-
- Hand-drawn style (sketch mode)
|
|
96
|
-
- Layouts with automatic positioning
|
|
97
|
-
- C4-style container diagrams
|
|
98
|
-
style_tips: |
|
|
99
|
-
Use containers for logical grouping.
|
|
100
|
-
D2 auto-layouts well - avoid manual positioning.
|
|
101
|
-
Use markdown in labels for rich formatting.
|
|
102
|
-
Leverage layers for complex diagrams.
|
|
103
|
-
Use shape: person for actors.
|
|
104
|
-
Direction hint: direction: right or direction: down.
|
|
105
|
-
|
|
106
|
-
QUOTING RULES (critical):
|
|
107
|
-
- Always quote labels after colon: node: "Display Name"
|
|
108
|
-
- IDs (before colon) should not have spaces
|
|
109
|
-
- Use style.sketch: true for hand-drawn look
|
|
110
|
-
syntax_guide: https://d2lang.com/tour/intro
|
|
111
|
-
example: |
|
|
112
|
-
direction: right
|
|
113
|
-
|
|
114
|
-
user: "User" {
|
|
115
|
-
shape: person
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
system: "My System" {
|
|
119
|
-
api: "API Server"
|
|
120
|
-
db: "Database"
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
user -> system.api: "Uses"
|
|
124
|
-
system.api -> system.db
|
|
125
|
-
|
|
126
|
-
templates:
|
|
127
|
-
api-flow:
|
|
128
|
-
provider: mermaid
|
|
129
|
-
diagram_type: sequence
|
|
130
|
-
description: REST API request/response flow
|
|
131
|
-
file: diagram-templates/api-flow.mmd
|
|
132
|
-
|
|
133
|
-
microservices:
|
|
134
|
-
provider: d2
|
|
135
|
-
diagram_type: architecture
|
|
136
|
-
description: Microservices architecture layout
|
|
137
|
-
file: diagram-templates/microservices.d2
|
|
138
|
-
|
|
139
|
-
c4-context:
|
|
140
|
-
provider: plantuml
|
|
141
|
-
diagram_type: c4
|
|
142
|
-
description: C4 system context diagram
|
|
143
|
-
file: diagram-templates/c4-context.puml
|
|
144
|
-
|
|
145
|
-
state-machine:
|
|
146
|
-
provider: mermaid
|
|
147
|
-
diagram_type: state
|
|
148
|
-
description: State machine diagram
|
|
149
|
-
file: diagram-templates/state-machine.mmd
|
|
150
|
-
|
|
151
|
-
class-diagram:
|
|
152
|
-
provider: mermaid
|
|
153
|
-
diagram_type: class
|
|
154
|
-
description: Class/data model diagram
|
|
155
|
-
file: diagram-templates/class-diagram.mmd
|
|
156
|
-
|
|
157
|
-
project-gantt:
|
|
158
|
-
provider: mermaid
|
|
159
|
-
diagram_type: gantt
|
|
160
|
-
description: Project timeline Gantt chart
|
|
161
|
-
file: diagram-templates/project-gantt.mmd
|
|
162
|
-
|
|
163
|
-
feature-mindmap:
|
|
164
|
-
provider: mermaid
|
|
165
|
-
diagram_type: mindmap
|
|
166
|
-
description: Feature brainstorming mindmap
|
|
167
|
-
file: diagram-templates/feature-mindmap.mmd
|
|
1
|
+
# Diagram tool configuration
|
|
2
|
+
# Load via: include: [config/diagram.yaml]
|
|
3
|
+
|
|
4
|
+
tools:
|
|
5
|
+
diagram:
|
|
6
|
+
backend:
|
|
7
|
+
type: kroki
|
|
8
|
+
remote_url: https://kroki.io
|
|
9
|
+
self_hosted_url: http://localhost:8000
|
|
10
|
+
prefer: self_hosted # remote | self_hosted | auto
|
|
11
|
+
timeout: 30.0
|
|
12
|
+
|
|
13
|
+
policy:
|
|
14
|
+
rules: |
|
|
15
|
+
NEVER use ASCII art or text-based diagrams in markdown.
|
|
16
|
+
Use the diagram tools for all visual representations.
|
|
17
|
+
Save output as SVG and reference in markdown.
|
|
18
|
+
Always generate source first, then render.
|
|
19
|
+
Choose the provider based on diagram type - see instructions.
|
|
20
|
+
preferred_format: svg
|
|
21
|
+
preferred_providers:
|
|
22
|
+
- mermaid
|
|
23
|
+
- d2
|
|
24
|
+
- plantuml
|
|
25
|
+
|
|
26
|
+
output:
|
|
27
|
+
dir: ../diagrams # Relative to config dir (.onetool/../diagrams)
|
|
28
|
+
naming: "{provider}_{name}_{timestamp}"
|
|
29
|
+
default_format: svg
|
|
30
|
+
save_source: true
|
|
31
|
+
|
|
32
|
+
instructions:
|
|
33
|
+
mermaid:
|
|
34
|
+
when_to_use: |
|
|
35
|
+
- Flowcharts and decision trees
|
|
36
|
+
- Sequence diagrams for API flows
|
|
37
|
+
- Class diagrams for data models
|
|
38
|
+
- State diagrams for workflows
|
|
39
|
+
- Gantt charts for project timelines
|
|
40
|
+
- Mindmaps for brainstorming
|
|
41
|
+
style_tips: |
|
|
42
|
+
Use subgraphs to group related nodes.
|
|
43
|
+
Keep flowcharts top-to-bottom (TD) for readability.
|
|
44
|
+
Limit sequence diagrams to 5-7 participants.
|
|
45
|
+
|
|
46
|
+
QUOTING RULES (critical):
|
|
47
|
+
- Sequence diagrams: NO quotes after 'as' (they appear literally)
|
|
48
|
+
Use: participant WS as Web Server
|
|
49
|
+
NOT: participant WS as "Web Server"
|
|
50
|
+
- Flowcharts/class: USE quotes for labels with spaces
|
|
51
|
+
Use: A["Start Process"], B{"Decision?"}
|
|
52
|
+
- Never put spaces in node/participant IDs
|
|
53
|
+
syntax_guide: https://mermaid.js.org/syntax/
|
|
54
|
+
example: |
|
|
55
|
+
sequenceDiagram
|
|
56
|
+
participant C as Client
|
|
57
|
+
participant S as Server
|
|
58
|
+
C->>S: Request
|
|
59
|
+
S-->>C: Response
|
|
60
|
+
|
|
61
|
+
plantuml:
|
|
62
|
+
when_to_use: |
|
|
63
|
+
- Complex UML diagrams (class, component, deployment)
|
|
64
|
+
- C4 architecture diagrams (use stdlib)
|
|
65
|
+
- Detailed sequence diagrams with notes
|
|
66
|
+
- Diagrams requiring themes and skinparams
|
|
67
|
+
style_tips: |
|
|
68
|
+
Use skinparam for consistent theming.
|
|
69
|
+
Leverage !include for reusable components.
|
|
70
|
+
Use packages to organise large diagrams.
|
|
71
|
+
Add notes for context on complex relationships.
|
|
72
|
+
|
|
73
|
+
QUOTING RULES (critical):
|
|
74
|
+
- Always quote display names BEFORE 'as':
|
|
75
|
+
participant "Web Server" as WS
|
|
76
|
+
- Never put spaces in aliases (the ID after 'as')
|
|
77
|
+
- Use stereotypes for interfaces: <<interface>>
|
|
78
|
+
syntax_guide: https://plantuml.com/
|
|
79
|
+
example: |
|
|
80
|
+
@startuml
|
|
81
|
+
actor User
|
|
82
|
+
participant "API Gateway" as GW
|
|
83
|
+
database DB
|
|
84
|
+
|
|
85
|
+
User -> GW: Login request
|
|
86
|
+
GW -> DB: Check credentials
|
|
87
|
+
DB --> GW: User record
|
|
88
|
+
GW --> User: 200 OK
|
|
89
|
+
@enduml
|
|
90
|
+
|
|
91
|
+
d2:
|
|
92
|
+
when_to_use: |
|
|
93
|
+
- Clean architecture diagrams
|
|
94
|
+
- System context diagrams
|
|
95
|
+
- Hand-drawn style (sketch mode)
|
|
96
|
+
- Layouts with automatic positioning
|
|
97
|
+
- C4-style container diagrams
|
|
98
|
+
style_tips: |
|
|
99
|
+
Use containers for logical grouping.
|
|
100
|
+
D2 auto-layouts well - avoid manual positioning.
|
|
101
|
+
Use markdown in labels for rich formatting.
|
|
102
|
+
Leverage layers for complex diagrams.
|
|
103
|
+
Use shape: person for actors.
|
|
104
|
+
Direction hint: direction: right or direction: down.
|
|
105
|
+
|
|
106
|
+
QUOTING RULES (critical):
|
|
107
|
+
- Always quote labels after colon: node: "Display Name"
|
|
108
|
+
- IDs (before colon) should not have spaces
|
|
109
|
+
- Use style.sketch: true for hand-drawn look
|
|
110
|
+
syntax_guide: https://d2lang.com/tour/intro
|
|
111
|
+
example: |
|
|
112
|
+
direction: right
|
|
113
|
+
|
|
114
|
+
user: "User" {
|
|
115
|
+
shape: person
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
system: "My System" {
|
|
119
|
+
api: "API Server"
|
|
120
|
+
db: "Database"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
user -> system.api: "Uses"
|
|
124
|
+
system.api -> system.db
|
|
125
|
+
|
|
126
|
+
templates:
|
|
127
|
+
api-flow:
|
|
128
|
+
provider: mermaid
|
|
129
|
+
diagram_type: sequence
|
|
130
|
+
description: REST API request/response flow
|
|
131
|
+
file: config/diagram-templates/api-flow.mmd
|
|
132
|
+
|
|
133
|
+
microservices:
|
|
134
|
+
provider: d2
|
|
135
|
+
diagram_type: architecture
|
|
136
|
+
description: Microservices architecture layout
|
|
137
|
+
file: config/diagram-templates/microservices.d2
|
|
138
|
+
|
|
139
|
+
c4-context:
|
|
140
|
+
provider: plantuml
|
|
141
|
+
diagram_type: c4
|
|
142
|
+
description: C4 system context diagram
|
|
143
|
+
file: config/diagram-templates/c4-context.puml
|
|
144
|
+
|
|
145
|
+
state-machine:
|
|
146
|
+
provider: mermaid
|
|
147
|
+
diagram_type: state
|
|
148
|
+
description: State machine diagram
|
|
149
|
+
file: config/diagram-templates/state-machine.mmd
|
|
150
|
+
|
|
151
|
+
class-diagram:
|
|
152
|
+
provider: mermaid
|
|
153
|
+
diagram_type: class
|
|
154
|
+
description: Class/data model diagram
|
|
155
|
+
file: config/diagram-templates/class-diagram.mmd
|
|
156
|
+
|
|
157
|
+
project-gantt:
|
|
158
|
+
provider: mermaid
|
|
159
|
+
diagram_type: gantt
|
|
160
|
+
description: Project timeline Gantt chart
|
|
161
|
+
file: config/diagram-templates/project-gantt.mmd
|
|
162
|
+
|
|
163
|
+
feature-mindmap:
|
|
164
|
+
provider: mermaid
|
|
165
|
+
diagram_type: mindmap
|
|
166
|
+
description: Feature brainstorming mindmap
|
|
167
|
+
file: config/diagram-templates/feature-mindmap.mmd
|
ot_tools/scaffold.py
CHANGED
|
@@ -24,9 +24,9 @@ __all__ = ["create", "extensions", "templates", "validate"]
|
|
|
24
24
|
|
|
25
25
|
def _get_templates_dir() -> Path:
|
|
26
26
|
"""Get the extension templates directory."""
|
|
27
|
-
from ot.paths import
|
|
27
|
+
from ot.paths import get_global_templates_dir
|
|
28
28
|
|
|
29
|
-
return
|
|
29
|
+
return get_global_templates_dir() / "tool_templates"
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def templates() -> str:
|
ot_tools/transform.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""Transform - LLM-powered data transformation.
|
|
2
2
|
|
|
3
|
-
Takes
|
|
3
|
+
Takes data and a prompt, uses an LLM to transform/process it.
|
|
4
4
|
|
|
5
5
|
Example:
|
|
6
6
|
llm.transform(
|
|
7
|
-
brave.search(query="metal prices", count=10),
|
|
7
|
+
data=brave.search(query="metal prices", count=10),
|
|
8
8
|
prompt="Extract prices as YAML with fields: metal, price, unit, url",
|
|
9
9
|
)
|
|
10
10
|
|
|
@@ -23,7 +23,7 @@ from __future__ import annotations
|
|
|
23
23
|
# Pack for dot notation: llm.transform()
|
|
24
24
|
pack = "llm"
|
|
25
25
|
|
|
26
|
-
__all__ = ["transform"]
|
|
26
|
+
__all__ = ["transform", "transform_file"]
|
|
27
27
|
|
|
28
28
|
# Dependency declarations for CLI validation
|
|
29
29
|
__ot_requires__ = {
|
|
@@ -38,6 +38,7 @@ from pydantic import BaseModel, Field
|
|
|
38
38
|
|
|
39
39
|
from ot.config import get_secret, get_tool_config
|
|
40
40
|
from ot.logging import LogSpan
|
|
41
|
+
from ot.paths import resolve_cwd_path
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
class Config(BaseModel):
|
|
@@ -82,19 +83,19 @@ def _get_api_config() -> tuple[str | None, str | None, str | None, Config]:
|
|
|
82
83
|
|
|
83
84
|
def transform(
|
|
84
85
|
*,
|
|
85
|
-
|
|
86
|
+
data: Any,
|
|
86
87
|
prompt: str,
|
|
87
88
|
model: str | None = None,
|
|
88
89
|
json_mode: bool = False,
|
|
89
90
|
) -> str:
|
|
90
|
-
"""Transform
|
|
91
|
+
"""Transform data using an LLM.
|
|
91
92
|
|
|
92
|
-
Takes any
|
|
93
|
+
Takes any data (typically a string result from another tool call)
|
|
93
94
|
and processes it according to the prompt instructions.
|
|
94
95
|
|
|
95
96
|
Args:
|
|
96
|
-
|
|
97
|
-
prompt: Instructions for how to transform/process the
|
|
97
|
+
data: Data to transform (will be converted to string if not already)
|
|
98
|
+
prompt: Instructions for how to transform/process the data
|
|
98
99
|
model: AI model to use (uses transform.model from config if not specified)
|
|
99
100
|
json_mode: If True, request JSON output format from the model
|
|
100
101
|
|
|
@@ -104,25 +105,25 @@ def transform(
|
|
|
104
105
|
Examples:
|
|
105
106
|
# Extract structured data from search results
|
|
106
107
|
llm.transform(
|
|
107
|
-
|
|
108
|
+
data=brave.search(query="gold price today", count=5),
|
|
108
109
|
prompt="Extract the current gold price in USD/oz as a single number",
|
|
109
110
|
)
|
|
110
111
|
|
|
111
112
|
# Convert to YAML format
|
|
112
113
|
llm.transform(
|
|
113
|
-
|
|
114
|
+
data=brave.search(query="metal prices", count=10),
|
|
114
115
|
prompt="Return ONLY valid YAML with fields: metal, price, unit, url",
|
|
115
116
|
)
|
|
116
117
|
|
|
117
118
|
# Summarize content
|
|
118
119
|
llm.transform(
|
|
119
|
-
|
|
120
|
+
data=some_long_text,
|
|
120
121
|
prompt="Summarize this in 3 bullet points"
|
|
121
122
|
)
|
|
122
123
|
|
|
123
124
|
# Get JSON output
|
|
124
125
|
llm.transform(
|
|
125
|
-
|
|
126
|
+
data=my_data,
|
|
126
127
|
prompt="Extract name and email as JSON",
|
|
127
128
|
json_mode=True
|
|
128
129
|
)
|
|
@@ -133,12 +134,12 @@ def transform(
|
|
|
133
134
|
s.add(error="empty_prompt")
|
|
134
135
|
return "Error: prompt is required and cannot be empty"
|
|
135
136
|
|
|
136
|
-
|
|
137
|
-
if not
|
|
138
|
-
s.add(error="
|
|
139
|
-
return "Error:
|
|
137
|
+
data_str = str(data)
|
|
138
|
+
if not data_str.strip():
|
|
139
|
+
s.add(error="empty_data")
|
|
140
|
+
return "Error: data is required and cannot be empty"
|
|
140
141
|
|
|
141
|
-
s.add(
|
|
142
|
+
s.add(dataLen=len(data_str))
|
|
142
143
|
|
|
143
144
|
# Get API config
|
|
144
145
|
api_key, base_url, default_model, config = _get_api_config()
|
|
@@ -158,8 +159,8 @@ def transform(
|
|
|
158
159
|
client = OpenAI(api_key=api_key, base_url=base_url, timeout=config.timeout)
|
|
159
160
|
|
|
160
161
|
# Build the message
|
|
161
|
-
user_message = f"""
|
|
162
|
-
{
|
|
162
|
+
user_message = f"""Data:
|
|
163
|
+
{data_str}
|
|
163
164
|
|
|
164
165
|
Instructions:
|
|
165
166
|
{prompt}"""
|
|
@@ -211,3 +212,107 @@ Instructions:
|
|
|
211
212
|
error_msg = "Authentication error - check OPENAI_API_KEY in secrets.yaml"
|
|
212
213
|
s.add(error=error_msg)
|
|
213
214
|
return f"Error: {error_msg}"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def transform_file(
|
|
218
|
+
*,
|
|
219
|
+
prompt: str,
|
|
220
|
+
in_file: str,
|
|
221
|
+
out_file: str,
|
|
222
|
+
model: str | None = None,
|
|
223
|
+
json_mode: bool = False,
|
|
224
|
+
) -> str:
|
|
225
|
+
"""Transform a file's content using an LLM and write to output file.
|
|
226
|
+
|
|
227
|
+
Reads the input file, transforms its content according to the prompt,
|
|
228
|
+
and writes the result to the output file.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
prompt: Instructions for how to transform/process the content
|
|
232
|
+
in_file: Path to input file (relative to cwd or absolute)
|
|
233
|
+
out_file: Path to output file (relative to cwd or absolute)
|
|
234
|
+
model: AI model to use (uses transform.model from config if not specified)
|
|
235
|
+
json_mode: If True, request JSON output format from the model
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Success message with bytes written, or error message
|
|
239
|
+
|
|
240
|
+
Examples:
|
|
241
|
+
# Convert markdown to restructured text
|
|
242
|
+
llm.transform_file(
|
|
243
|
+
prompt="Convert this markdown to reStructuredText format",
|
|
244
|
+
in_file="README.md",
|
|
245
|
+
out_file="README.rst",
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Extract data as JSON
|
|
249
|
+
llm.transform_file(
|
|
250
|
+
prompt="Extract all URLs and their descriptions as JSON",
|
|
251
|
+
in_file="links.txt",
|
|
252
|
+
out_file="links.json",
|
|
253
|
+
json_mode=True,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Translate content
|
|
257
|
+
llm.transform_file(
|
|
258
|
+
prompt="Translate this to Spanish",
|
|
259
|
+
in_file="greeting.txt",
|
|
260
|
+
out_file="greeting_es.txt",
|
|
261
|
+
)
|
|
262
|
+
"""
|
|
263
|
+
with LogSpan(
|
|
264
|
+
span="llm.transform_file", promptLen=len(prompt), inFile=in_file, outFile=out_file
|
|
265
|
+
) as s:
|
|
266
|
+
# Validate prompt
|
|
267
|
+
if not prompt or not prompt.strip():
|
|
268
|
+
s.add(error="empty_prompt")
|
|
269
|
+
return "Error: prompt is required and cannot be empty"
|
|
270
|
+
|
|
271
|
+
# Resolve and read input file
|
|
272
|
+
try:
|
|
273
|
+
in_path = resolve_cwd_path(in_file)
|
|
274
|
+
if not in_path.exists():
|
|
275
|
+
s.add(error="in_file_not_found")
|
|
276
|
+
return f"Error: Input file not found: {in_file}"
|
|
277
|
+
if not in_path.is_file():
|
|
278
|
+
s.add(error="in_file_not_file")
|
|
279
|
+
return f"Error: Input path is not a file: {in_file}"
|
|
280
|
+
in_content = in_path.read_text(encoding="utf-8")
|
|
281
|
+
except UnicodeDecodeError as e:
|
|
282
|
+
s.add(error="in_file_decode_error")
|
|
283
|
+
return f"Error: Could not decode input file as UTF-8: {e}"
|
|
284
|
+
except OSError as e:
|
|
285
|
+
s.add(error=f"in_file_read_error: {e}")
|
|
286
|
+
return f"Error: Could not read input file: {e}"
|
|
287
|
+
|
|
288
|
+
if not in_content.strip():
|
|
289
|
+
s.add(error="empty_in_file")
|
|
290
|
+
return "Error: Input file is empty"
|
|
291
|
+
|
|
292
|
+
s.add(inLen=len(in_content))
|
|
293
|
+
|
|
294
|
+
# Transform the content
|
|
295
|
+
result = transform(
|
|
296
|
+
data=in_content,
|
|
297
|
+
prompt=prompt,
|
|
298
|
+
model=model,
|
|
299
|
+
json_mode=json_mode,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Check if transform returned an error
|
|
303
|
+
if result.startswith("Error:"):
|
|
304
|
+
s.add(error="transform_failed")
|
|
305
|
+
return result
|
|
306
|
+
|
|
307
|
+
# Resolve and write output file
|
|
308
|
+
try:
|
|
309
|
+
out_path = resolve_cwd_path(out_file)
|
|
310
|
+
# Create parent directories if needed
|
|
311
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
312
|
+
out_path.write_text(result, encoding="utf-8")
|
|
313
|
+
bytes_written = len(result.encode("utf-8"))
|
|
314
|
+
s.add(outLen=bytes_written)
|
|
315
|
+
return f"OK: Transformed {in_file} -> {out_file} ({bytes_written} bytes)"
|
|
316
|
+
except OSError as e:
|
|
317
|
+
s.add(error=f"out_file_write_error: {e}")
|
|
318
|
+
return f"Error: Could not write output file: {e}"
|