monadic-chat 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,36 +6,27 @@ class MonadicApp
6
6
  ##################################################
7
7
  def format_data
8
8
  contextual = []
9
- accumulated = []
9
+ accumulator = []
10
10
 
11
- objectify.each do |key, val|
12
- next if %w[prompt response].include? key
11
+ if @method == "completions"
12
+ objectify.each do |key, val|
13
+ next if %w[prompt response messages].include? key
13
14
 
14
- if (@method == "completions" && key == @prop_accumulated) ||
15
- (@method == "chat/completions" && key == "messages")
16
- val = val.map do |v|
17
- case @method
18
- when "completions"
19
- if v.instance_of?(String)
20
- v.sub(/\s+###\s*$/m, "")
21
- else
22
- v.map { |role, text| "#{role.strip.capitalize}: #{text.sub(/\s+###\s*$/m, "")}" }
23
- end
24
- when "chat/completions"
25
- "#{v["role"].capitalize}: #{v["content"]}"
26
- end
27
- end
28
- accumulated << val.join("\n\n")
29
- else
30
15
  contextual << "- **#{key.split("_").map(&:capitalize).join(" ")}**: #{val.to_s.strip}"
31
16
  end
32
17
  end
33
18
 
19
+ @messages.each do |m|
20
+ accumulator << "#{m["role"].capitalize}: #{m["content"]}".sub("\n\n###\n\n", "")
21
+ end
22
+
34
23
  h1 = "# Monadic :: Chat / #{self.class.name}"
35
24
  contextual.map!(&:strip).unshift "## Contextual Data\n" unless contextual.empty?
36
- accum_label = @prop_accumulated.split("_").map(&:capitalize).join(" ")
37
- accumulated.map!(&:strip).unshift "## #{accum_label}\n" unless accumulated.empty?
38
- "#{h1}\n\n#{contextual.join("\n")}\n\n#{accumulated.join("\n")}"
25
+
26
+ accum_label = @prop_accumulator.split("_").map(&:capitalize).join(" ")
27
+ accumulator.map!(&:strip).unshift "## #{accum_label}\n" unless accumulator.empty?
28
+
29
+ "#{h1}\n\n#{contextual.join("\n")}\n\n#{accumulator.join("\n\n")}"
39
30
  end
40
31
 
41
32
  def show_data
@@ -48,12 +39,22 @@ class MonadicApp
48
39
  end
49
40
 
50
41
  def set_html
51
- print PROMPT_SYSTEM.prefix
42
+ res = format_data.sub(%r{::(.+?)/(.+?)\b}) do
43
+ " <span class='monadic_gray'>::</span> <span class='monadic_app'>#{Regexp.last_match(1)}</span> <span class='monadic_gray'>/</span> #{Regexp.last_match(2)}"
44
+ end
45
+ res = res.gsub("```") { "~~~" }
46
+ .gsub(/^(system):/i) { "<span class='monadic_system'> #{Regexp.last_match(1)} </span><br />" }
47
+ .gsub(/^(user):/i) { "<span class='monadic_user'> #{Regexp.last_match(1)} </span><br />" }
48
+ .gsub(/^(assistant|gpt):/i) { "<span class='monadic_chat'> #{Regexp.last_match(1)} </span><br />" }
49
+ add_to_html(res, TEMP_HTML)
50
+ end
52
51
 
52
+ def show_html
53
53
  wait
54
-
54
+ set_html
55
+ print PROMPT_SYSTEM.prefix
55
56
  print "HTML is ready\n"
56
- show_html
57
+ Launchy.open(TEMP_HTML)
57
58
  end
58
59
 
59
60
  def add_to_html(text, filepath)
@@ -94,17 +95,5 @@ class MonadicApp
94
95
  HTML
95
96
  f.write html
96
97
  end
97
- Launchy.open(filepath)
98
- end
99
-
100
- def show_html
101
- res = format_data.sub(%r{::(.+?)/(.+?)\b}) do
102
- " <span class='monadic_gray'>::</span> <span class='monadic_app'>#{Regexp.last_match(1)}</span> <span class='monadic_gray'>/</span> #{Regexp.last_match(2)}"
103
- end
104
- res = res.gsub("```") { "~~~" }
105
- .gsub(/^(system):/i) { "<span class='monadic_system'> #{Regexp.last_match(1)} </span><br />" }
106
- .gsub(/^(user):/i) { "<span class='monadic_user'> #{Regexp.last_match(1)} </span><br />" }
107
- .gsub(/^(assistant|gpt):/i) { "<span class='monadic_chat'> #{Regexp.last_match(1)} </span><br />" }
108
- add_to_html(res, TEMP_HTML)
109
98
  end
110
99
  end
@@ -32,12 +32,8 @@ class MonadicApp
32
32
  false
33
33
  else
34
34
  replacements.each do |key, value|
35
- case @method
36
- when "completions"
37
- @template.gsub!(key, value)
38
- when "chat/completions"
39
- @template["messages"][0]["content"].gsub!(key, value)
40
- end
35
+ @messages[0]["content"].gsub!(key, value)
36
+ messages[0]["content"]
41
37
  end
42
38
  true
43
39
  end
@@ -68,34 +64,58 @@ class MonadicApp
68
64
  when "completions"
69
65
  m = /\n\n```json\s*(\{.+\})\s*```\n\n/m.match(@template)
70
66
  json = m[1].gsub(/(?!\\\\\\)\\\\"/) { '\\\"' }
71
- JSON.parse(json)
67
+ res = JSON.parse(json)
68
+ res["messages"] = @messages
69
+ res
72
70
  when "chat/completions"
73
- @template
71
+ @messages
74
72
  end
75
73
  end
76
74
 
77
75
  def prepare_params(input)
78
76
  params = @params.dup
77
+
78
+ @update_proc.call
79
79
  case @method
80
80
  when "completions"
81
- template = @template.dup.sub("{{PROMPT}}", input).sub("{{MAX_TOKENS}}", (@params["max_tokens"] / 2).to_s)
81
+ messages = +""
82
+ system = +""
83
+ @messages.each do |mes|
84
+ role = mes["role"]
85
+ content = mes["content"]
86
+ case role
87
+ when "system"
88
+ system << "#{content}\n"
89
+ when "assistant", "gpt"
90
+ system << "- #{mes["role"].strip}: #{content.sub("\n\n###\n\n", "")}\n\n###\n\n"
91
+ else
92
+ messages << "- #{mes["role"].strip}: #{mes["content"]}"
93
+ end
94
+ end
95
+ template = @template.dup.sub("{{SYSTEM}}", system)
96
+ .sub("{{PROMPT}}", input)
97
+ .sub("{{MESSAGES}}", messages.strip)
98
+
82
99
  params["prompt"] = template
100
+ @messages << { "role" => "user", "content" => input }
83
101
  when "chat/completions"
84
- @template["messages"] << { "role" => "user", "content" => input }
85
- params["messages"] = @template["messages"]
102
+ @messages << { "role" => "user", "content" => input }
103
+ @update_proc.call
104
+ params["messages"] = @messages
86
105
  end
106
+
87
107
  params
88
108
  end
89
109
 
90
110
  def update_template(res)
91
111
  case @method
92
112
  when "completions"
93
- updated = @update_proc.call(res)
94
- json = updated.to_json.strip
113
+ @metadata = res
114
+ @messages << { "role" => "assistant", "content" => res["response"] }
115
+ json = res.to_json.strip
95
116
  @template.sub!(/\n\n```json.+```\n\n/m, "\n\n```json\n#{json}\n```\n\n")
96
117
  when "chat/completions"
97
- @template["messages"] << { "role" => "assistant", "content" => res }
98
- @template["messages"] = @update_proc.call(@template["messages"])
118
+ @messages << { "role" => "assistant", "content" => res }
99
119
  end
100
120
  end
101
121
 
@@ -110,6 +130,7 @@ class MonadicApp
110
130
  wait
111
131
 
112
132
  params = prepare_params(input)
133
+
113
134
  print TTY::Cursor.save
114
135
 
115
136
  escaping = +""
@@ -158,6 +179,7 @@ class MonadicApp
158
179
  print "\n"
159
180
 
160
181
  update_template(res)
182
+ set_html if @html
161
183
  end
162
184
 
163
185
  def bind_research_mode(input, num_retry: 0)
@@ -166,6 +188,7 @@ class MonadicApp
166
188
  wait
167
189
 
168
190
  params = prepare_params(input)
191
+
169
192
  print TTY::Cursor.save
170
193
 
171
194
  @threads << true
@@ -179,7 +202,7 @@ class MonadicApp
179
202
  finished = false
180
203
  response = +""
181
204
  spinning = false
182
- res = @completion.run(params, num_retry: num_retry) do |chunk|
205
+ res = @completion.run(params, num_retry: num_retry, tmp_json_file: TEMP_JSON, tmp_md_file: TEMP_MD) do |chunk|
183
206
  if finished && !response_all_shown
184
207
  response_all_shown = true
185
208
  @responses << response.sub(/\s+###\s*".*/m, "")
@@ -265,5 +288,6 @@ class MonadicApp
265
288
  break
266
289
  end
267
290
  end
291
+ set_html if @html
268
292
  end
269
293
  end
@@ -9,16 +9,16 @@ class MonadicApp
9
9
  clear_screen
10
10
  print TTY::Cursor.save
11
11
  parameter = PROMPT_SYSTEM.select("Select function:", per_page: 10, cycle: true, filter: true, default: 1, show_help: :never) do |menu|
12
- menu.choice "#{BULLET} #{PASTEL.bold("cancel/return/escape")} cancel this menu", "cancel"
13
- menu.choice "#{BULLET} #{PASTEL.bold("params/settings/config")} show and change values of parameters", "params"
14
- menu.choice "#{BULLET} #{PASTEL.bold("data/context")} show currrent contextual info", "data"
15
- menu.choice "#{BULLET} #{PASTEL.bold("html")} view contextual info on the web browser", "html"
16
- menu.choice "#{BULLET} #{PASTEL.bold("reset")} reset context to original state", "reset"
17
- menu.choice "#{BULLET} #{PASTEL.bold("save")} save current contextual info to file", "save"
18
- menu.choice "#{BULLET} #{PASTEL.bold("load")} load current contextual info from file", "load"
19
- menu.choice "#{BULLET} #{PASTEL.bold("clear/clean")} clear screen", "clear"
20
- menu.choice "#{BULLET} #{PASTEL.bold("readme/documentation")} open readme/documentation", "readme"
21
- menu.choice "#{BULLET} #{PASTEL.bold("exit/bye/quit")} go back to main menu", "exit"
12
+ menu.choice "#{BULLET} #{PASTEL.bold("cancel/return/escape")} Cancel this menu", "cancel"
13
+ menu.choice "#{BULLET} #{PASTEL.bold("params/settings/config")} Show and change values of parameters", "params"
14
+ menu.choice "#{BULLET} #{PASTEL.bold("data/context")} Show currrent contextual info", "data"
15
+ menu.choice "#{BULLET} #{PASTEL.bold("html")} View contextual info on the web browser", "html"
16
+ menu.choice "#{BULLET} #{PASTEL.bold("reset")} Reset context to initial state", "reset"
17
+ menu.choice "#{BULLET} #{PASTEL.bold("save")} Save current contextual info to file", "save"
18
+ menu.choice "#{BULLET} #{PASTEL.bold("load")} Load current contextual info from file", "load"
19
+ menu.choice "#{BULLET} #{PASTEL.bold("clear/clean")} Clear screen", "clear"
20
+ menu.choice "#{BULLET} #{PASTEL.bold("readme/documentation")} Open readme/documentation", "readme"
21
+ menu.choice "#{BULLET} #{PASTEL.bold("exit/bye/quit")} Go back to main menu", "exit"
22
22
  end
23
23
 
24
24
  print TTY::Cursor.restore
@@ -33,7 +33,8 @@ class MonadicApp
33
33
  when "data"
34
34
  show_data
35
35
  when "html"
36
- set_html
36
+ @html = true
37
+ show_html
37
38
  when "reset"
38
39
  reset
39
40
  when "save"
@@ -52,14 +53,10 @@ class MonadicApp
52
53
  end
53
54
 
54
55
  def reset
55
- @params = @params_original.dup
56
-
57
- case @method
58
- when "completions"
59
- @template = @template_original.dup
60
- when "chat/completions"
61
- @template = JSON.parse @template_original
62
- end
56
+ @html = false
57
+ @params = @params_initial.dup
58
+ @messages = @messages_initial.dup
59
+ @template = @template_initial.dup
63
60
 
64
61
  if @placeholders.empty?
65
62
  print PROMPT_SYSTEM.prefix
@@ -133,9 +130,11 @@ class MonadicApp
133
130
  case @method
134
131
  when "completions"
135
132
  m = /\n\n```json\s*(\{.+\})\s*```\n\n/m.match(@template)
136
- f.write JSON.pretty_generate(JSON.parse(m[1]))
133
+ data = JSON.parse(m[1])
134
+ data["messages"] = @messages
135
+ f.write JSON.pretty_generate(data)
137
136
  when "chat/completions"
138
- f.write JSON.pretty_generate(@template)
137
+ f.write JSON.pretty_generate({ "messages" => @messages })
139
138
  end
140
139
 
141
140
  print "Data has been saved successfully\n"
@@ -170,14 +169,17 @@ class MonadicApp
170
169
  data = JSON.parse(json)
171
170
  case @method
172
171
  when "completions"
172
+ self.class.name.downcase.split("::")[-1]
173
+
173
174
  raise unless data["mode"] == self.class.name.downcase.split("::")[-1]
174
175
 
175
- new_template = @template.sub(/\n\n```json\s*\{.+\}\s*```\n\n/m, "\n\n```json\n#{JSON.pretty_generate(data).strip}\n```\n\n")
176
- @template = new_template
176
+ @messages = data.delete "messages"
177
+ @template = @template.sub(/\n\n```json\s*\{.+\}\s*```\n\n/m, "\n\n```json\n#{JSON.pretty_generate(data).strip}\n```\n\n")
177
178
  when "chat/completions"
179
+ pp data
178
180
  raise unless data["messages"] && data["messages"][0]["role"]
179
181
 
180
- @template["messages"] = data["messages"]
182
+ @messages = data["messages"]
181
183
  end
182
184
  print "Data has been loaded successfully\n"
183
185
  true
@@ -81,16 +81,15 @@ module OpenAI
81
81
  class Completion
82
82
  attr_reader :access_token
83
83
 
84
- def initialize(access_token, tmp_file: nil)
84
+ def initialize(access_token)
85
85
  @access_token = access_token
86
- @tmp_file = tmp_file
87
86
  end
88
87
 
89
88
  def models
90
89
  OpenAI.models(@access_token)
91
90
  end
92
91
 
93
- def run(params, num_retry: 1, &block)
92
+ def run(params, num_retry: 1, tmp_json_file: nil, tmp_md_file: nil, &block)
94
93
  method = OpenAI.model_to_method(params["model"])
95
94
 
96
95
  response = OpenAI.query(@access_token, "post", method, 60, params, &block)
@@ -102,7 +101,8 @@ module OpenAI
102
101
 
103
102
  case method
104
103
  when "completions"
105
- get_json response ["choices"][0]["text"]
104
+ File.open(tmp_md_file, "w") { |f| f.write params["prompt"] } if tmp_md_file
105
+ get_json(response["choices"][0]["text"], tmp_json_file: tmp_json_file)
106
106
  when "chat/completions"
107
107
  response ["choices"][0]["text"]
108
108
  end
@@ -115,7 +115,7 @@ module OpenAI
115
115
  end
116
116
  end
117
117
 
118
- def get_json(data)
118
+ def get_json(data, tmp_json_file: nil)
119
119
  case data
120
120
  when %r{<JSON>\n*(\{.+\})\n*</JSON>}m
121
121
  json = Regexp.last_match(1).gsub(/\r\n?/, "\n").gsub(/\r\n/) { "\n" }
@@ -126,7 +126,7 @@ module OpenAI
126
126
  else
127
127
  res = data
128
128
  end
129
- File.open(@tmp_file, "w") { |f| f.write json } if @tmp_file
129
+ File.open(tmp_json_file, "w") { |f| f.write json } if tmp_json_file
130
130
  res
131
131
  end
132
132
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MonadicChat
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/monadic_chat.rb CHANGED
@@ -46,6 +46,7 @@ module MonadicChat
46
46
 
47
47
  TEMP_HTML = File.join(Dir.home, "monadic_chat.html")
48
48
  TEMP_JSON = File.join(Dir.home, "monadic_chat.json")
49
+ TEMP_MD = File.join(Dir.home, "monadic_chat.md")
49
50
 
50
51
  style = +File.read(File.join(__dir__, "..", "assets", "github.css")).gsub(".markdown-") { "" }
51
52
  style << File.read(File.join(__dir__, "..", "assets", "pigments-default.css"))
@@ -126,7 +127,7 @@ module MonadicChat
126
127
  raise if OpenAI.models(token).empty?
127
128
 
128
129
  print "success\n"
129
- OpenAI::Completion.new(token, tmp_file: TEMP_JSON)
130
+ OpenAI::Completion.new(token)
130
131
  rescue StandardError
131
132
  print "failure.\n"
132
133
  false
data/monadic_chat.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
14
14
  DESC
15
15
  spec.homepage = "https://github.com/yohasebe/monadic-chat"
16
16
  spec.license = "MIT"
17
- spec.required_ruby_version = ">= 2.6.0"
17
+ spec.required_ruby_version = ">= 2.6.10"
18
18
 
19
19
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
20
20
 
@@ -36,7 +36,6 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency "bundler"
37
37
  spec.add_development_dependency "rake"
38
38
  spec.add_development_dependency "rspec"
39
- spec.add_development_dependency "solargraph"
40
39
 
41
40
  spec.add_dependency "http"
42
41
  spec.add_dependency "kramdown"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monadic-chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yohasebe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-12 00:00:00.000000000 Z
11
+ date: 2023-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: solargraph
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: http
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -264,6 +250,7 @@ files:
264
250
  - ".ruby-version"
265
251
  - CHANGELOG.md
266
252
  - Gemfile
253
+ - Gemfile.lock
267
254
  - LICENSE.txt
268
255
  - README.md
269
256
  - Rakefile
@@ -273,6 +260,9 @@ files:
273
260
  - apps/code/code.json
274
261
  - apps/code/code.md
275
262
  - apps/code/code.rb
263
+ - apps/linguistic/linguistic.json
264
+ - apps/linguistic/linguistic.md
265
+ - apps/linguistic/linguistic.rb
276
266
  - apps/novel/novel.json
277
267
  - apps/novel/novel.md
278
268
  - apps/novel/novel.rb
@@ -289,7 +279,6 @@ files:
289
279
  - doc/img/input-acess-token.png
290
280
  - doc/img/langacker-2001.svg
291
281
  - doc/img/linguistic-html.png
292
- - doc/img/monadic-chat-main-menu.png
293
282
  - doc/img/monadic-chat.svg
294
283
  - doc/img/readme-example-beatles-html.png
295
284
  - doc/img/readme-example-beatles.png
@@ -310,9 +299,6 @@ files:
310
299
  - lib/monadic_chat/parameters.rb
311
300
  - lib/monadic_chat/version.rb
312
301
  - monadic_chat.gemspec
313
- - samples/linguistic/linguistic.json
314
- - samples/linguistic/linguistic.md
315
- - samples/linguistic/linguistic.rb
316
302
  homepage: https://github.com/yohasebe/monadic-chat
317
303
  licenses:
318
304
  - MIT
@@ -329,14 +315,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
329
315
  requirements:
330
316
  - - ">="
331
317
  - !ruby/object:Gem::Version
332
- version: 2.6.0
318
+ version: 2.6.10
333
319
  required_rubygems_version: !ruby/object:Gem::Requirement
334
320
  requirements:
335
321
  - - ">="
336
322
  - !ruby/object:Gem::Version
337
323
  version: '0'
338
324
  requirements: []
339
- rubygems_version: 3.4.8
325
+ rubygems_version: 3.4.1
340
326
  signing_key:
341
327
  specification_version: 4
342
328
  summary: Highly configurable CLI client app for OpenAI chat/text-completion API
Binary file
@@ -1,39 +0,0 @@
1
- You are an English syntactic/semantic/pragmatic analyzer. Analyze the new prompt from the user below and execute a syntactic parsing. Give your response in a variation of the penn treebank format, but use brackets [ ] instead of parentheses ( ). Also, give your response in a markdown code span. The sentence must always be parsed if the user's input sentence is enclosed in double quotes. Create a response to the following new prompt from the user and set your response to the "response" property of the JSON object shown below. All prompts by "user" in the "messages" property are continuous in content. If pasing the input sentence is extremely difficult, or the input is not enclosed in double quotes, let the user know.
2
-
3
- NEW PROMPT: {{PROMPT}}
4
-
5
- ```json
6
- {
7
- "prompt": "\"We didn't have a camera.\"",
8
- "response": "`[S [NP We] [VP [V didn't] [VP [V have] [NP [Det a] [N camera] ] ] ] ] ]`\n\n###\n\n",
9
- "mode": "linguistic",
10
- "turns": 3,
11
- "sentence_type": ["declarative"],
12
- "sentiment": ["sad"],
13
- "summary": "The user saw a beautiful sunset, but did not take a picture because the user did not have a camera.",
14
- "tokens": 351,
15
- "messages": [{"user": "\"We saw a beautiful sunset.\"", "assistant": "`[S [NP He] [VP [V saw] [NP [det a] [N' [Adj beautiful] [N sunset] ] ] ] ]`\n\n###\n\n"},{"user": "\"We didn't take a picture.\"", "assistant": "`[S [NP We] [IP [I didn't] [VP [V take] [NP [Det a] [N picture] ] ] ] ] ]`\n\n###\n\n"},{"user": "\"We didn't have a camera.\"", "assistant": "`[S [NP We] [IP [I didn't] [VP [V have] [NP [Det a] [N camera] ] ] ] ] ]`\n\n###\n\n"}]
16
- }
17
- ```
18
-
19
- Make sure the following content requirements are all fulfilled:
20
-
21
- - keep the value of the "mode" property at "linguistic"
22
- - set the new prompt to the "prompt" property
23
- - create your response to the new prompt in accordance with the "messages" and set it to "response"
24
- - insert both the new prompt and the response after all the existing items in the "messages"
25
- - analyze the new prompt's sentence type and set a sentence type value such as "interrogative", "imperative", "exclamatory", or "declarative" to the "sentence_type" property
26
- - analyze the new prompt's sentiment and set one or more sentiment types such as "happy", "excited", "troubled", "upset", or "sad" to the "sentiment" property
27
- - summarize the user's messages so far and update the "summary" property with a text of fewer than 100 words using as many discourse markers such as "because", "therefore", "but", "so" to show the logical connection between the events.
28
- - update the value of "tokens" with the number of tokens of the resulting JSON object"
29
-
30
- Make sure the following formal requirements are all fulfilled:
31
-
32
- - do not use invalid characters in the JSON object
33
- - escape double quotes and other special characters in the text values in the resulting JSON object
34
- - increment the value of "turns" by 1 and update the property so that the value of "turns" equals the number of the items in the "messages" of the resulting JSON object
35
- - check the validity of the generated JSON object and correct any possible parsing problems before returning it
36
-
37
- Add "\n\n###\n\n" at the end of the "response" value.
38
-
39
- Wrap the JSON object with "<JSON>\n" and "\n</JSON>".