cpee-llm 1.0.6 → 1.1.0

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -0
  3. data/cpee-llm.gemspec +1 -1
  4. data/lib/cpee/llm/functions.rb +76 -73
  5. data/lib/cpee/llm/implementation.rb +39 -13
  6. data/lib/cpee/llm/implementation.xml +34 -1
  7. data/lib/cpee/llm/prompts/system/adapt_docxml_description.txt +50 -0
  8. data/lib/cpee/llm/prompts/{adapt_xml_endpoints.txt → system/adapt_xml_endpoints.txt} +1 -76
  9. data/lib/cpee/llm/prompts/system/cpee_xml.txt +99 -0
  10. data/lib/cpee/llm/prompts/system/cpee_xml_documentation_modelling.txt +35 -0
  11. data/lib/cpee/llm/prompts/system/intent.txt +45 -0
  12. data/lib/cpee/llm/prompts/user/cpee_repair.txt +5 -0
  13. data/lib/cpee/llm/prompts/user/dataflow.txt +9 -0
  14. data/lib/cpee/llm/prompts/user/intent.txt +17 -0
  15. data/lib/cpee/llm/prompts/user/process_description.txt +5 -0
  16. data/lib/cpee/llm/prompts/user/process_description_endpoints.txt +9 -0
  17. data/lib/cpee/llm/prompts/user/process_model_adapt.txt +8 -0
  18. data/lib/cpee/llm/prompts/user/process_model_adapt_api.txt +11 -0
  19. data/lib/cpee/llm/prompts/user/process_model_text.txt +4 -0
  20. data/lib/cpee/llm/prompts/user/repair.txt +5 -0
  21. data/lib/cpee/llm/rubyllm_requests.rb +64 -116
  22. data/server/connect_gemini +1 -1
  23. data/server/connect_gpt +1 -1
  24. data/server/connect_morpheus +1 -1
  25. data/server/cpee-llm +1 -1
  26. data/server/plugins.json +51 -0
  27. data/tools/cpee-llm-tool +1 -1
  28. metadata +27 -14
  29. data/lib/cpee/llm/prompts/adapt_docxml_description.txt +0 -131
  30. /data/lib/cpee/llm/prompts/{apply.txt → system/apply.txt} +0 -0
  31. /data/lib/cpee/llm/prompts/{dataflow.txt → system/dataflow.txt} +0 -0
  32. /data/lib/cpee/llm/prompts/{derive.txt → system/derive.txt} +0 -0
  33. /data/lib/cpee/llm/prompts/{describe.txt → system/describe.txt} +0 -0
  34. /data/lib/cpee/llm/prompts/{gemini-request.json → system/gemini-request.json} +0 -0
  35. /data/lib/cpee/llm/prompts/{generate1.txt → system/generate1.txt} +0 -0
  36. /data/lib/cpee/llm/prompts/{generate_enpoints.txt → system/generate_enpoints.txt} +0 -0
  37. /data/lib/cpee/llm/prompts/{generate_enpoints1.txt → system/generate_enpoints1.txt} +0 -0
  38. /data/lib/cpee/llm/prompts/{identify.txt → system/identify.txt} +0 -0
  39. /data/lib/cpee/llm/prompts/{validate_mermaid.xml → system/validate_mermaid.xml} +0 -0
  40. /data/lib/cpee/llm/prompts/{validate_xml.txt → system/validate_xml.txt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca5babd5dc06dda1ca60b1143f4e1ee041f294c3e07c05bb833f92b4c922141d
4
- data.tar.gz: a9301f53687d861859ab0bab28603334e7b4a26c08915e1bdbf5a027b12c9dda
3
+ metadata.gz: 173032c1cbbc6ff2fa8ecb64b3ad47dc3c8998e9f978cb3ba137228948c1ad93
4
+ data.tar.gz: '090933e62d1ceb692f42762c6c7c2efa06f4c842032e2d38ac202cbd77eb7150'
5
5
  SHA512:
6
- metadata.gz: 4ba74739c3478243731b13ffd4e9029518cffb1fe11b9bb35a45099fe9289e4810c72ea064a324baa3e1d6efcb53e0355de0db9d87b6706169a52eddbeac2bc3
7
- data.tar.gz: 5bf927f26210ac7b2efff4a9e9448bac8ebfe3d41fe5621b7513d4775677ced97525befc10da07ed318cd1d483d627da12553fa05801539fcf43fee480a5804b
6
+ metadata.gz: ff11667abbf905c538f416b28642c6d91edab16f1e4c77e2344f31f9770e240c52c900d8a7f9bf29af57df40a3f3946aae33b1cc3e548edf093921a175cd0c69
7
+ data.tar.gz: cfeeacc7885181012472be6be35677ea66521bc10e6141812b212a1e2390a01bcd9f10e86d752de8f83b0e2972dc5896be50d9e936d50df2aa4dd1e27ab68cc6
data/README.md CHANGED
@@ -152,6 +152,7 @@ Performs arbitrary LLM tasks using a system prompt and user input.
152
152
  | system_prompt | text/plain |
153
153
  | format | text/plain (`true`/`false`) |
154
154
  | temperature | text/plain (optional) |
155
+ | documents | `*/*` (optional, repeatable) |
155
156
 
156
157
  ## Response
157
158
 
@@ -168,6 +169,7 @@ Performs arbitrary LLM tasks using a system prompt and user input.
168
169
  ### Notes
169
170
 
170
171
  - `format=true` requests JSON output (guarantees valid JSON but not any specific structure).
172
+ - `documents` can be repeated to attach one or more files (e.g. images, PDFs, office documents, plain text) to the request, sent as multipart file parts. Attachments are passed through to the LLM alongside `user_input`; support depends on the selected model/provider.
171
173
 
172
174
  List of supporteb providers: https://rubyllm.com/chat/#getting-structured-output
173
175
 
@@ -182,4 +184,17 @@ curl -X POST https://cpee.org/llm/generic/ \
182
184
  -F "format=false;type=text/plain"
183
185
  ```
184
186
 
187
+ With attached documents:
188
+
189
+ ```bash
190
+ curl -X POST https://cpee.org/llm/generic/ \
191
+ -H 'Content-Type:multipart/form-data' \
192
+ -F "llm=gemini-2.5-flash-lite;type=text/plain" \
193
+ -F "user_input=Summarize the attached document.;type=text/plain" \
194
+ -F "system_prompt=Return the summary as bullet points.;type=text/plain" \
195
+ -F "format=false;type=text/plain" \
196
+ -F "documents=@report.pdf;type=application/pdf" \
197
+ -F "documents=@chart.png;type=image/png"
198
+ ```
199
+
185
200
  ---
data/cpee-llm.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "cpee-llm"
3
- s.version = "1.0.6"
3
+ s.version = "1.1.0"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.license = "LGPL-3.0-or-later"
6
6
  s.summary = "CPEE Conversational Agents"
@@ -45,15 +45,9 @@ module CPEE
45
45
  trans.generate_model(CPEE::Transformation::Target::CPEE)
46
46
  end #}}}
47
47
 
48
- def generate_model(myllm,user_input,temperature,llms) #{{{
48
+ def error_handler #{{{
49
49
  begin
50
- llm_response = generate_mermaid_model(myllm,user_input,temperature,llms)
51
- # raise exceptions if response is empty for some reason
52
- if llm_response.nil? || llm_response.empty?
53
- raise LLMError.new("Something went wrong and your content was not generated!", 500)
54
- else
55
- return llm_response
56
- end
50
+ yield
57
51
  rescue LLMError => e_llm
58
52
  e_llm.message
59
53
  raise e_llm
@@ -63,28 +57,42 @@ module CPEE
63
57
  end
64
58
  end #}}}
65
59
 
60
+ def generate_model(myllm,user_input,temperature,llms) #{{{
61
+ error_handler do
62
+ system_prompt = build_system_prompt("generate1.txt")
63
+ user_prompt = build_user_prompt("process_description.txt", user_input:)
64
+ llm_response = generate_content(myllm,system_prompt,user_prompt,4000,temperature,llms)
65
+ # raise exceptions if response is empty for some reason
66
+ if llm_response.nil? || llm_response.empty?
67
+ raise LLMError.new("Something went wrong and your content was not generated!", 500)
68
+ else
69
+ return llm_response
70
+ end
71
+ end
72
+ end #}}}
73
+
66
74
  def adapt_model(myllm,doc,user_input,llms) #{{{
67
75
  input_cpee = doc.to_s()
68
76
  input_mermaid = cpee_to_mermaid(doc.to_s())
69
- begin
70
- llm_response = adapt_mermaid_model(myllm,user_input,input_mermaid,llms)
77
+ error_handler do
78
+ system_prompt = build_system_prompt("apply.txt")
79
+ user_prompt = build_user_prompt("process_model_adapt.txt", user_input:, process_model: input_mermaid)
80
+ llm_response = generate_content(myllm,system_prompt,user_prompt,4000,0,llms)
71
81
  # raise exceptions if response is empty for some reason
72
82
  if llm_response.nil? || llm_response.empty?
73
83
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
74
84
  else
75
85
  return llm_response
76
86
  end
77
- rescue LLMError => e_llm
78
- raise e_llm
79
- rescue Exception => e
80
- raise e
81
87
  end
82
88
  end #}}}
83
89
 
84
90
  def adapt_doccpee_description(myllm,doc,user_input,llms) #{{{
85
91
  input_cpee = doc.to_s()
86
- begin
87
- llm_response = adapt_docxml_description(myllm,user_input,input_cpee,llms)
92
+ error_handler do
93
+ system_prompt = build_system_prompt("adapt_docxml_description.txt")
94
+ user_prompt = build_user_prompt("process_model_adapt.txt", user_input:, process_model: input_cpee)
95
+ llm_response = generate_content(myllm,system_prompt,user_prompt,16000,0,llms)
88
96
  # raise exceptions if response is empty for some reason
89
97
  if llm_response.nil? || llm_response.empty?
90
98
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
@@ -100,27 +108,20 @@ module CPEE
100
108
  end
101
109
  return llm_response
102
110
  end
103
- rescue LLMError => e_llm
104
- raise e_llm
105
- rescue Exception => e
106
- raise e
107
111
  end
108
112
  end #}}}
109
113
 
110
114
  def adapt_cpee_model(myllm,doc,user_input,existing_endpoints,endpoints,llms) #{{{
111
- testset = XML::Smart.string(<<~XML)
112
- <testset xmlns="http://cpee.org/ns/properties/2.0">
113
- </testset>
114
- XML
115
+ testset = XML::Smart.string('<testset xmlns="http://cpee.org/ns/properties/2.0"></testset>')
115
116
  root = testset.root
116
117
  root.add(existing_endpoints.root)
117
118
  dslx = root.add("dslx")
118
119
  dslx.add(doc.root)
119
120
 
120
- #puts testset.to_s
121
-
122
- begin
123
- llm_response = adapt_xml_model(myllm,user_input,testset,endpoints,llms)
121
+ error_handler do
122
+ system_prompt = build_system_prompt("adapt_xml_endpoints.txt")
123
+ user_prompt = build_user_prompt("process_model_adapt_api.txt", user_input:, process_model: testset, api_specification: endpoints)
124
+ llm_response = generate_content(myllm,system_prompt,user_prompt,15000,0,llms)
124
125
  # raise exceptions if response is empty for some reason
125
126
  if llm_response.nil? || llm_response.empty?
126
127
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
@@ -136,54 +137,42 @@ module CPEE
136
137
  end
137
138
  return llm_response
138
139
  end
139
- rescue LLMError => e_llm
140
- raise e_llm
141
- rescue Exception => e
142
- raise e
143
140
  end
144
141
  end #}}}
145
142
 
146
143
  def generate_text(myllm,doc,llms) #{{{
147
144
  input_cpee = doc.to_s()
148
145
  input_mermaid = cpee_to_mermaid(doc.to_s())
149
- begin
150
- llm_response = generate_plain_text(myllm,input_mermaid,llms)
146
+ error_handler do
147
+ system_prompt = build_system_prompt("describe.txt")
148
+ user_prompt = build_user_prompt("process_model_text.txt", user_input: input_mermaid)
149
+ llm_response = generate_content(myllm,system_prompt,user_prompt,4000,0,llms)
151
150
  # raise exceptions if response is empty for some reason
152
151
  if llm_response.nil? || llm_response.empty?
153
152
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
154
153
  else
155
154
  return llm_response
156
155
  end
157
- rescue LLMError => e_llm
158
- e_llm.message
159
- raise e_llm
160
- rescue Exception => e
161
- e.message
162
- raise e
163
156
  end
164
157
  end #}}}
165
158
 
166
- def generate_generic(myllm,user_input,system_prompt,format,temperature,llms) #{{{
167
- begin
168
- llm_response = generate_generic_content(myllm, user_input, system_prompt, format, temperature, llms)
159
+ def generate_generic(myllm,user_input,system_prompt,format,temperature,documents,llms) #{{{
160
+ error_handler do
161
+ llm_response = generate_content(myllm, system_prompt, user_input, 16000, temperature, llms, format == 'true' ? { json: true } : {}, documents)
169
162
  # raise exceptions if response is empty for some reason
170
163
  if llm_response.nil? || llm_response.empty?
171
164
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
172
165
  else
173
166
  return llm_response
174
167
  end
175
- rescue LLMError => e_llm
176
- e_llm.message
177
- raise e_llm
178
- rescue Exception => e
179
- e.message
180
- raise e
181
168
  end
182
169
  end #}}}
183
170
 
184
171
  def generate_dataflow(myllm,mermaid_model,api_specification,llms) #{{{
185
- begin
186
- llm_response = generate_dataflow_content(myllm, mermaid_model, api_specification, llms)
172
+ error_handler do
173
+ system_prompt = build_system_prompt("dataflow.txt")
174
+ user_prompt = build_user_prompt("dataflow.txt", mermaid_model:, api_specification:)
175
+ llm_response = generate_content(myllm, system_prompt, user_prompt, 4000, 0.1, llms)
187
176
  # raise exceptions if response is empty for some reason
188
177
  if llm_response.nil? || llm_response.empty?
189
178
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
@@ -201,36 +190,28 @@ module CPEE
201
190
  end
202
191
  return llm_response
203
192
  end
204
- rescue LLMError => e_llm
205
- e_llm.message
206
- raise e_llm
207
- rescue Exception => e
208
- e.message
209
- raise e
210
193
  end
211
194
  end #}}}
212
195
 
213
196
  def generate_endpoint_model(myllm,user_input,endpoints,llms) #{{{
214
- begin
215
- llm_response = generate_endpoint_mermaid_model(myllm,user_input,endpoints,llms)
197
+ error_handler do
198
+ system_prompt = build_system_prompt("generate_enpoints.txt")
199
+ user_prompt = build_user_prompt("process_description_endpoints.txt", user_input:, endpoints:)
200
+ llm_response = generate_content(myllm,system_prompt,user_prompt,4000,0.1,llms)
216
201
  # raise exceptions if response is empty for some reason
217
202
  if llm_response.nil? || llm_response.empty?
218
203
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
219
204
  else
220
205
  return llm_response
221
206
  end
222
- rescue LLMError => e_llm
223
- e_llm.message
224
- raise e_llm
225
- rescue Exception => e
226
- e.message
227
- raise e
228
207
  end
229
208
  end #}}}
230
209
 
231
210
  def validate_cpee_model(myllm,cpee_model,llms) #{{{
232
- begin
233
- llm_response = validate_xml_model(myllm,cpee_model,llms)
211
+ error_handler do
212
+ system_prompt = build_system_prompt("validate_xml.txt")
213
+ user_prompt = build_user_prompt("cpee_repair.txt", cpee_model:)
214
+ llm_response = generate_content(myllm,system_prompt,user_prompt,0,0.1,llms)
234
215
  if llm_response.nil? || llm_response.empty?
235
216
  raise LLMError.new("Something went wrong and your content was not generated!", 500)
236
217
  elsif llm_response.strip.downcase == "perfect"
@@ -247,12 +228,34 @@ module CPEE
247
228
  end
248
229
  return llm_response
249
230
  end
250
- rescue LLMError => e_llm
251
- e_llm.message
252
- raise e_llm
253
- rescue Exception => e
254
- e.message
255
- raise e
231
+ end
232
+ end #}}}
233
+
234
+ def guess_intent(myllm,user_input,plugins,llms) #{{{
235
+ plugs = File.read(plugins)
236
+ error_handler do
237
+ system_prompt = build_system_prompt("intent.txt")
238
+ user_prompt = build_user_prompt("intent.txt", user_input:, plugins: plugs)
239
+ response = generate_content(myllm,system_prompt,user_prompt,4000,0.1,llms,{ json: true })
240
+ if response.nil? || response.empty?
241
+ raise LLMError.new("Something went wrong and your content was not generated!", 500)
242
+ else
243
+ result = JSON::parse(response)
244
+ if result.is_a?(Hash) && result["id"]
245
+ plugin_list = JSON::parse(plugs)
246
+ plugin = plugin_list.find { |p| p["id"] == result["id"] }
247
+ if plugin
248
+ plugin.each do |k,v|
249
+ result[k] = v unless k == "description"
250
+ end
251
+ result
252
+ else
253
+ nil
254
+ end
255
+ else
256
+ result
257
+ end
258
+ end
256
259
  end
257
260
  end #}}}
258
261
 
@@ -41,7 +41,6 @@ module CPEE
41
41
  temperature = @p.shift.value.read if @p[0]&.name == 'temperature'
42
42
 
43
43
  doc = XML::Smart.string(input_cpee)
44
- pp prompt_type
45
44
  begin
46
45
  output_cpee = if prompt_type == 'generate_noendpoints' || prompt_type == 'generate_noendpoints_docdescription'
47
46
  llm_response = generate_model(myllm,user_input,temperature,llms)
@@ -64,7 +63,7 @@ module CPEE
64
63
  return Riddl::Parameter::Complex.new('llm_out', 'application/json', { error: e }.to_json)
65
64
  end
66
65
 
67
- return(Riddl::Parameter::Complex.new("llm_out","application/json",{:user_input => user_input, :used_llm => myllm, :input_cpee => input_cpee, :input_intermediate => doc.root().empty?() ? "" : cpee_to_mermaid(doc.to_s()), :output_intermediate => llm_response, :output_cpee => output_cpee, :status => "Success"}.to_json()))
66
+ return Riddl::Parameter::Complex.new("llm_out","application/json",{:user_input => user_input, :used_llm => myllm, :input_cpee => input_cpee, :input_intermediate => doc.root().empty?() ? "" : cpee_to_mermaid(doc.to_s()), :output_intermediate => llm_response, :output_cpee => output_cpee, :status => "Success"}.to_json())
68
67
  rescue LLMError => e
69
68
  @status = e&.http_response || 400
70
69
  return Riddl::Parameter::Complex.new("llm_out","application/json",{ :error => "#{prompt_type} #{e.message}"}.to_json())
@@ -115,18 +114,20 @@ module CPEE
115
114
  llms = @a[0]
116
115
  #get parameters
117
116
  begin
118
- myllm = @p[0].value.read
119
- user_input = @p[1].value.read
120
- system_prompt = @p[2].value.read
121
- format = @p[3].value.read
122
- temperature = @p[4]&.value&.read
117
+ myllm = @p.shift.value.read
118
+ user_input = @p.shift.value.read
119
+ system_prompt = @p.shift.value.read
120
+ format = @p.shift.value.read
121
+ temperature = @p.shift.value.read if @p[0]&.name == 'temperature'
122
+ documents = []
123
+ documents << @p.shift while @p[0]&.name == 'document'
123
124
  rescue Exception => e
124
125
  @status = 400
125
126
  return Riddl::Parameter::Complex.new("generic_out","application/json",{:error => e}.to_json())
126
127
  end
127
128
 
128
129
  begin
129
- llm_response = generate_generic(myllm,user_input,system_prompt,format,temperature,llms)
130
+ llm_response = generate_generic(myllm,user_input,system_prompt,format,temperature,documents,llms)
130
131
  rescue LLMError => e
131
132
  @status = e.http_response
132
133
  return Riddl::Parameter::Complex.new("generic_out","application/json",{:error => e.message}.to_json())
@@ -205,29 +206,54 @@ module CPEE
205
206
  end
206
207
  end #}}}
207
208
 
209
+ class GuessIntent < Riddl::Implementation #{{{
210
+ include Functions
211
+
212
+ def response
213
+ llms = @a[0]
214
+ plugins = @a[1]
215
+
216
+ input_cpee = @p[0].value.read
217
+ myllm = @p[1].value.read
218
+
219
+ begin
220
+ response = guess_intent(myllm,input_cpee,plugins,llms)
221
+ rescue LLMError => e
222
+ @status = e.http_response
223
+ return Riddl::Parameter::Complex.new("user_intent","application/json",{:error => e.message}.to_json())
224
+ end
225
+
226
+ Riddl::Parameter::Complex.new("user_intent","application/json",response.to_json())
227
+ end
228
+ end #}}}
229
+
208
230
  def self::implementation(opts)
209
231
  Proc.new do
210
232
  on resource do
211
- run(CreateMermaid, opts[:llms]) if post 'llm_in'
233
+ run CreateMermaid, opts[:llms] if post 'llm_in'
212
234
 
213
235
  on resource 'dataflow' do
214
- run(CreateDataFlow, opts[:llms]) if post 'dataflow_in'
236
+ run CreateDataFlow, opts[:llms] if post 'dataflow_in'
215
237
  end
216
238
 
217
239
  on resource 'validate' do
218
240
  on resource 'xml' do
219
- run(ValidateDataFlow, opts[:llms]) if post 'dataflow_in'
241
+ run ValidateDataFlow, opts[:llms] if post 'dataflow_in'
220
242
  end
221
243
  end
222
244
 
223
245
  on resource 'text' do
224
246
  on resource 'llm' do
225
- run(CreateText, opts[:llms]) if post 'text_in'
247
+ run CreateText, opts[:llms] if post 'text_in'
226
248
  end
227
249
  end
228
250
 
251
+ on resource 'intent' do
252
+ run GuessIntent, opts[:llms], opts[:plugins] if post 'intent_in'
253
+ end
254
+
229
255
  on resource 'generic' do
230
- run(CreateGeneric, opts[:llms]) if post 'generic_in'
256
+ run CreateGeneric, opts[:llms] if post 'generic_in'
231
257
  end
232
258
  end
233
259
  end
@@ -35,9 +35,35 @@
35
35
  <parameter name="rpst_xml" mimetype="application/json"/>
36
36
  </message>
37
37
 
38
+ <message name="intent_in">
39
+ <parameter name="user_input" mimetype="text/plain"/>
40
+ <parameter name="llm" mimetype="text/plain"/>
41
+ </message>
42
+
43
+ <message name="intent_out">
44
+ <parameter name="user_intent" mimetype="application/json"/>
45
+ <!--
46
+ prompt/user/intent.txt
47
+ prompt/system/intent.txt
48
+
49
+ output: json
50
+ {
51
+ url: // url to call
52
+ required_input: {
53
+ text: // typically extracted from user_input
54
+ documents: { name: value, }, // documents to pass
55
+ model: true|false,
56
+ message_id: '' // input is then the message
57
+ }
58
+ output_template: ... // the output text when calling url is written into this template where the %%% is. If the output of calling url is a json, insert multiple %%%name.
59
+ output: 'chat|process|reintent' // write to chat, give to the normal pipeline, or pass the output to the intention service again
60
+ }
61
+ -->
62
+ </message>
63
+
38
64
  <message name="text_in">
39
65
  <parameter name="rpst_xml" mimetype="*/xml"/>
40
- <parameter name="llm" type="string"/>
66
+ <parameter name="llm" mimetype="text/plain"/>
41
67
  </message>
42
68
  <message name="text_out">
43
69
  <parameter name="output_text" mimetype="application/json"/>
@@ -51,6 +77,9 @@
51
77
  <optional>
52
78
  <parameter name="temperature" mimetype="text/plain"/>
53
79
  </optional>
80
+ <zeroOrMore>
81
+ <parameter name="document" mimetype="*"/>
82
+ </zeroOrMore>
54
83
  </message>
55
84
  <message name="generic_out">
56
85
  <parameter name="output_text" mimetype="application/json"/>
@@ -68,6 +97,10 @@
68
97
  <post in="dataflow_in" out="llm_out"/>
69
98
  </resource>
70
99
 
100
+ <resource relative="intent">
101
+ <post in="intent_in" out="intent_out"/>
102
+ </resource>
103
+
71
104
  <resource relative="text">
72
105
  <resource relative="llm">
73
106
  <post in="text_in" out="text_out"/>
@@ -0,0 +1,50 @@
1
+ You are an expert BPMN 2.0 process model editor for the CPEE XML process description language.
2
+ Your task is to modify an existing CPEE XML process model according to the user's natural-language modification request.
3
+ The user will always provide:
4
+ * an existing valid CPEE XML process model;
5
+ * one or more textual modification requests;
6
+
7
+ Core Objective
8
+ Your task is to produce a modified CPEE XML process model that implements the requested changes.
9
+ Only modify the parts of the process that are explicitly or necessarily affected by the user's request.
10
+ Do not redesign, simplify, optimize, refactor, or rewrite unrelated parts of the model.
11
+ Never remove existing functionality unless explicitly requested.
12
+ Never introduce additional behavior that was not requested.
13
+
14
+ Editing Workflow
15
+ Internally perform the following steps:
16
+ 1. Parse the existing CPEE XML description.
17
+ 3. Parse the workflow contained in the description element.
18
+ 4. Understand the user's requested modifications.
19
+ 5. Determine which workflow elements are affected.
20
+ 6. Apply only the requested changes.
21
+ 7. Update documentation flow if necessary.
22
+ 8. Generate the complete updated CPEE XML description.
23
+
24
+ %%%cpee_xml.txt
25
+ %%%cpee_xml_documentation_modelling.txt
26
+
27
+ For the purpose of modelling, arguments can be ignored and dont have to cary anny values. Code also can be left empty.
28
+
29
+ # Handling Ambiguity
30
+ If the user's request is sufficiently precise, perform the modification directly.
31
+ If multiple valid interpretations exist and the missing information affects the resulting workflow, select the best possible interpretation and perform changes.
32
+
33
+ # Important
34
+ If user deletes a single task in a branch, remove task but leave the branch. Use default branch.
35
+ eid attributes are IDs. All eid attributes have to be unique for the whole XML and start with an e followed by a number, e.g., "e1".
36
+ id attributes are IDs. All id attributes have to be unique for the whole XML and start with an a followed by a number, e.g., "a1".
37
+ Don't change ANY existing id's or eid's. Only genereate new unique id's or eid's for new nodes which have id's or eid's.
38
+ Don't change existing nodes, even when you move them. For example dont add documentation if it is not there.
39
+
40
+ # Output Requirements
41
+ Return the complete updated CPEE XML process model.
42
+ Preserve the overall document structure.
43
+ Modify only the elements affected by the user's request.
44
+ Return the entire XML document, including unchanged sections.
45
+ Do not explain the modifications.
46
+ Do not summarize the changes.
47
+ Do not output Markdown.
48
+ Do not omit unchanged sections.
49
+ The returned XML must be immediately usable as a valid CPEE process model.
50
+
@@ -64,81 +64,7 @@ If the task does not exist in the Service Registry:
64
64
  - Leave the task unconfigured except for information explicitly requested by the user.
65
65
  Always use the Service Registry whenever a matching service specification is available.
66
66
 
67
- # CPEE XML Process Model Structure
68
- The process model itself is contained entirely inside the <description> element. Interpret the XML inside <description> using the following mapping.
69
- ## Sequential Flow
70
- Sequential execution is represented by sibling XML elements appearing in order inside the same parent element.
71
-
72
- ## Service Task
73
- A BPMN Service Task is represented by a `<call>` element.
74
- The endpoint of the service is stored in the **endpoint attribute**.
75
- <call endpoint="measurelightingconditions">
76
- The following child elements may appear inside `<call>`:
77
- ├── parameters
78
- │ ├── label
79
- │ ├── method
80
- │ └── arguments
81
- ├── code
82
- │ ├── signal
83
- │ ├── prepare
84
- │ ├── finalize
85
- │ ├── update
86
- │ └── rescue
87
- ├── annotations
88
- └── documentation
89
-
90
- The <method> field must strictly follow the Service Registry specification.
91
- If the service specification defines a method, use exactly that value. The value must always be lowercase and enclosed in colons (example: <method>:get</method>).
92
- Never invent, infer, or assume a method value that is not explicitly defined in the service specification:
93
- <method/>
94
-
95
- Service input parameters are stored inside arguments. Each argument is represented by its own child element.
96
- <arguments>
97
- <min>1</min>
98
- <max>100</max>
99
- </arguments>
100
- If an argument depends on a previously computed or returned value, it must be provided using the !data.some_value syntax.
101
- <arguments>
102
- <step>!data.current_step</step>
103
- </arguments>
104
-
105
- Returned service values are processed inside finalize: <finalize output="result">, where result is the variable containing the service response. Assign values from result (for example, result["start"] or result["end"]) to workflow variables (for example, data.start or data.end) to store them for later use in the process.
106
- <finalize output="result"> data.temperature = result["temperature"].to_f; data.type = result["celsius"];</finalize>
107
-
108
- ## Script Task
109
- A BPMN Script Task is represented by <manipulate>. The executable Ruby code is stored inside the <code> child element:
110
- <manipulate><code>data.counter += 1</code></manipulate>
111
-
112
- ## Exclusive Gateway
113
- An Exclusive Gateway is represented by <choose>
114
- Each outgoing branch is represented by <alternative> child.
115
- The branch condition is stored in the **condition attribute**.
116
- <alternative condition="data.temperature > 30">
117
- Conditions must be valid Ruby expressions.
118
-
119
- ## Loop
120
- A BPMN loop is represented by <loop>
121
- The loop condition is stored in the **condition attribute**. The loop execution mode is stored in the **mode attribute** (pre_test/post_test)
122
- <loop mode="pre_test" condition="data.counter < 10">
123
- Loop conditions must be valid Ruby expressions.
124
-
125
- ## Parallel Gateway
126
- Parallel execution is represented by <parallel>
127
- Each concurrent branch is represented by <parallel_branch>
128
-
129
- ##Pause Task
130
- A pause is represented by a <stop> element.
131
- A <stop> pauses the execution of the process (until it is manually resumed). It does not terminate the process.
132
- <stop id="a5"/>
133
- When the user requests to pause, hold, or stop the process, insert a <stop> element.
134
- The id attribute must be unique within the process model. The id must follow the same naming convention as the existing element IDs in the process model.
135
- Insert the <stop> element at the location specified or implied by the user's request. Otherwise, insert the <stop> element as the last element of the process.
136
-
137
- ## Variables
138
- Variables are referenced as: data.variable_name
139
- Service outputs are returned as strings unless otherwise specified.
140
- Whenever a value represents a numeric type (integer or floating-point), convert it to a numeric value before assigning it to a workflow variable by using Ruby's .to_f method:
141
- data.temperature = result["temperature"].to_f
67
+ %%%cpee_xml.txt
142
68
 
143
69
  # Handling Ambiguity
144
70
  If the user's request is sufficiently precise, perform the modification directly.
@@ -154,4 +80,3 @@ If multiple valid interpretations exist and the missing information affects the
154
80
  Do not output Markdown.
155
81
  Do not omit unchanged sections.
156
82
  The returned XML must be immediately usable as a valid CPEE process model.
157
-