Class: Cline::TaskMessage

Inherits:
Schema
  • Object
show all
Defined in:
lib/cline/task_message.rb

Overview

Task's message

Defined Under Namespace

Classes: ModelInfo

Internal collapse

Attributes inherited from Schema

#extra_attributes

Public API collapse

Internal collapse

Methods inherited from Schema

#==, as_hash, cast, cline_snake_attributes, #to_cline_json, #to_hash

Instance Attribute Details

#cline_modelsModels

Returns The Clines models used to interpret the message.

Returns:

  • (Models)

    The Clines models used to interpret the message



194
195
196
# File 'lib/cline/task_message.rb', line 194

def cline_models
  @cline_models
end

Class Method Details

.of_hash(hash, *args, cline_models:, **kwargs) ⇒ Schema

Parse a Hash object and instantiate the proper instance from it.

Parameters:

  • hash (Hash)

    Data

  • args (Array)

    Remaining arguments to be transferred to Shale

  • cline_models (Models)

    The Clines models used to interpret the message

  • kwargs (Hash)

    Remaining kwargs to be transferred to Shale

Returns:

  • (Schema)

    Corresponding instance



187
188
189
190
191
# File 'lib/cline/task_message.rb', line 187

def self.of_hash(hash, *args, cline_models:, **kwargs)
  instance = super(hash, *args, **kwargs)
  instance.cline_models = cline_models
  instance
end

Instance Method Details

#askString

Returns Ask message identifier.

Returns:

  • (String)

    Ask message identifier



33
# File 'lib/cline/task_message.rb', line 33

attribute :ask, :string

#conversation_history_indexInteger

Returns Position index within the conversation history sequence.

Returns:

  • (Integer)

    Position index within the conversation history sequence



42
# File 'lib/cline/task_message.rb', line 42

attribute :conversation_history_index, :integer

#model_infoModelInfo

Returns Model metadata.

Returns:



39
# File 'lib/cline/task_message.rb', line 39

attribute :model_info, ModelInfo

#partialBoolean

Returns Flag indicating this is an incomplete streaming message.

Returns:

  • (Boolean)

    Flag indicating this is an incomplete streaming message



45
# File 'lib/cline/task_message.rb', line 45

attribute :partial, :boolean

#sayString

Returns Say message identifier.

Returns:

  • (String)

    Say message identifier



30
# File 'lib/cline/task_message.rb', line 30

attribute :say, :string

#textString

Returns Raw text content of the message.

Returns:

  • (String)

    Raw text content of the message



36
# File 'lib/cline/task_message.rb', line 36

attribute :text, :string

#timestampTime

Get the message timestamp as a Ruby time

Returns:

  • (Time)

    The message timestamp



50
51
52
# File 'lib/cline/task_message.rb', line 50

def timestamp
  @timestamp ||= Time.at(ts / 1000.0)
end

#to_human(limit: 128) ⇒ String

Return a human-friendly version of a message. Useful for stdout or logging.

Parameters:

  • limit (Integer) (defaults to: 128)

    Number of characters the message should be limited to

Returns:

  • (String)

    The human translation



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/cline/task_message.rb', line 78

