goose-py 0.3.6__py3-none-any.whl → 0.3.8__py3-none-any.whl

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.
goose/agent.py CHANGED
@@ -150,12 +150,20 @@ class AgentResponse[R: BaseModel](BaseModel):
150
150
  @computed_field
151
151
  @property
152
152
  def input_cost(self) -> float:
153
- return self.INPUT_CENTS_PER_MILLION_TOKENS[self.model] * self.input_tokens
153
+ return (
154
+ self.INPUT_CENTS_PER_MILLION_TOKENS[self.model]
155
+ * self.input_tokens
156
+ / 1_000_000
157
+ )
154
158
 
155
159
  @computed_field
156
160
  @property
157
161
  def output_cost(self) -> float:
158
- return self.OUTPUT_CENTS_PER_MILLION_TOKENS[self.model] * self.output_tokens
162
+ return (
163
+ self.OUTPUT_CENTS_PER_MILLION_TOKENS[self.model]
164
+ * self.output_tokens
165
+ / 1_000_000
166
+ )
159
167
 
160
168
  @computed_field
161
169
  @property
goose/flow.py CHANGED
@@ -12,7 +12,7 @@ from typing import (
12
12
  overload,
13
13
  )
14
14
 
15
- from pydantic import BaseModel, ConfigDict, field_validator
15
+ from pydantic import BaseModel, ConfigDict
16
16
 
17
17
  from goose.agent import (
18
18
  Agent,
@@ -32,51 +32,34 @@ class Result(BaseModel):
32
32
  model_config = ConfigDict(frozen=True)
33
33
 
34
34
 
35
- class GooseResponse[R: Result](BaseModel):
36
- result: R
37
-
38
-
39
35
  class Conversation[R: Result](BaseModel):
40
- messages: list[UserMessage | GooseResponse[R]]
36
+ user_messages: list[UserMessage]
37
+ result_messages: list[R]
41
38
  context: SystemMessage | None = None
42
39
 
43
- @field_validator("messages")
44
- def alternates_starting_with_result(
45
- cls, messages: list[UserMessage | GooseResponse[R]]
46
- ) -> list[UserMessage | GooseResponse[R]]:
47
- if len(messages) == 0:
48
- return messages
49
- elif isinstance(messages[0], UserMessage):
50
- raise Honk(
51
- "User cannot start a conversation on a Task, must begin with a Result"
52
- )
53
-
54
- last_message_type: type[UserMessage | GooseResponse[R]] = type(messages[0])
55
- for message in messages[1:]:
56
- if isinstance(message, last_message_type):
57
- raise Honk(
58
- "Conversation must alternate between User and Result messages"
59
- )
60
- last_message_type = type(message)
61
-
62
- return messages
63
-
64
40
  @property
65
41
  def awaiting_response(self) -> bool:
66
- return len(self.messages) % 2 == 0
42
+ return len(self.user_messages) == len(self.result_messages)
67
43
 
68
44
  def render(self) -> list[LLMMessage]:
69
45
  messages: list[LLMMessage] = []
70
46
  if self.context is not None:
71
47
  messages.append(self.context.render())
72
48
 
73
- for message in self.messages:
74
- if isinstance(message, UserMessage):
75
- messages.append(message.render())
76
- else:
77
- messages.append(
78
- AssistantMessage(text=message.result.model_dump_json()).render()
79
- )
49
+ for message_index in range(len(self.user_messages)):
50
+ messages.append(
51
+ AssistantMessage(
52
+ text=self.result_messages[message_index].model_dump_json()
53
+ ).render()
54
+ )
55
+ messages.append(self.user_messages[message_index].render())
56
+
57
+ if len(self.result_messages) > len(self.user_messages):
58
+ messages.append(
59
+ AssistantMessage(
60
+ text=self.result_messages[-1].model_dump_json()
61
+ ).render()
62
+ )
80
63
 
81
64
  return messages
82
65
 
@@ -93,12 +76,11 @@ class NodeState[ResultT: Result](BaseModel):
93
76
 
94
77
  @property
95
78
  def result(self) -> ResultT:
96
- last_message = self.conversation.messages[-1]
97
- if isinstance(last_message, GooseResponse):
98
- return last_message.result
99
- else:
79
+ if len(self.conversation.result_messages) == 0:
100
80
  raise Honk("Node awaiting response, has no result")
101
81
 
82
+ return self.conversation.result_messages[-1]
83
+
102
84
  def set_context(self, *, context: SystemMessage) -> Self:
103
85
  self.conversation.context = context
104
86
  return self
@@ -110,19 +92,16 @@ class NodeState[ResultT: Result](BaseModel):
110
92
  new_input_hash: int | None = None,
111
93
  overwrite: bool = False,
112
94
  ) -> Self:
