prompt_builder 0.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +24 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +763 -0
  5. data/VERSION +1 -0
  6. data/lib/prompt_builder/content/base.rb +44 -0
  7. data/lib/prompt_builder/content/input_file.rb +63 -0
  8. data/lib/prompt_builder/content/input_image.rb +64 -0
  9. data/lib/prompt_builder/content/input_text.rb +42 -0
  10. data/lib/prompt_builder/content/input_video.rb +43 -0
  11. data/lib/prompt_builder/content/output_text.rb +59 -0
  12. data/lib/prompt_builder/content/reasoning_text.rb +42 -0
  13. data/lib/prompt_builder/content/refusal_content.rb +42 -0
  14. data/lib/prompt_builder/content/summary_text.rb +42 -0
  15. data/lib/prompt_builder/content/text.rb +42 -0
  16. data/lib/prompt_builder/content.rb +28 -0
  17. data/lib/prompt_builder/errors.rb +18 -0
  18. data/lib/prompt_builder/items/base.rb +41 -0
  19. data/lib/prompt_builder/items/compaction.rb +60 -0
  20. data/lib/prompt_builder/items/function_call.rb +97 -0
  21. data/lib/prompt_builder/items/function_call_output.rb +110 -0
  22. data/lib/prompt_builder/items/item_reference.rb +42 -0
  23. data/lib/prompt_builder/items/message.rb +113 -0
  24. data/lib/prompt_builder/items/reasoning.rb +75 -0
  25. data/lib/prompt_builder/items.rb +13 -0
  26. data/lib/prompt_builder/response.rb +257 -0
  27. data/lib/prompt_builder/serializers/base.rb +37 -0
  28. data/lib/prompt_builder/serializers/chat_completion/request.rb +389 -0
  29. data/lib/prompt_builder/serializers/chat_completion/response.rb +139 -0
  30. data/lib/prompt_builder/serializers/chat_completion.rb +30 -0
  31. data/lib/prompt_builder/serializers/converse/request.rb +623 -0
  32. data/lib/prompt_builder/serializers/converse/response.rb +140 -0
  33. data/lib/prompt_builder/serializers/converse.rb +30 -0
  34. data/lib/prompt_builder/serializers/gemini/request.rb +562 -0
  35. data/lib/prompt_builder/serializers/gemini/response.rb +233 -0
  36. data/lib/prompt_builder/serializers/gemini.rb +30 -0
  37. data/lib/prompt_builder/serializers/messages/request.rb +634 -0
  38. data/lib/prompt_builder/serializers/messages/response.rb +157 -0
  39. data/lib/prompt_builder/serializers/messages.rb +30 -0
  40. data/lib/prompt_builder/serializers/open_responses/request.rb +229 -0
  41. data/lib/prompt_builder/serializers/open_responses/response.rb +18 -0
  42. data/lib/prompt_builder/serializers/open_responses.rb +30 -0
  43. data/lib/prompt_builder/serializers.rb +35 -0
  44. data/lib/prompt_builder/session.rb +383 -0
  45. data/lib/prompt_builder/tool_registry.rb +75 -0
  46. data/lib/prompt_builder/tools/definition.rb +66 -0
  47. data/lib/prompt_builder/tools.rb +7 -0
  48. data/lib/prompt_builder/usage.rb +100 -0
  49. data/lib/prompt_builder.rb +86 -0
  50. data/prompt_builder.gemspec +41 -0
  51. metadata +107 -0
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptBuilder
4
+ module Serializers
5
+ class ChatCompletion < Base
6
+ # Response parser for the OpenAI Chat Completions API format.
7
+ #
8
+ # Responses with multiple choices (+n > 1+) parse only the first choice;
9
+ # the canonical response object has no candidate collection. Audio
10
+ # responses, legacy +function_call+ responses, non-function tool calls,
11
+ # and unknown content block types are silently skipped. Streaming chunks
12
+ # (+chat.completion.chunk+ deltas) raise +UnsupportedFormatError+ — this
13
+ # parser expects a fully assembled non-streaming response body.
14
+ # Top-level +system_fingerprint+ is exposed through +extra+.
15
+ class Response < Base
16
+ class << self
17
+ private
18
+
19
+ def deserialize_response(hash)
20
+ validate_response!(hash)
21
+
22
+ output = []
23
+ choice = hash.dig("choices", 0)
24
+
25
+ if choice
26
+ message = choice["message"] || {}
27
+ logprobs_content = choice.dig("logprobs", "content") || []
28
+ annotations = message["annotations"] || []
29
+
30
+ # Audio responses and legacy function_call responses are not
31
+ # modeled; they are silently ignored.
32
+
33
+ if message["refusal"]
34
+ output << Items::Message.new(
35
+ role: "assistant",
36
+ content: [Content::RefusalContent.new(refusal: message["refusal"])]
37
+ )
38
+ elsif message["content"].is_a?(Array)
39
+ contents = message["content"].each_with_object([]) do |block, acc|
40
+ case block["type"]
41
+ when "text", nil
42
+ text = block["text"] || ""
43
+ next if text.empty?
44
+
45
+ acc << Content::OutputText.new(
46
+ text: text,
47
+ logprobs: logprobs_content,
48
+ annotations: annotations
49
+ )
50
+ when "refusal"
51
+ acc << Content::RefusalContent.new(refusal: block["refusal"]) if block["refusal"]
52
+ else
53
+ # Unsupported content block types are silently skipped.
54
+ next
55
+ end
56
+ end
57
+ output << Items::Message.new(role: "assistant", content: contents) unless contents.empty?
58
+ elsif message["content"] && !message["content"].empty?
59
+ output << Items::Message.new(
60
+ role: "assistant",
61
+ content: [Content::OutputText.new(
62
+ text: message["content"],
63
+ logprobs: logprobs_content,
64
+ annotations: annotations
65
+ )]
66
+ )
67
+ end
68
+
69
+ (message["tool_calls"] || []).each do |tool_call|
70
+ # Non-function tool call types are silently skipped.
71
+ next unless tool_call["type"] == "function"
72
+
73
+ function = tool_call["function"] || {}
74
+ output << Items::FunctionCall.new(
75
+ name: function["name"],
76
+ call_id: tool_call["id"],
77
+ arguments: function["arguments"] || "{}"
78
+ )
79
+ end
80
+ end
81
+
82
+ usage_hash = hash["usage"]
83
+ usage = if usage_hash
84
+ Usage.new(
85
+ input_tokens: usage_hash["prompt_tokens"],
86
+ output_tokens: usage_hash["completion_tokens"],
87
+ total_tokens: usage_hash["total_tokens"],
88
+ input_tokens_details: usage_hash["prompt_tokens_details"],
89
+ output_tokens_details: usage_hash["completion_tokens_details"]
90
+ )
91
+ end
92
+
93
+ PromptBuilder::Response.new(
94
+ id: hash["id"],
95
+ object: hash["object"],
96
+ created_at: hash["created"],
97
+ model: hash["model"],
98
+ service_tier: hash["service_tier"],
99
+ output: output,
100
+ status: map_finish_reason(choice&.dig("finish_reason")),
101
+ usage: usage,
102
+ extra: provider_data(hash)
103
+ )
104
+ end
105
+
106
+ def validate_response!(hash)
107
+ # A streaming chunk is not a complete response body, so it cannot be
108
+ # parsed into a canonical Response.
109
+ if hash["object"] == "chat.completion.chunk"
110
+ raise UnsupportedFormatError, "Chat Completions streaming chunks are not supported"
111
+ end
112
+ # Responses with multiple choices have no canonical multi-candidate
113
+ # representation; only the first choice is parsed (handled by the
114
+ # caller using choices[0]).
115
+ end
116
+
117
+ def provider_data(hash)
118
+ data = {}
119
+ data["system_fingerprint"] = hash["system_fingerprint"] if hash["system_fingerprint"]
120
+ data.empty? ? nil : data
121
+ end
122
+
123
+ def map_finish_reason(reason)
124
+ case reason
125
+ when "stop", "tool_calls", "function_call"
126
+ "completed"
127
+ when "length"
128
+ "incomplete"
129
+ when "content_filter"
130
+ "failed"
131
+ else
132
+ reason
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptBuilder
4
+ module Serializers
5
+ # Serializer for the OpenAI Chat Completions API format.
6
+ # Delegates request and response handling to dedicated nested classes.
7
+ class ChatCompletion < Base
8
+ autoload :Request, File.expand_path("chat_completion/request", __dir__)
9
+ autoload :Response, File.expand_path("chat_completion/response", __dir__)
10
+
11
+ class << self
12
+ # Export a session to Chat Completions request payload.
13
+ #
14
+ # @param session [Session] the session to export
15
+ # @return [Hash] the serialized request payload
16
+ def request_payload(session)
17
+ Request.request_payload(session)
18
+ end
19
+
20
+ # Parse a Chat Completions response into an PromptBuilder::Response.
21
+ #
22
+ # @param hash [Hash] the response hash in Chat Completions format
23
+ # @return [PromptBuilder::Response] the parsed response
24
+ def parse_response(hash)
25
+ Response.parse_response(hash)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end