def to_human(limit: 128)
  case type
  when 'say'
    case say
    when 'text', 'task'
      one_lining(text)
    when 'api_req_started'
      sections = parse_sections(JSON.parse(text, symbolize_names: true)[:request])
      section_delimiter = '|'
      # Ignore some sections
      sections.reject! { |section| section[:name] == 'environment_details' }
      section_size = (limit / sections.size) - section_delimiter.size
      sections.map do |section|
        "#{"#{section[:name]}: " if section[:name]}#{one_lining(section[:content])}".ellipsized(section_size)
      end.join('|')
    when 'tool'
      tool_details = JSON.parse(text, symbolize_names: true)
      tool_header =
        case tool_details[:tool]
        when 'readFile'
          "[readFile] - #{tool_details[:path]}"
        when 'listFilesRecursive'
          "[listFilesRecursive] - #{tool_details[:path]}"
        when 'listFilesTopLevel'
          "[listFilesTopLevel] - #{tool_details[:path]}"
        when 'newFileCreated'
          "[newFileCreated] - #{tool_details[:path]}"
        when 'editedExistingFile'
          "[editedExistingFile] - #{tool_details[:path]}"
        when 'searchFiles'
          "[searchFiles] - #{tool_details[:path]} (regex: #{tool_details[:regex]})"
        when 'useSkill'
          "[useSkill] - #{tool_details[:skill_name]}"
        else
          raise NotImplementedError, "Unknown tool @ts #{ts}: #{self}"
        end
      "#{tool_header}#{": #{one_lining(tool_details[:content])}".ellipsized(limit - tool_header.size) if tool_details.key?(:content)}"
    when 'api_req_retried'
      'API request retried'
    when 'command'
      "Command: #{one_lining(text)}"
    when 'command_output'
      "Command output: #{one_lining(text)}"
    when 'diff_error'
      "Diff error: #{one_lining(text)}"
    when 'error_retry'
      "Error retry: #{one_lining(text)}"
    when 'reasoning'
      "Reasoning: #{one_lining(text)}"
    when 'user_feedback'
      "User feedback: #{one_lining(text)}"
    when 'task_progress'
      # Count completed vs total tasks
      completed_tasks = text.scan('- [x]').size
      total_tasks = text.scan(/- \[[ x]\]/).size
      "Task progress: #{completed_tasks}/#{total_tasks} tasks"
    when 'completion_result'
      "Task completed: #{one_lining(text)}"
    when 'error'
      "Error: #{one_lining(text)}"
    else
      raise NotImplementedError, "Unknown say @ts #{ts}: #{self}"
    end
  when 'ask'
    "Ask user: #{
      case ask
      when 'resume_task'
        'Resume task'
      when 'resume_completed_task'
        'Resume completed task'
      when 'api_req_failed'
        details = JSON.parse(text, symbolize_names: true)
        "API request failed - #{details[:code]} - #{one_lining(details[:message])}"
      when 'command_output'
        "Command output - #{one_lining(text)}"
      when 'completion_result'
        'Completion result'
      when 'followup'
        details = JSON.parse(text, symbolize_names: true)
        "Follow-up - #{details[:question]}#{" - Options: #{details[:options].join(', ')}" unless details[:options].nil? || details[:options].empty?}"
      when 'plan_mode_respond'
        details = JSON.parse(text, symbolize_names: true)
        "Plan mode respond - #{one_lining(details[:response])}}"
      when 'tool'
        details = JSON.parse(text, symbolize_names: true)
        tool_name = details.delete(:tool)
        "Use tool - #{tool_name} - #{JSON.dump(details)}}"
      when 'mistake_limit_reached'
        "Mistake limit reached - #{one_lining(text)}}"
      when 'new_task'
        "New task - #{one_lining(text)}"
      else
        raise NotImplementedError, "Unknown ask @ts #{ts}: #{self}"
      end
    }"
  else
    raise NotImplementedError, "Unknown type @ts #{ts}: #{self}"
  end.ellipsized(limit)
end

#tsInteger

Returns Message timestamp.

Returns:

  • (Integer)

    Message timestamp



24
# File 'lib/cline/task_message.rb', line 24

attribute :ts, :integer

#typeString

Returns Message type identifier.

Returns:

  • (String)

    Message type identifier



27
# File 'lib/cline/task_message.rb', line 27

attribute :type, :string

#usageUsage?

Get the usage statistics of this message, if any

Returns:

  • (Usage, nil)

    The usage statistics, or nil if none



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/cline/task_message.rb', line 57

def usage
  return unless type == 'say' && say == 'api_req_started'

  api_details = JSON.parse(text, symbolize_names: true)
  Usage.new(
    **{
      cost: api_details[:cost],
      input_tokens: api_details[:tokensIn],
      output_tokens: api_details[:tokensOut],
      cache_read_tokens: api_details[:cacheReads],
      cache_write_tokens: api_details[:cacheWrites],
      cline_model: cline_models[model_info.model_id]
    }.compact
  )
end