113
- if overwrite:
114
- if len(self.conversation.messages) == 0:
115
- self.conversation.messages.append(GooseResponse(result=result))
116
- else:
117
- self.conversation.messages[-1] = GooseResponse(result=result)
95
+ if overwrite and len(self.conversation.result_messages) > 0:
96
+ self.conversation.result_messages[-1] = result
118
97
  else:
119
- self.conversation.messages.append(GooseResponse(result=result))
98
+ self.conversation.result_messages.append(result)
120
99
  if new_input_hash is not None:
121
100
  self.last_input_hash = new_input_hash
122
101
  return self
123
102
 
124
103
  def add_user_message(self, *, message: UserMessage) -> Self:
125
- self.conversation.messages.append(message)
104
+ self.conversation.user_messages.append(message)
126
105
  return self
127
106
 
128
107
 
@@ -178,7 +157,9 @@ class FlowRun:
178
157
  return NodeState[task.result_type](
179
158
  task_name=task.name,
180
159
  index=index or 0,
181
- conversation=Conversation[task.result_type](messages=[]),
160
+ conversation=Conversation[task.result_type](
161
+ user_messages=[], result_messages=[]
162
+ ),
182
163
  last_input_hash=0,
183
164
  )
184
165
 
@@ -314,10 +295,6 @@ class Task[**P, R: Result]:
314
295
  state.add_result(result=result, new_input_hash=input_hash, overwrite=True)
315
296
  return result
316
297
  else:
317
- if not isinstance(state.conversation.messages[-1], GooseResponse):
318
- raise Honk(
319
- "Conversation must alternate between User and Result messages"
320
- )
321
298
  return state.result
322
299
 
323
300
  async def jam(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goose-py
3
- Version: 0.3.6
3
+ Version: 0.3.8
4
4
  Summary: A tool for AI workflows based on human-computer collaboration and structured output.
5
5
  Home-page: https://github.com/chelle-ai/goose
6
6
  Keywords: ai,yaml,configuration,llm
@@ -0,0 +1,9 @@
1
+ goose/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ goose/agent.py,sha256=AyAQqgvG-SgYD4O8-yRHfJ3oJpk7zRMdSVkqVdGii4A,7770
3
+ goose/errors.py,sha256=-0OyZQJWYTRw5YgnCB2_uorVaUsL6Z0QYQO2FqzCiyg,32
4
+ goose/flow.py,sha256=08RlviG3VeU1hNRXtAWUrBwKmsd6TB-7ECC_ykPF3O0,11710
5
+ goose/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ goose/store.py,sha256=6IIGkIYt6CWiNENi2gaS9C0Z-62ia-Qdz29HhCg8njw,698
7
+ goose_py-0.3.8.dist-info/METADATA,sha256=rRzWY9BepvDUV96gYPY52nSdd_pulwLMa3pVFq7qGDA,1106
8
+ goose_py-0.3.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
9
+ goose_py-0.3.8.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- goose/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- goose/agent.py,sha256=5S9p_EclF97F_TTSP61KJFk5yxFqSJ5QxCsnbb-wNEI,7650
3
- goose/errors.py,sha256=-0OyZQJWYTRw5YgnCB2_uorVaUsL6Z0QYQO2FqzCiyg,32
4
- goose/flow.py,sha256=_kSNB9CnDoduOm0YLLq0q5kzkUrtNEtvAx7A9D0_YkU,12605
5
- goose/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- goose/store.py,sha256=6IIGkIYt6CWiNENi2gaS9C0Z-62ia-Qdz29HhCg8njw,698
7
- goose_py-0.3.6.dist-info/METADATA,sha256=kAU3G6iWj09wiISWH5-ripnLwbiln6qNrlROqwPHM10,1106
8
- goose_py-0.3.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
9
- goose_py-0.3.6.dist-info/RECORD,,