goose-py 0.9.13__tar.gz → 0.9.15__tar.gz

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 (35) hide show
  1. {goose_py-0.9.13 → goose_py-0.9.15}/.stubs/litellm/__init__.pyi +3 -7
  2. {goose_py-0.9.13 → goose_py-0.9.15}/PKG-INFO +1 -1
  3. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/agent.py +1 -5
  4. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/types/agent.py +20 -31
  5. {goose_py-0.9.13 → goose_py-0.9.15}/goose/agent.py +4 -8
  6. {goose_py-0.9.13 → goose_py-0.9.15}/pyproject.toml +1 -1
  7. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_agent.py +3 -2
  8. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_refining.py +6 -5
  9. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_state.py +3 -3
  10. {goose_py-0.9.13 → goose_py-0.9.15}/uv.lock +1 -1
  11. {goose_py-0.9.13 → goose_py-0.9.15}/.envrc +0 -0
  12. {goose_py-0.9.13 → goose_py-0.9.15}/.github/workflows/publish.yml +0 -0
  13. {goose_py-0.9.13 → goose_py-0.9.15}/.gitignore +0 -0
  14. {goose_py-0.9.13 → goose_py-0.9.15}/.python-version +0 -0
  15. {goose_py-0.9.13 → goose_py-0.9.15}/.stubs/jsonpath_ng/__init__.pyi +0 -0
  16. {goose_py-0.9.13 → goose_py-0.9.15}/Makefile +0 -0
  17. {goose_py-0.9.13 → goose_py-0.9.15}/README.md +0 -0
  18. {goose_py-0.9.13 → goose_py-0.9.15}/goose/__init__.py +0 -0
  19. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/conversation.py +0 -0
  20. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/flow.py +0 -0
  21. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/result.py +0 -0
  22. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/state.py +0 -0
  23. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/store.py +0 -0
  24. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/task.py +0 -0
  25. {goose_py-0.9.13 → goose_py-0.9.15}/goose/_internal/types/__init__.py +0 -0
  26. {goose_py-0.9.13 → goose_py-0.9.15}/goose/errors.py +0 -0
  27. {goose_py-0.9.13 → goose_py-0.9.15}/goose/flow.py +0 -0
  28. {goose_py-0.9.13 → goose_py-0.9.15}/goose/py.typed +0 -0
  29. {goose_py-0.9.13 → goose_py-0.9.15}/goose/runs.py +0 -0
  30. {goose_py-0.9.13 → goose_py-0.9.15}/goose/task.py +0 -0
  31. {goose_py-0.9.13 → goose_py-0.9.15}/tests/__init__.py +0 -0
  32. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_downstream_task.py +0 -0
  33. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_hashing.py +0 -0
  34. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_looping.py +0 -0
  35. {goose_py-0.9.13 → goose_py-0.9.15}/tests/test_regenerate.py +0 -0
@@ -1,4 +1,5 @@
1
- from typing import Any, Literal, NotRequired, TypedDict
1
+ from typing import Literal, NotRequired, TypedDict
2
+ from pydantic import BaseModel
2
3
 
