charai 0.1.0 → 0.2.0.beta1

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.
@@ -0,0 +1,40 @@
1
+ module Charai
2
+ class InjectedScript
3
+ def initialize(realm, handle)
4
+ @realm = realm
5
+ @handle = handle
6
+ end
7
+
8
+ def e(value)
9
+ @realm.script_evaluate(value, as_handle: false)
10
+ end
11
+
12
+ def h(value)
13
+ @realm.script_evaluate(value, as_handle: true)
14
+ end
15
+
16
+ def getprop(name, as_handle: false)
17
+ c(
18
+ function_declaration: "(injected) => injected.#{name}",
19
+ as_handle: as_handle,
20
+ )
21
+ end
22
+
23
+ def call(name, *args, as_handle: false)
24
+ c(
25
+ function_declaration: "(injected, ...args) => injected.#{name}(...args)",
26
+ args: args,
27
+ as_handle: as_handle,
28
+ )
29
+ end
30
+
31
+ private
32
+
33
+ def c(function_declaration:, args: [], as_handle: false)
34
+ @realm.script_call_function(
35
+ function_declaration,
36
+ arguments: [@handle, *args],
37
+ as_handle: as_handle)
38
+ end
39
+ end
40
+ end
@@ -31,6 +31,31 @@ module Charai
31
31
  end
32
32
  end
33
33
 
34
+ def aria_snapshot(root_locator: 'document.body', ref: false)
35
+ trigger_callback(:on_action_start, 'aria_snapshot', { root_locator: root_locator, ref: ref })
36
+
37
+ current_url = @browsing_context.url
38
+ snapshot = @browsing_context.default_realm._with_injected_script do |script|
39
+ if ref
40
+ body_handle = script.getprop("document.body", as_handle: true)
41
+ result = script.call(:ariaSnapshot, body_handle, { mode: 'ai' })
42
+ result.split("\n")
43
+ else
44
+ not_found = script.e("!#{root_locator}")
45
+ if not_found
46
+ raise ArgumentError, "Element not found: #{root_locator}"
47
+ end
48
+ result = script.call(:ariaSnapshot, script.h(root_locator), { mode: 'autoexpect' })
49
+ result.split("\n")
50
+ end
51
+ end
52
+
53
+ if @message_sender
54
+ message = Agent::Message.new(text: "ARIA snapshot of #{current_url}\n\n#{snapshot}")
55
+ @message_sender.call(message)
56
+ end
57
+ end
58
+
34
59
  def capture_screenshot
35
60
  trigger_callback(:on_action_start, 'capture_screenshot', {})
36
61
 
@@ -73,6 +98,23 @@ module Charai
73
98
  result
74
99
  end
75
100
 
101
+ def execute_script_with_ref(ref, element_function_declaration)
102
+ resolved = resolve_selector_for_ref(ref)
103
+ trigger_callback(:on_action_start, 'execute_script_with_ref', { script: element_function_declaration, ref: ref, selector: resolved[:selector] })
104
+
105
+ begin
106
+ result = @browsing_context.default_realm.script_call_function(
107
+ element_function_declaration,
108
+ arguments: [resolved[:element_handle]])
109
+ rescue BrowsingContext::Realm::ScriptEvaluationError => e
110
+ result = e.message
111
+ end
112
+
113
+ notify_to_sender(result) unless "#{result}" == ''
114
+
115
+ result
116
+ end
117
+
76
118
  def on_pressing_key(key, &block)
77
119
  trigger_callback(:on_action_start, 'key_down', { key: key })
78
120
 
@@ -175,6 +217,23 @@ module Charai
175
217
  end
176
218
  end
177
219
 
220
+ def resolve_selector_for_ref(ref)
221
+ @browsing_context.default_realm._with_injected_script do |script|
222
+ parsed = script.call(:parseSelector, "aria-ref=#{ref}")
223
+
224
+ # ensure ref is attached.
225
+ body_handle = script.getprop("document.body", as_handle: true)
226
+ script.call(:ariaSnapshot, body_handle, { mode: 'ai' })
227
+
228
+ document_handle = script.getprop('document', as_handle: true)
229
+ element_handle = script.call(:querySelector, parsed, document_handle, false, as_handle: true)
230
+
231
+ selector = script.call(:generateSelectorSimple, element_handle, { omitInternalEngines: true })
232
+
233
+ { selector: selector, element_handle: element_handle }
234
+ end
235
+ end
236
+
178
237
  # ref: https://github.com/puppeteer/puppeteer/blob/puppeteer-v23.5.3/packages/puppeteer-core/src/bidi/Input.ts#L52
179
238
  # Converted using ChatGPT 4o
180
239
  def convert_key(key)
@@ -19,6 +19,26 @@ module Charai
19
19
  end
20
20
  end
21
21
 
22
+ class GeminiOpenaiConfiguration
23
+ def initialize(model:, api_key:)
24
+ @endpoint_url = 'https://generativelanguage.googleapis.com/v1beta/openai/'
25
+ @model = model
26
+ @api_key = api_key
27
+ end
28
+
29
+ attr_reader :endpoint_url
30
+
31
+ def add_auth_header(headers)
32
+ headers['Authorization'] = "Bearer #{@api_key}"
33
+ headers
34
+ end
35
+
36
+ def decorate_body(payload)
37
+ payload[:model] = @model
38
+ payload
39
+ end
40
+ end
41
+
22
42
  class AzureOpenaiConfiguration
23
43
  def initialize(endpoint_url:, api_key:)
24
44
  @endpoint_url = endpoint_url
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Charai
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0.beta1"
5
5
  end
data/lib/charai.rb CHANGED
@@ -10,6 +10,7 @@ require 'charai/browser_launcher'
10
10
  require 'charai/browser_process'
11
11
  require 'charai/browsing_context'
12
12
  require 'charai/driver'
13
+ require 'charai/injected_script'
13
14
  require 'charai/input_tool'
14
15
  require 'charai/openai_chat'
15
16
  require 'charai/openai_configuration'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: charai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-25 00:00:00.000000000 Z
11
+ date: 2025-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -75,6 +75,8 @@ files:
75
75
  - lib/charai/browser_process.rb
76
76
  - lib/charai/browsing_context.rb
77
77
  - lib/charai/driver.rb
78
+ - lib/charai/injectedScriptSource.js
79
+ - lib/charai/injected_script.rb
78
80
  - lib/charai/input_tool.rb
79
81
  - lib/charai/openai_chat.rb
80
82
  - lib/charai/openai_configuration.rb