codex-ruby 0.1.5 → 0.2.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/lib/codex_sdk/agent_thread.rb +34 -6
- data/lib/codex_sdk/exec.rb +31 -11
- data/lib/codex_sdk/options.rb +8 -2
- data/lib/codex_sdk/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8b977d75f6a42ed832175f5f2fe94a51edc5cee832e23de58ef7a154062310e9
|
|
4
|
+
data.tar.gz: 9742a0cd52e621689755eee26f7f41cf199b2f964dced853e41765ae44595a82
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7f9f2b48f75d8f07bf09befcd9f5f5d85c420f4757ea11f4d9292f6421e4c7d2d345ac29b414280df2fb05815ab382f996fe2b6efa99568cae19b52c53fa5fb
|
|
7
|
+
data.tar.gz: 6cad8b57516073b897fb6465f3a8409995559cf616928cd3ae9663ffe0afa6afe8315c9ca9e904a9ea9e389727cc2909aeb3264398c0879441d53c5c729103ae
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3 (2026-09-23)
|
|
4
|
+
|
|
5
|
+
- Preserve provider failures when macOS reports a transient permission error for an exiting process group; verify that the group is gone before ignoring cleanup errors.
|
|
6
|
+
|
|
7
|
+
## 0.2.2 (2026-09-23)
|
|
8
|
+
|
|
9
|
+
- Clear the exposed PID after an already-exited CLI has been reaped, preventing stale process diagnostics.
|
|
10
|
+
|
|
11
|
+
## 0.2.1 (2026-09-23)
|
|
12
|
+
|
|
13
|
+
- Expose the active CLI PID through `AgentThread#pid` for worker recovery diagnostics.
|
|
14
|
+
|
|
15
|
+
## 0.2.0 (2026-09-23)
|
|
16
|
+
|
|
17
|
+
- Forward ordered `local_image` inputs through the public thread API; reject unsupported input types and invalid local paths instead of silently discarding them.
|
|
18
|
+
- Add `ignore_user_config`, `ignore_rules`, and `ephemeral` thread options; use the documented `--json` CLI flag.
|
|
19
|
+
- Honor explicit environment replacement without inheriting parent secrets.
|
|
20
|
+
- Terminate and reap CLI process groups on cancellation or consumer errors, with concurrent interruption serialized.
|
|
21
|
+
- Raise on streams that end without a completed turn instead of returning partial answers as success.
|
|
22
|
+
|
|
3
23
|
## 0.1.5 (2026-06-17)
|
|
4
24
|
|
|
5
25
|
- Include structured Codex CLI error events in non-zero exit errors, so
|
|
@@ -38,7 +38,8 @@ module CodexSDK
|
|
|
38
38
|
|
|
39
39
|
# Streaming run: yields each event to the block as it arrives.
|
|
40
40
|
def run_streamed(input, turn_options: TurnOptions.new, &block)
|
|
41
|
-
prompt = normalize_input(input)
|
|
41
|
+
prompt, images = normalize_input(input)
|
|
42
|
+
completed = false
|
|
42
43
|
|
|
43
44
|
output_schema_path = nil
|
|
44
45
|
output_schema_path = write_output_schema(turn_options.output_schema) if turn_options.output_schema
|
|
@@ -50,19 +51,27 @@ module CodexSDK
|
|
|
50
51
|
|
|
51
52
|
@exec.run(
|
|
52
53
|
prompt,
|
|
54
|
+
images: images,
|
|
53
55
|
resume_thread_id: @id,
|
|
54
56
|
output_schema_path: output_schema_path
|
|
55
57
|
) do |event|
|
|
56
58
|
# Capture thread ID from first event
|
|
57
59
|
@id = event.thread_id if event.is_a?(Events::ThreadStarted)
|
|
60
|
+
completed = true if event.is_a?(Events::TurnCompleted)
|
|
58
61
|
|
|
59
62
|
block.call(event)
|
|
60
63
|
end
|
|
64
|
+
raise Error, "Codex stream ended without turn completion" unless completed
|
|
61
65
|
ensure
|
|
62
66
|
@context_snapshot = @exec&.context_snapshot
|
|
63
67
|
cleanup_output_schema(output_schema_path)
|
|
64
68
|
end
|
|
65
69
|
|
|
70
|
+
# PID of the running CLI, for external lifecycle diagnostics.
|
|
71
|
+
def pid
|
|
72
|
+
@exec&.pid
|
|
73
|
+
end
|
|
74
|
+
|
|
66
75
|
# Interrupt the running subprocess.
|
|
67
76
|
def interrupt
|
|
68
77
|
@exec&.interrupt
|
|
@@ -73,13 +82,32 @@ module CodexSDK
|
|
|
73
82
|
def normalize_input(input)
|
|
74
83
|
case input
|
|
75
84
|
when String
|
|
76
|
-
input
|
|
85
|
+
[input, []]
|
|
77
86
|
when Array
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
texts = []
|
|
88
|
+
images = []
|
|
89
|
+
input.each do |entry|
|
|
90
|
+
raise ArgumentError, "Unsupported input entry" unless entry.is_a?(Hash)
|
|
91
|
+
|
|
92
|
+
case entry[:type]
|
|
93
|
+
when "text"
|
|
94
|
+
raise ArgumentError, "Text input must be a string" unless entry[:text].is_a?(String)
|
|
95
|
+
|
|
96
|
+
texts << entry[:text]
|
|
97
|
+
when "local_image"
|
|
98
|
+
path = entry[:path]
|
|
99
|
+
unless path.is_a?(String) && path.start_with?(File::SEPARATOR) && File.file?(path) && File.readable?(path)
|
|
100
|
+
raise ArgumentError, "Local image must be an absolute readable file path"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
images << path
|
|
104
|
+
else
|
|
105
|
+
raise ArgumentError, "Unsupported input type: #{entry[:type].inspect}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
[texts.join("\n\n"), images]
|
|
81
109
|
else
|
|
82
|
-
input
|
|
110
|
+
raise ArgumentError, "Unsupported input: expected string or array"
|
|
83
111
|
end
|
|
84
112
|
end
|
|
85
113
|
|
data/lib/codex_sdk/exec.rb
CHANGED
|
@@ -5,7 +5,7 @@ require "json"
|
|
|
5
5
|
|
|
6
6
|
module CodexSDK
|
|
7
7
|
# Internal: manages the codex CLI subprocess.
|
|
8
|
-
# Spawns `codex exec --
|
|
8
|
+
# Spawns `codex exec --json`, writes prompt to stdin,
|
|
9
9
|
# reads JSONL events from stdout.
|
|
10
10
|
class Exec
|
|
11
11
|
SHUTDOWN_TIMEOUT = 10 # seconds to wait after SIGTERM before SIGKILL
|
|
@@ -32,7 +32,9 @@ module CodexSDK
|
|
|
32
32
|
@context_snapshot = nil
|
|
33
33
|
diagnostics = []
|
|
34
34
|
|
|
35
|
-
@stdin, @stdout, @stderr, @wait_thread = Open3.popen3(env, *args
|
|
35
|
+
@stdin, @stdout, @stderr, @wait_thread = Open3.popen3(env, *args, unsetenv_others: !@options.env.nil?,
|
|
36
|
+
pgroup: true)
|
|
37
|
+
@pid = @wait_thread.pid
|
|
36
38
|
|
|
37
39
|
# Write prompt and close stdin (one-shot, matching TypeScript SDK)
|
|
38
40
|
@stdin.write(prompt.to_s)
|
|
@@ -85,27 +87,41 @@ module CodexSDK
|
|
|
85
87
|
# Sends SIGTERM to the subprocess, waits, then SIGKILL if needed.
|
|
86
88
|
def interrupt
|
|
87
89
|
@mutex.synchronize do
|
|
88
|
-
return unless @
|
|
90
|
+
return unless @pid
|
|
89
91
|
|
|
90
92
|
begin
|
|
91
|
-
|
|
93
|
+
signal_group("TERM")
|
|
92
94
|
rescue Errno::ESRCH
|
|
95
|
+
@wait_thread.value
|
|
96
|
+
@pid = nil
|
|
93
97
|
return
|
|
94
98
|
end
|
|
95
99
|
|
|
96
100
|
# Wait for graceful shutdown
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
wait_for_exit(SHUTDOWN_TIMEOUT)
|
|
102
|
+
begin
|
|
103
|
+
# Also stop descendants that outlive the immediate CLI child.
|
|
104
|
+
signal_group("KILL")
|
|
105
|
+
rescue Errno::ESRCH
|
|
106
|
+
# already gone
|
|
103
107
|
end
|
|
108
|
+
@wait_thread.value
|
|
109
|
+
@pid = nil
|
|
104
110
|
end
|
|
105
111
|
end
|
|
106
112
|
|
|
107
113
|
private
|
|
108
114
|
|
|
115
|
+
def signal_group(signal)
|
|
116
|
+
Process.kill(signal, -@pid)
|
|
117
|
+
rescue Errno::EPERM
|
|
118
|
+
# macOS can report EPERM while the last group member is exiting.
|
|
119
|
+
# Only treat it as gone when a subsequent group probe confirms ESRCH.
|
|
120
|
+
@wait_thread.join(0.1)
|
|
121
|
+
Process.kill(0, -@pid)
|
|
122
|
+
raise
|
|
123
|
+
end
|
|
124
|
+
|
|
109
125
|
def capture_diagnostic(event, diagnostics)
|
|
110
126
|
message =
|
|
111
127
|
case event
|
|
@@ -136,7 +152,7 @@ module CodexSDK
|
|
|
136
152
|
codex_path = @options.codex_path || find_codex_path
|
|
137
153
|
args = [codex_path]
|
|
138
154
|
args << "--search" if @thread_options.web_search
|
|
139
|
-
args.concat(["exec", "--
|
|
155
|
+
args.concat(["exec", "--json"])
|
|
140
156
|
|
|
141
157
|
# Global config overrides
|
|
142
158
|
args.concat(ConfigSerializer.to_flags(@options.config)) if @options.config.any?
|
|
@@ -153,6 +169,9 @@ module CodexSDK
|
|
|
153
169
|
args.concat(["--cd", to.working_directory]) if to.working_directory
|
|
154
170
|
args << "--dangerously-bypass-approvals-and-sandbox" if to.dangerously_bypass_approvals_and_sandbox
|
|
155
171
|
args << "--skip-git-repo-check" if to.skip_git_repo_check
|
|
172
|
+
args << "--ignore-user-config" if to.ignore_user_config
|
|
173
|
+
args << "--ignore-rules" if to.ignore_rules
|
|
174
|
+
args << "--ephemeral" if to.ephemeral
|
|
156
175
|
|
|
157
176
|
to.additional_directories.each { |dir| args.concat(["--add-dir", dir]) }
|
|
158
177
|
|
|
@@ -227,6 +246,7 @@ module CodexSDK
|
|
|
227
246
|
end
|
|
228
247
|
|
|
229
248
|
def cleanup
|
|
249
|
+
interrupt
|
|
230
250
|
@stdin&.close unless @stdin&.closed?
|
|
231
251
|
@stdout&.close unless @stdout&.closed?
|
|
232
252
|
@stderr&.close unless @stderr&.closed?
|
data/lib/codex_sdk/options.rb
CHANGED
|
@@ -31,7 +31,10 @@ module CodexSDK
|
|
|
31
31
|
:network_access,
|
|
32
32
|
:web_search,
|
|
33
33
|
:additional_directories,
|
|
34
|
-
:skip_git_repo_check
|
|
34
|
+
:skip_git_repo_check,
|
|
35
|
+
:ignore_user_config,
|
|
36
|
+
:ignore_rules,
|
|
37
|
+
:ephemeral
|
|
35
38
|
) do
|
|
36
39
|
def initialize(
|
|
37
40
|
model: nil,
|
|
@@ -43,7 +46,10 @@ module CodexSDK
|
|
|
43
46
|
network_access: nil,
|
|
44
47
|
web_search: nil,
|
|
45
48
|
additional_directories: [],
|
|
46
|
-
skip_git_repo_check: false
|
|
49
|
+
skip_git_repo_check: false,
|
|
50
|
+
ignore_user_config: false,
|
|
51
|
+
ignore_rules: false,
|
|
52
|
+
ephemeral: false
|
|
47
53
|
)
|
|
48
54
|
super
|
|
49
55
|
end
|
data/lib/codex_sdk/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: codex-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anton Kopylov
|
|
@@ -51,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
51
51
|
- !ruby/object:Gem::Version
|
|
52
52
|
version: '0'
|
|
53
53
|
requirements: []
|
|
54
|
-
rubygems_version:
|
|
54
|
+
rubygems_version: 4.0.20
|
|
55
55
|
specification_version: 4
|
|
56
56
|
summary: Ruby SDK for the Codex CLI
|
|
57
57
|
test_files: []
|