3
4
  _LiteLLMGeminiModel = Literal[
4
5
  "vertex_ai/gemini-1.5-flash",
@@ -28,11 +29,6 @@ class _LiteLLMMessage(TypedDict):
28
29
  content: list[_LiteLLMTextMessageContent | _LiteLLMMediaMessageContent]
29
30
  cache_control: NotRequired[_LiteLLMCacheControl]
30
31
 
31
- class _LiteLLMResponseFormat(TypedDict):
32
- type: Literal["json_object"]
33
- response_schema: dict[str, Any] # must be a valid JSON schema
34
- enforce_validation: NotRequired[bool]
35
-
36
32
  class _LiteLLMModelResponseChoiceMessage:
37
33
  role: Literal["assistant"]
38
34
  content: str
@@ -60,7 +56,7 @@ async def acompletion(
60
56
  *,
61
57
  model: _LiteLLMGeminiModel,
62
58
  messages: list[_LiteLLMMessage],
63
- response_format: _LiteLLMResponseFormat | None = None,
59
+ response_format: type[BaseModel] | None = None,
64
60
  max_tokens: int | None = None,
65
61
  temperature: float = 1.0,
66
62
  ) -> ModelResponse: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: goose-py
3
- Version: 0.9.13
3
+ Version: 0.9.15
4
4
  Summary: A tool for AI workflows based on human-computer collaboration and structured output.
5
5
  Author-email: Nash Taylor <nash@chelle.ai>, Joshua Cook <joshua@chelle.ai>, Michael Sankur <michael@chelle.ai>
6
6
  Requires-Python: >=3.12
@@ -153,11 +153,7 @@ class Agent:
153
153
  response = await acompletion(
154
154
  model=model.value,
155
155
  messages=rendered_messages,
156
- response_format={
157
- "type": "json_object",
158
- "response_schema": response_model.model_json_schema(),
159
- "enforce_validation": True,
160
- },
156
+ response_format=response_model,
161
157
  )
162
158
  parsed_response = response_model.model_validate_json(response.choices[0].message.content)
163
159
 
@@ -1,19 +1,8 @@
1
1
  import base64
2
2
  from enum import StrEnum
3
- from typing import Any, Literal, NotRequired, TypedDict
3
+ from typing import Literal, NotRequired, TypedDict
4
4
 
5
- from pydantic import BaseModel, GetCoreSchemaHandler
6
- from pydantic_core import CoreSchema, core_schema
7
-
8
-
9
- class Base64MediaContent(str):
10
- @classmethod
11
- def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
12
- return core_schema.no_info_after_validator_function(cls, handler(str))
13
-
14
- @classmethod
15
- def from_bytes(cls, content: bytes, /) -> "Base64MediaContent":
16
- return cls(base64.b64encode(content).decode())
5
+ from pydantic import BaseModel
17
6
 
18
7
 
19
8
  class AIModel(StrEnum):
@@ -30,7 +19,10 @@ class AIModel(StrEnum):
30
19
  GEMINI_FLASH_2_0 = "gemini/gemini-2.0-flash"
31
20
 
32
21
 
33
- class UserMediaContentType(StrEnum):
22
+ class ContentType(StrEnum):
23
+ # text
24
+ TEXT = "text/plain"
25
+
34
26
  # images
35
27
  JPEG = "image/jpeg"
36
28
  PNG = "image/png"
@@ -64,33 +56,30 @@ class LLMMessage(TypedDict):
64
56
  cache_control: NotRequired[CacheControl]
65
57
 
66
58
 
67
- class TextMessagePart(BaseModel):
68
- text: str
69
-
70
- def render(self) -> LLMTextMessagePart:
71
- return {"type": "text", "text": self.text}
72
-
59
+ class MessagePart(BaseModel):
60
+ content: str
61
+ content_type: ContentType = ContentType.TEXT
73
62
 
74
- class MediaMessagePart(BaseModel):
75
- content_type: UserMediaContentType
76
- content: Base64MediaContent
63
+ @classmethod
64
+ def from_media(cls, *, content: bytes, content_type: ContentType) -> "MessagePart":
65
+ return cls(content=base64.b64encode(content).decode(), content_type=content_type)
77
66
 
78
- def render(self) -> LLMMediaMessagePart:
79
- return {
80
- "type": "image_url",
81
- "image_url": f"data:{self.content_type};base64,{self.content}",
82
- }
67
+ def render(self) -> LLMTextMessagePart | LLMMediaMessagePart:
68
+ if self.content_type == ContentType.TEXT:
69
+ return {"type": "text", "text": self.content}
70
+ else:
71
+ return {"type": "image_url", "image_url": f"data:{self.content_type};base64,{self.content}"}
83
72
 
84
73
 
85
74
  class UserMessage(BaseModel):
86
- parts: list[TextMessagePart | MediaMessagePart]
75
+ parts: list[MessagePart]
87
76
 
88
77
  def render(self) -> LLMMessage:
89
78
  content: LLMMessage = {
90
79
  "role": "user",
91
80
  "content": [part.render() for part in self.parts],
92
81
  }
93
- if any(isinstance(part, MediaMessagePart) for part in self.parts):
82
+ if any(part.content_type != ContentType.TEXT for part in self.parts):
94
83
  content["cache_control"] = {"type": "ephemeral"}
95
84
  return content
96
85
 
@@ -103,7 +92,7 @@ class AssistantMessage(BaseModel):
103
92
 
104
93
 
105
94
  class SystemMessage(BaseModel):
106
- parts: list[TextMessagePart | MediaMessagePart]
95
+ parts: list[MessagePart]
107
96
 
108
97
  def render(self) -> LLMMessage:
109
98
  return {
@@ -2,14 +2,12 @@ from ._internal.agent import AgentResponse, IAgentLogger
2
2
  from ._internal.types.agent import (
3
3
  AIModel,
4
4
  AssistantMessage,
5
- Base64MediaContent,
5
+ ContentType,
6
6
  LLMMediaMessagePart,
7
7
  LLMMessage,
8
8
  LLMTextMessagePart,
9
- MediaMessagePart,
9
+ MessagePart,
10
10
  SystemMessage,
11
- TextMessagePart,
12
- UserMediaContentType,
13
11
  UserMessage,
14
12
  )
15
13
 
@@ -18,13 +16,11 @@ __all__ = [
18
16
  "AIModel",
19
17
  "IAgentLogger",
20
18
  "AssistantMessage",
21
- "Base64MediaContent",
22
19
  "LLMMediaMessagePart",
23
20
  "LLMMessage",
24
21
  "LLMTextMessagePart",
25
- "MediaMessagePart",
26
22
  "SystemMessage",
27
- "TextMessagePart",
28
- "UserMediaContentType",
23
+ "MessagePart",
24
+ "ContentType",
29
25
  "UserMessage",
30
26
  ]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "goose-py"
3
- version = "0.9.13"
3
+ version = "0.9.15"
4
4
  description = "A tool for AI workflows based on human-computer collaboration and structured output."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -4,7 +4,8 @@ import pytest
4
4
  from pytest_mock import MockerFixture
5
5
 
6
6
  from goose import Agent, FlowArguments, TextResult, flow, task
7
- from goose.agent import AgentResponse, AIModel, IAgentLogger, TextMessagePart, UserMessage
7
+ from goose._internal.types.agent import MessagePart
8
+ from goose.agent import AgentResponse, AIModel, IAgentLogger, UserMessage
8
9
 
9
10
 
10
11
  class TestFlowArguments(FlowArguments):
@@ -28,7 +29,7 @@ def mock_litellm(mocker: MockerFixture) -> Mock:
28
29
  @task
29
30
  async def use_agent(*, agent: Agent) -> TextResult:
30
31
  return await agent(
31
- messages=[UserMessage(parts=[TextMessagePart(text="Hello")])],
32
+ messages=[UserMessage(parts=[MessagePart(content="Hello")])],
32
33
  model=AIModel.GEMINI_FLASH_8B,
33
34
  task_name="greet",
34
35
  )
@@ -6,7 +6,8 @@ import pytest
6
6
  from pytest_mock import MockerFixture
7
7
 
8
8
  from goose import Agent, FlowArguments, Result, flow, task
9
- from goose.agent import SystemMessage, TextMessagePart, UserMessage
9
+ from goose._internal.types.agent import MessagePart
10
+ from goose.agent import SystemMessage, UserMessage
10
11
  from goose.errors import Honk
11
12
 
12
13
 
@@ -59,8 +60,8 @@ async def test_refining() -> None:
59
60
  # imagine this is a new process
60
61
  async with sentence.start_run(run_id="1") as second_run:
61
62
  await generate_random_word.refine(
62
- user_message=UserMessage(parts=[TextMessagePart(text="Change it")]),
63
- context=SystemMessage(parts=[TextMessagePart(text="Extra info")]),
63
+ user_message=UserMessage(parts=[MessagePart(content="Change it")]),
64
+ context=SystemMessage(parts=[MessagePart(content="Extra info")]),
64
65
  )
65
66
 
66
67
  random_words = second_run.get_all(task=generate_random_word)
@@ -76,6 +77,6 @@ async def test_refining_before_generate_fails() -> None:
76
77
  with pytest.raises(Honk):
77
78
  async with sentence.start_run(run_id="2"):
78
79
  await generate_random_word.refine(
79
- user_message=UserMessage(parts=[TextMessagePart(text="Change it")]),
80
- context=SystemMessage(parts=[TextMessagePart(text="Extra info")]),
80
+ user_message=UserMessage(parts=[MessagePart(content="Change it")]),
81
+ context=SystemMessage(parts=[MessagePart(content="Extra info")]),
81
82
  )
@@ -6,7 +6,7 @@ import pytest
6
6
  from pytest_mock import MockerFixture
7
7
 
8
8
  from goose import Agent, FlowArguments, Result, flow, task
9
- from goose._internal.types.agent import SystemMessage, TextMessagePart, UserMessage
9
+ from goose._internal.types.agent import MessagePart, SystemMessage, UserMessage
10
10
  from goose.errors import Honk
11
11
 
12
12
 
@@ -74,8 +74,8 @@ async def test_state_undo() -> None:
74
74
  async with with_state.start_run(run_id="2"):
75
75
  await generate_random_word.refine(
76
76
  index=0,
77
- user_message=UserMessage(parts=[TextMessagePart(text="Change it")]),
78
- context=SystemMessage(parts=[TextMessagePart(text="Extra info")]),
77
+ user_message=UserMessage(parts=[MessagePart(content="Change it")]),
78
+ context=SystemMessage(parts=[MessagePart(content="Extra info")]),
79
79
  )
80
80
 
81
81
  async with with_state.start_run(run_id="2") as run:
@@ -234,7 +234,7 @@ wheels = [
234
234
 
235
235
  [[package]]
236
236
  name = "goose-py"
237
- version = "0.9.13"
237
+ version = "0.9.15"
238
238
  source = { editable = "." }
239
239
  dependencies = [
240
240
  { name = "jsonpath-ng" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes