Skip to content

Commit

Permalink
Merge pull request #59 from bmritz/48-allow-function-calls-with-non-k…
Browse files Browse the repository at this point in the history
…eyword-args

closes #47: Add in the ability to call ghostfunctions with non-keyword arguments
  • Loading branch information
bmritz authored May 4, 2023
2 parents 9847096 + 461a26a commit 5bfc53a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/ai_ghostfunctions/ghostfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@


def _make_chatgpt_message_from_function(
f: Callable[..., Any], **kwargs: Any
f: Callable[..., Any], *args: Any, **kwargs: Any
) -> Message:
sig = inspect.signature(f)
if args:
params = list(sig.parameters)
for i, arg in enumerate(args):
kwargs[params[i]] = arg
if not f.__doc__:
raise ValueError("The function must have a docstring.")
prompt = (
Expand All @@ -41,7 +45,9 @@ def _make_chatgpt_message_from_function(
return Message(role=USER, content=prompt)


def _default_prompt_creation(f: Callable[..., Any], **kwargs: Any) -> List[Message]:
def _default_prompt_creation(
f: Callable[..., Any], *args: Any, **kwargs: Any
) -> List[Message]:
return [
Message(
role=SYSTEM,
Expand All @@ -64,7 +70,7 @@ def _default_prompt_creation(f: Callable[..., Any], **kwargs: Any) -> List[Messa
" I will return the output, and nothing else."
),
),
_make_chatgpt_message_from_function(f, **kwargs),
_make_chatgpt_message_from_function(f, *args, **kwargs),
]


Expand Down Expand Up @@ -148,8 +154,8 @@ def ghostfunction(
return_type_annotation = get_type_hints(function)["return"]

@wraps(function)
def wrapper(**kwargs_inner: Any) -> Any:
prompt = prompt_function(function, **kwargs_inner) # type: ignore[arg-type]
def wrapper(*args_inner: Any, **kwargs_inner: Any) -> Any:
prompt = prompt_function(function, *args_inner, **kwargs_inner) # type: ignore[arg-type]
ai_result = ai_callable(messages=prompt, **kwargs) # type: ignore[misc]
return _parse_ai_result(
ai_result=ai_result, expected_return_type=return_type_annotation
Expand Down
33 changes: 33 additions & 0 deletions tests/test_ghostfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,39 @@ def generate_n_random_words(n: int, startswith: str) -> annotation:
assert result == expected_result


@pytest.mark.parametrize(
"expected_result,annotation",
[
("return a string", str),
],
)
def test_ghostfunction_can_be_called_with_positional_arguments(
expected_result: Any, annotation: Any
) -> None:
mock_return_result = str(expected_result)

mock_callable = Mock(
return_value=openai.openai_object.OpenAIObject.construct_from(
{"choices": [{"message": {"content": mock_return_result}}]}
)
)
with patch.object(
ai_ghostfunctions.ghostfunctions,
"_default_ai_callable",
return_value=mock_callable,
):

@ghostfunction
def generate_n_random_words(n: int, startswith: str) -> annotation:
"""Return a list of `n` random words that start with `startswith`."""
pass

result = generate_n_random_words(5, "goo")
result2 = generate_n_random_words(5, startswith="goo")

assert result == result2 == expected_result


def test_ghostfunction_decorator_errors_if_no_return_type_annotation() -> None:
expected_result = "returned value from openai"

Expand Down

0 comments on commit 5bfc53a

Please sign in to comment.