Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d8a39dd
Move my experiments to Marvin
peteryongzhong Apr 3, 2024
74a2cfa
trying to add higher order functions
peteryongzhong Apr 3, 2024
d8e5679
higher order function now "works" because one example said so.
peteryongzhong Apr 4, 2024
22d7246
trying to make higher order type usage = tool usage
peteryongzhong Apr 5, 2024
283a544
add argument that is function as tool usage
peteryongzhong Apr 6, 2024
681e871
formatting
peteryongzhong Apr 6, 2024
ab2050a
adding predicate in preparation for natural language types
peteryongzhong Apr 6, 2024
10f8a35
trying to add contract with two args
peteryongzhong Apr 7, 2024
65ef5b6
keep experimenting with contracts
peteryongzhong Apr 7, 2024
a5ccfb3
change name consistent
peteryongzhong Apr 7, 2024
17e252d
reverting back debugging code
peteryongzhong Apr 7, 2024
3de6402
make predicate more general
peteryongzhong Apr 7, 2024
b063ede
reorg
peteryongzhong Apr 8, 2024
6ae0585
reorg
peteryongzhong Apr 8, 2024
db7cd94
i need to finish this
peteryongzhong Apr 21, 2024
54cf218
added more road maps ahead of final report
peteryongzhong Apr 22, 2024
c43ac08
more matching logic
peteryongzhong Apr 23, 2024
33db56f
more matching logic
peteryongzhong Apr 23, 2024
1c4ab4d
more matching logic
peteryongzhong Apr 23, 2024
48f849c
formatting
peteryongzhong Apr 23, 2024
13d8a13
Finished match pending debugging
peteryongzhong Apr 24, 2024
367808b
match and contracts are more or less finished
peteryongzhong Apr 25, 2024
864fe43
formatting
peteryongzhong Apr 25, 2024
b5ac0d7
preparing for the final report
peteryongzhong Apr 27, 2024
2f59f8e
more final report preparations
peteryongzhong Apr 28, 2024
98e9e3a
Finished Final Report
peteryongzhong Apr 28, 2024
1065d32
fix
peteryongzhong Apr 28, 2024
607bef6
fix
peteryongzhong Apr 28, 2024
72dcbf9
fix
peteryongzhong Apr 28, 2024
025a23a
delete old files
peteryongzhong Apr 28, 2024
2771d42
Update final_report_prompt_engineering1.ipynb
peteryongzhong Aug 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,6 @@ src/marvin/_version.py
# Prefect
.prefect/
.prefect/*.json
.prefectignore
.prefectignore

.idea/
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# IMPORTANT

This is a fork for Marvin for my research. I don't expect this to have wider adoption beyond my own research. Please see [here](ResearchReadMe.md) for some more information.


<p align="center">
<img src="docs/assets/images/heroes/it_hates_me_hero.png" style="width: 95%; height: auto;"/>
</p>
Expand Down
363 changes: 363 additions & 0 deletions ResearchReadMe.md

Large diffs are not rendered by default.

1,297 changes: 1,297 additions & 0 deletions final_report_prompt_engineering1.ipynb

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions just_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This directory will be deleted in due course. Containing experimentations that I wish to track in git.

Look if you want but it's like looking into a man's sock drawer, quite boring objectively, embarrassing subjectively.
135 changes: 135 additions & 0 deletions just_test/func_contract_play.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import functools
from typing import Callable, Any

import pydantic
from annotated_types import Predicate
from dotenv import load_dotenv

from typing import Annotated, get_type_hints, Callable

import marvin
import inspect

from pydantic import BaseModel, Field, type_adapter

import marvin
from marvin.settings import temporary_settings

load_dotenv()


def contract(func: Callable, pre: Callable = None, post: Callable = None) -> Callable:
pre = lambda *args, **kwargs: True if pre is None else pre # noqa E731
post = lambda *args, **kwargs: True if post is None else post # noqa E731

@functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
hints = get_type_hints(func, include_extras=True)
signature = inspect.signature(func)

new_args = []
new_kwargs = {}

# Merge args and kwargs into a single dictionary for easier processing
bound_arguments = signature.bind(*args, **kwargs)
bound_arguments.apply_defaults()
all_arguments = bound_arguments.arguments
for name, value in all_arguments.items():
if name in hints:
# Use TypeAdapter for the parameter annotation to validate and/or coerce the value
adapter = type_adapter.TypeAdapter(
signature.parameters[name].annotation
)
# For TypeAdapter, `validate_python` both validates and coerces the value
coerced_value = adapter.validate_python(value)
# Determine if the parameter should be treated as positional or keyword argument
if name in signature.parameters and signature.parameters[name].kind in (
signature.parameters[name].POSITIONAL_ONLY,
signature.parameters[name].POSITIONAL_OR_KEYWORD,
):
new_args.append(coerced_value)
else:
new_kwargs[name] = coerced_value
else:
# No specific type hint for this parameter, pass it as is
if name in signature.parameters and signature.parameters[name].kind in (
signature.parameters[name].POSITIONAL_ONLY,
signature.parameters[name].POSITIONAL_OR_KEYWORD,
):
new_args.append(value)
else:
new_kwargs[name] = value
if not pre(*new_args, **new_kwargs):
raise pydantic.ValidationError("Failed Pre condition of contract")

# Call the original function with coerced values
result = func(*new_args, **new_kwargs)

if "return" in hints and hints["return"] is not None:
return_adapter = type_adapter.TypeAdapter(hints["return"])
result = return_adapter.validate_python(result)

new_args = [result] + new_args
if not post(*new_args, **new_kwargs):
raise pydantic.ValidationError("Failed post condition of contract")
return result

return wrapper


@contract
def reply_comment(
processed_comment: Annotated[
str,
Predicate(
marvin.val_contract("must not contain words inappropriate for children")
),
],
) -> None:
server.post(processed_comment)


with temporary_settings(ai__text__disable_contract=False):
# print(marvin.val_contract("must add up to 2")(1, 1))
# print(marvin.val_contract("must add up to 2")(1, 2))
print(reply_comment("fuck this shit"))


@contract(
pre=lambda comment, reply: marvin.val_contract(
"the comment and reply must be related and not off topic"
)(comment=comment, reply=reply),
post=lambda result, comment, reply: True,
)
def process_comment(comment: str, reply: str) -> str:
pass


class User:
pass


class Transaction:
pass


@contract(
pre=lambda user, transaction: marvin.val_contract(
"The user needs to be authenticated to operate in the same market as the transaction"
)(user=user, transaction=transaction),
)
def process_payment(
user: Annotated[
User, Predicate(marvin.val_contract("User should be eligible for purchases"))
],
transaction: Annotated[
Transaction,
Predicate(
marvin.val_contract(
"The transaction must not involved illicit drugs or other items banned in PA"
)
),
],
) -> None:
# code to process the transaction
pass
120 changes: 120 additions & 0 deletions just_test/higher_order_funcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import functools
from typing import Callable, Any, Optional, List

import pydantic
from annotated_types import Predicate
from dotenv import load_dotenv

load_dotenv()

from typing import Annotated, get_type_hints, Callable

import marvin
import inspect

from pydantic import BaseModel, Field, type_adapter, schema_json_of

import marvin
from marvin.settings import temporary_settings


class NaturalLangType(BaseModel):
other_information: Optional[str] = Field(
default=None,
description="Other information about the current data that could be "
"relevant but is not otherwise captured by the other fields",
)

@classmethod
def natural_lang_constraints(cls) -> List[str]:
"""
This is a function where all child classes should override if they wish
to declare additional natural language constraints. Note that the overridden class must
call this method on the super() object to ensure that all constraints are populated appropriately
from the parents unless explicitly overridden.
"""
# super().natural_lang_constraints()
return ["hi"]

def func(self):
return self.__class__.natural_lang_constraints()


class Sad(NaturalLangType):
@classmethod
def natural_lang_constraints(cls) -> List[str]:
existing = super().natural_lang_constraints()
return existing + ["hello"]


print(Sad.natural_lang_constraints())
print(Sad().func())


#
# @marvin.fn
# def rating_for_customer(customer_profile: str) -> Callable[[str], int]:
# """
# Args:
# customer_profile: the preferences of the customer
# Returns:
# a function that specializes on the customer_profile to give a rating of a product between 1 to 10.
# """
# pass
#
#


#
#
# class Location(BaseModel):
# city: str = Field(description="City of life ")
# state: str = Field(description="State of affairs")
# comment: Annotated[
# str,
# Predicate(
# marvin.val_contract("must not contain words inappropriate for children")
# ),
# ]
#
#
# print(Location.model_json_schema())
#
#
def weather_at_city(city: str) -> str:
if city == "San Francisco":
return "Sunny and bright"
if city == "Los Angeles":
return "Cold and Cloudy"


#
#
# @marvin.fn
# def pleasantness(attraction: str, weather_func: Callable[[str], str]) -> str:
# """
# Args:
# attraction: the name of the attraction in some place
# weather_func: a function that get the weather at a particular **city** that the attraction is located.
# Returns:
# How pleasant the attraction will likely be given the weather between 0 and 10
# """
# pass
#
#
# # the weather in SF is really good rn, LA not so much
# pleasantness("The Golden Gate Bridge", weather_at_city) # return 8
# pleasantness("Hollywood Sign", weather_at_city) # return 2
#
#
# application_profile = Profile(
# name="Adam Smith",
# education="Bachelor's in Data Science",
# projects=["Building my own neural network at SpaceX", ...],
# )
# marvin.match(
# application_profile,
# ("Strong Experience in Data Science Particularly Feature Engineering", lambda: ...),
# ("Have a degree in related field, but lacks real world projects", lambda: ...),
# ("No relevant or very little relevant experience ", lambda: send_rejection_email()),
# )
114 changes: 114 additions & 0 deletions just_test/natural_lang_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from functools import partial
from typing import Callable, Any

import pydantic
from annotated_types import Predicate
from dotenv import load_dotenv

load_dotenv()
from typing import Annotated, get_type_hints, Callable

import marvin
import inspect

from pydantic import BaseModel, Field, type_adapter

import marvin
from marvin.settings import temporary_settings


@marvin.func_contract(
pre=lambda comment, reply: marvin.val_contract(
"the comment and reply must be somewhat related"
)(comment=comment, reply=reply)
)
def process_comment(comment: str, reply: str) -> str:
return f"comment: {comment}\nreply: {reply}"


# with temporary_settings(ai__text__disable_contract=False):
# try:
# process_comment("This apple is great!", "IKEA stock is down a lot")
# except Exception as e:
# print(e)
# print(process_comment("This apple is great!", "I agree, but the apple is very sweet and so could be unhealthy"))


@marvin.func_contract
def reply_comment(
processed_comment: Annotated[
str,
Predicate(
marvin.val_contract("must not contain words inappropriate for children")
),
],
) -> None:
print("The comment passed validation and is sent to the server")


with temporary_settings(ai__text__disable_contract=False):
print("Try First Reply with Illegal Arguments")
try:
reply_comment("fuck this shit")
except Exception as e:
print("The first call is flagged as a contract violation")
print(e)
try:
reply_comment("The sky is beautiful today")
except Exception as e:
print("The second call is flagged as a contract violation")
print(e)


class Pilot(marvin.NaturalLangType):
id: int
name: str
plane_model: str
certificate: str
airport: str


class AdvancedPilot(Pilot):
@classmethod
def natural_lang_constraints(cls) -> List[str]:
existing = super().natural_lang_constraints()
new_constraints = [
"The pilot must hold the appropriate certificate for the plane_model, "
+ 'which should also be a plane that is considered "big" with paid passengers'
]
return existing + new_constraints


marvin.match(
"Noah Singer, employee number 321, is a Boeing 747 Pilot "
"holding an Airline Transport Pilot with 1000 hours of operations. "
"He mainly flies from KPIT. ",
(AdvancedPilot, lambda pilot: print(pilot)),
fall_through=lambda : print("No Advanced Pilot found")
)


# marvin.match(
# "Peter Zhong, employee number 453 is a student pilot"
# "flying out of KPJC with 6 hours of experience mainly in Piper Warrior",
# (AdvancedPilot, lambda pilot: print(pilot)),
# fall_through=lambda: print("No Advanced Pilot found"),
# )


# marvin.match(
# "Alexa up the sound by 10 points will you? ",
# ("Play Music by {artist}", lambda artist: artist),
# ("Volume increase by {volume_up} units", lambda volume_up: print("System: Increasing Volume by 10 pts")),
# ("Lights on", lambda: True),
# ("Lights off", lambda: True),
# (AdvancedPilot, lambda pilot: print(pilot)),
# )

# marvin.match(
# "The recipe requires 1. Eggs 2. Tomatoes 3. Pineapples 4. Salt 5. Pepper",
# (list, lambda ls: print(ls))
# )

if __name__ == "__main__":
pass
Loading