prediction-market-agent-tooling 0.51.0__tar.gz → 0.52.0__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.
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/PKG-INFO +1 -1
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/agent.py +5 -0
- prediction_market_agent_tooling-0.52.0/prediction_market_agent_tooling/markets/metaculus/data_models.py +104 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +5 -6
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/data_models.py +9 -1
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +165 -73
- prediction_market_agent_tooling-0.52.0/prediction_market_agent_tooling/tools/is_invalid.py +92 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/utils.py +3 -1
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/pyproject.toml +1 -1
- prediction_market_agent_tooling-0.51.0/prediction_market_agent_tooling/markets/metaculus/data_models.py +0 -97
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/README.md +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/config.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/betting_strategy.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/jobs.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/loggers.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/agent_market.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/markets.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/omen.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/datetime_utc.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/google.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/tavily_storage/tavily_models.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/tavily_storage/tavily_storage.py +0 -0
- {prediction_market_agent_tooling-0.51.0 → prediction_market_agent_tooling-0.52.0}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -66,6 +66,7 @@ from prediction_market_agent_tooling.monitor.monitor_app import (
|
|
66
66
|
)
|
67
67
|
from prediction_market_agent_tooling.tools.hexbytes_custom import HexBytes
|
68
68
|
from prediction_market_agent_tooling.tools.ipfs.ipfs_handler import IPFSHandler
|
69
|
+
from prediction_market_agent_tooling.tools.is_invalid import is_invalid
|
69
70
|
from prediction_market_agent_tooling.tools.is_predictable import is_predictable_binary
|
70
71
|
from prediction_market_agent_tooling.tools.langfuse_ import langfuse_context, observe
|
71
72
|
from prediction_market_agent_tooling.tools.utils import DatetimeUTC, utcnow
|
@@ -295,6 +296,7 @@ class DeployableTraderAgent(DeployableAgent):
|
|
295
296
|
bet_on_n_markets_per_run: int = 1
|
296
297
|
min_required_balance_to_operate: xDai | None = xdai_type(1)
|
297
298
|
min_balance_to_keep_in_native_currency: xDai | None = xdai_type(0.1)
|
299
|
+
allow_invalid_questions: bool = False
|
298
300
|
|
299
301
|
def __init__(
|
300
302
|
self,
|
@@ -403,6 +405,9 @@ class DeployableTraderAgent(DeployableAgent):
|
|
403
405
|
if not is_predictable_binary(market.question):
|
404
406
|
return False
|
405
407
|
|
408
|
+
if not self.allow_invalid_questions and is_invalid(market.question):
|
409
|
+
return False
|
410
|
+
|
406
411
|
return True
|
407
412
|
|
408
413
|
def answer_binary_market(self, market: AgentMarket) -> ProbabilisticAnswer | None:
|
@@ -0,0 +1,104 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import BaseModel
|
5
|
+
|
6
|
+
from prediction_market_agent_tooling.gtypes import Probability
|
7
|
+
from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
8
|
+
|
9
|
+
|
10
|
+
class QuestionType(str, Enum):
|
11
|
+
binary = "binary"
|
12
|
+
|
13
|
+
|
14
|
+
class AggregationItem(BaseModel):
|
15
|
+
start_time: DatetimeUTC
|
16
|
+
end_time: DatetimeUTC | None
|
17
|
+
forecast_values: list[float] | None
|
18
|
+
forecaster_count: int
|
19
|
+
interval_lower_bounds: list[float] | None
|
20
|
+
centers: list[float] | None
|
21
|
+
interval_upper_bounds: list[float] | None
|
22
|
+
means: list[float] | None
|
23
|
+
histogram: list[float] | None
|
24
|
+
|
25
|
+
|
26
|
+
class Aggregation(BaseModel):
|
27
|
+
history: list[AggregationItem]
|
28
|
+
latest: AggregationItem | None
|
29
|
+
score_data: dict[str, Any]
|
30
|
+
|
31
|
+
|
32
|
+
class Aggregations(BaseModel):
|
33
|
+
recency_weighted: Aggregation
|
34
|
+
unweighted: Aggregation
|
35
|
+
single_aggregation: Aggregation
|
36
|
+
metaculus_prediction: Aggregation
|
37
|
+
|
38
|
+
|
39
|
+
class MyForecast(BaseModel):
|
40
|
+
start_time: DatetimeUTC
|
41
|
+
end_time: DatetimeUTC | None
|
42
|
+
forecast_values: list[float] | None
|
43
|
+
interval_lower_bounds: list[float] | None
|
44
|
+
centers: list[float] | None
|
45
|
+
interval_upper_bounds: list[float] | None
|
46
|
+
|
47
|
+
|
48
|
+
class MyAggregation(BaseModel):
|
49
|
+
history: list[MyForecast]
|
50
|
+
latest: MyForecast | None
|
51
|
+
score_data: dict[str, Any]
|
52
|
+
|
53
|
+
|
54
|
+
class Question(BaseModel):
|
55
|
+
aggregations: Aggregations
|
56
|
+
my_forecasts: MyAggregation
|
57
|
+
type: QuestionType
|
58
|
+
possibilities: dict[str, str] | None
|
59
|
+
|
60
|
+
|
61
|
+
class MetaculusQuestion(BaseModel):
|
62
|
+
id: int
|
63
|
+
author_id: int
|
64
|
+
author_username: str
|
65
|
+
title: str
|
66
|
+
created_at: DatetimeUTC
|
67
|
+
published_at: DatetimeUTC
|
68
|
+
scheduled_close_time: DatetimeUTC
|
69
|
+
scheduled_resolve_time: DatetimeUTC
|
70
|
+
user_permission: str
|
71
|
+
comment_count: int
|
72
|
+
question: Question
|
73
|
+
# TODO add the rest of the fields https://github.com/gnosis/prediction-market-agent-tooling/issues/301
|
74
|
+
|
75
|
+
@property
|
76
|
+
def page_url(self) -> str:
|
77
|
+
return f"https://www.metaculus.com/questions/{self.id}/"
|
78
|
+
|
79
|
+
@property
|
80
|
+
def p_yes(self) -> Probability:
|
81
|
+
if self.question.type != QuestionType.binary:
|
82
|
+
raise ValueError(f"Only binary markets can have p_yes.")
|
83
|
+
if (
|
84
|
+
self.question.aggregations.recency_weighted is None
|
85
|
+
or self.question.aggregations.recency_weighted.latest is None
|
86
|
+
or self.question.aggregations.recency_weighted.latest.forecast_values
|
87
|
+
is None
|
88
|
+
):
|
89
|
+
# If no value is provided (i.e. the question is new and has not been answered yet), we default to 0.5.
|
90
|
+
return Probability(0.5)
|
91
|
+
if len(self.question.aggregations.recency_weighted.latest.forecast_values) != 2:
|
92
|
+
raise ValueError(
|
93
|
+
f"Invalid logic, assumed that binary markets will have two forecasts, got: {self.question.aggregations.recency_weighted.latest.forecast_values}"
|
94
|
+
)
|
95
|
+
# Experimentally figured out that they store "Yes" at index 1.
|
96
|
+
return Probability(
|
97
|
+
self.question.aggregations.recency_weighted.latest.forecast_values[1]
|
98
|
+
)
|
99
|
+
|
100
|
+
|
101
|
+
class MetaculusQuestions(BaseModel):
|
102
|
+
next: str | None
|
103
|
+
previous: str | None
|
104
|
+
results: list[MetaculusQuestion]
|
@@ -37,13 +37,12 @@ class MetaculusAgentMarket(AgentMarket):
|
|
37
37
|
question=model.title,
|
38
38
|
outcomes=[],
|
39
39
|
resolution=None,
|
40
|
-
current_p_yes=
|
41
|
-
created_time=model.
|
42
|
-
close_time=model.
|
43
|
-
url=model.
|
40
|
+
current_p_yes=model.p_yes,
|
41
|
+
created_time=model.created_at,
|
42
|
+
close_time=model.scheduled_close_time,
|
43
|
+
url=model.page_url,
|
44
44
|
volume=None,
|
45
|
-
have_predicted=model.
|
46
|
-
and len(model.my_predictions.predictions) > 0,
|
45
|
+
have_predicted=model.question.my_forecasts.latest is not None,
|
47
46
|
outcome_token_pool=None,
|
48
47
|
)
|
49
48
|
|
@@ -73,6 +73,10 @@ class Question(BaseModel):
|
|
73
73
|
answerFinalizedTimestamp: t.Optional[DatetimeUTC] = None
|
74
74
|
currentAnswer: t.Optional[str] = None
|
75
75
|
|
76
|
+
@property
|
77
|
+
def question_id(self) -> HexBytes:
|
78
|
+
return self.id
|
79
|
+
|
76
80
|
@property
|
77
81
|
def question_raw(self) -> str:
|
78
82
|
# Based on https://github.com/protofire/omen-exchange/blob/2cfdf6bfe37afa8b169731d51fea69d42321d66c/app/src/hooks/graph/useGraphMarketMakerData.tsx#L217.
|
@@ -583,7 +587,7 @@ class RealityQuestion(BaseModel):
|
|
583
587
|
historyHash: HexBytes | None
|
584
588
|
updatedTimestamp: int
|
585
589
|
contentHash: HexBytes
|
586
|
-
questionId: HexBytes
|
590
|
+
questionId: HexBytes # This is the `id` on question from omen subgraph.
|
587
591
|
answerFinalizedTimestamp: int
|
588
592
|
currentScheduledFinalizationTimestamp: int
|
589
593
|
|
@@ -660,6 +664,10 @@ def format_realitio_question(
|
|
660
664
|
template_id: int,
|
661
665
|
) -> str:
|
662
666
|
"""If you add a new template id here, also add to the parsing function below."""
|
667
|
+
|
668
|
+
# Escape characters for JSON troubles on Reality.eth.
|
669
|
+
question = question.replace('"', '\\"')
|
670
|
+
|
663
671
|
if template_id == 2:
|
664
672
|
return "␟".join(
|
665
673
|
[
|
@@ -218,30 +218,45 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
218
218
|
|
219
219
|
def _build_where_statements(
|
220
220
|
self,
|
221
|
-
creator:
|
222
|
-
creator_in: t.
|
223
|
-
outcomes: list[str]
|
224
|
-
created_after:
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
221
|
+
creator: HexAddress | None,
|
222
|
+
creator_in: t.Sequence[HexAddress] | None,
|
223
|
+
outcomes: list[str],
|
224
|
+
created_after: DatetimeUTC | None,
|
225
|
+
question_opened_before: DatetimeUTC | None,
|
226
|
+
question_opened_after: DatetimeUTC | None,
|
227
|
+
question_finalized_before: DatetimeUTC | None,
|
228
|
+
question_finalized_after: DatetimeUTC | None,
|
229
|
+
question_with_answers: bool | None,
|
230
|
+
question_id: HexBytes | None,
|
231
|
+
question_id_in: list[HexBytes] | None,
|
232
|
+
question_current_answer_before: DatetimeUTC | None,
|
233
|
+
question_excluded_titles: set[str] | None,
|
234
|
+
resolved: bool | None,
|
235
|
+
liquidity_bigger_than: Wei | None,
|
236
|
+
condition_id_in: list[HexBytes] | None,
|
237
|
+
id_in: list[str] | None,
|
238
|
+
collateral_token_address_in: tuple[ChecksumAddress, ...] | None,
|
239
|
+
category: str | None,
|
236
240
|
) -> dict[str, t.Any]:
|
237
241
|
where_stms: dict[str, t.Any] = {
|
238
242
|
"isPendingArbitration": False,
|
239
243
|
"outcomes": outcomes,
|
240
244
|
"title_not": None,
|
241
|
-
"question_": {},
|
242
245
|
"condition_": {},
|
243
246
|
}
|
244
247
|
|
248
|
+
where_stms["question_"] = self.get_omen_question_filters(
|
249
|
+
question_id=question_id,
|
250
|
+
opened_before=question_opened_before,
|
251
|
+
opened_after=question_opened_after,
|
252
|
+
finalized_before=question_finalized_before,
|
253
|
+
finalized_after=question_finalized_after,
|
254
|
+
with_answers=question_with_answers,
|
255
|
+
current_answer_before=question_current_answer_before,
|
256
|
+
question_id_in=question_id_in,
|
257
|
+
excluded_titles=question_excluded_titles,
|
258
|
+
)
|
259
|
+
|
245
260
|
if collateral_token_address_in:
|
246
261
|
where_stms["collateralToken_in"] = [
|
247
262
|
x.lower() for x in collateral_token_address_in
|
@@ -256,11 +271,6 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
256
271
|
if created_after:
|
257
272
|
where_stms["creationTimestamp_gt"] = to_int_timestamp(created_after)
|
258
273
|
|
259
|
-
if opened_before:
|
260
|
-
where_stms["question_"]["openingTimestamp_lt"] = to_int_timestamp(
|
261
|
-
opened_before
|
262
|
-
)
|
263
|
-
|
264
274
|
if liquidity_bigger_than is not None:
|
265
275
|
where_stms["liquidityParameter_gt"] = liquidity_bigger_than
|
266
276
|
|
@@ -277,30 +287,9 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
277
287
|
else:
|
278
288
|
where_stms["resolutionTimestamp"] = None
|
279
289
|
|
280
|
-
if opened_after:
|
281
|
-
where_stms["question_"]["openingTimestamp_gt"] = to_int_timestamp(
|
282
|
-
opened_after
|
283
|
-
)
|
284
|
-
|
285
|
-
if finalized_before:
|
286
|
-
where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
|
287
|
-
finalized_before
|
288
|
-
)
|
289
|
-
|
290
|
-
if finalized_after:
|
291
|
-
where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
|
292
|
-
finalized_after
|
293
|
-
)
|
294
|
-
|
295
290
|
if category:
|
296
291
|
where_stms["category"] = category
|
297
292
|
|
298
|
-
# `excluded_question_titles` can not be an empty list, otherwise the API bugs out and returns nothing.
|
299
|
-
excluded_question_titles = [""]
|
300
|
-
if excluded_questions:
|
301
|
-
excluded_question_titles = [i for i in excluded_questions]
|
302
|
-
|
303
|
-
where_stms["question_"]["title_not_in"] = excluded_question_titles
|
304
293
|
return where_stms
|
305
294
|
|
306
295
|
def _build_sort_params(
|
@@ -378,12 +367,12 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
378
367
|
return self.get_omen_binary_markets(
|
379
368
|
limit=limit,
|
380
369
|
resolved=resolved,
|
381
|
-
|
370
|
+
question_opened_after=opened_after,
|
382
371
|
liquidity_bigger_than=liquidity_bigger_than,
|
383
372
|
sort_direction=sort_direction,
|
384
373
|
sort_by_field=sort_by_field,
|
385
374
|
created_after=created_after,
|
386
|
-
|
375
|
+
question_excluded_titles=excluded_questions,
|
387
376
|
collateral_token_address_in=collateral_token_address_in,
|
388
377
|
category=category,
|
389
378
|
)
|
@@ -391,18 +380,22 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
391
380
|
def get_omen_binary_markets(
|
392
381
|
self,
|
393
382
|
limit: t.Optional[int],
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
383
|
+
creator: HexAddress | None = None,
|
384
|
+
creator_in: t.Sequence[HexAddress] | None = None,
|
385
|
+
created_after: DatetimeUTC | None = None,
|
386
|
+
question_opened_before: DatetimeUTC | None = None,
|
387
|
+
question_opened_after: DatetimeUTC | None = None,
|
388
|
+
question_finalized_before: DatetimeUTC | None = None,
|
389
|
+
question_finalized_after: DatetimeUTC | None = None,
|
390
|
+
question_with_answers: bool | None = None,
|
391
|
+
question_id: HexBytes | None = None,
|
392
|
+
question_id_in: list[HexBytes] | None = None,
|
393
|
+
question_current_answer_before: DatetimeUTC | None = None,
|
394
|
+
question_excluded_titles: set[str] | None = None,
|
399
395
|
resolved: bool | None = None,
|
400
|
-
creator: t.Optional[HexAddress] = None,
|
401
|
-
creator_in: t.Optional[t.Sequence[HexAddress]] = None,
|
402
396
|
liquidity_bigger_than: Wei | None = None,
|
403
397
|
condition_id_in: list[HexBytes] | None = None,
|
404
398
|
id_in: list[str] | None = None,
|
405
|
-
excluded_questions: set[str] | None = None, # question titles
|
406
399
|
sort_by_field: FieldPath | None = None,
|
407
400
|
sort_direction: str | None = None,
|
408
401
|
outcomes: list[str] = OMEN_BINARY_MARKET_OUTCOMES,
|
@@ -419,14 +412,18 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
419
412
|
creator_in=creator_in,
|
420
413
|
outcomes=outcomes,
|
421
414
|
created_after=created_after,
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
415
|
+
question_opened_before=question_opened_before,
|
416
|
+
question_opened_after=question_opened_after,
|
417
|
+
question_finalized_before=question_finalized_before,
|
418
|
+
question_finalized_after=question_finalized_after,
|
419
|
+
question_with_answers=question_with_answers,
|
420
|
+
question_id=question_id,
|
421
|
+
question_id_in=question_id_in,
|
422
|
+
question_current_answer_before=question_current_answer_before,
|
423
|
+
question_excluded_titles=question_excluded_titles,
|
426
424
|
resolved=resolved,
|
427
425
|
condition_id_in=condition_id_in,
|
428
426
|
id_in=id_in,
|
429
|
-
excluded_questions=excluded_questions,
|
430
427
|
liquidity_bigger_than=liquidity_bigger_than,
|
431
428
|
collateral_token_address_in=collateral_token_address_in,
|
432
429
|
category=category,
|
@@ -644,15 +641,21 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
644
641
|
|
645
642
|
@staticmethod
|
646
643
|
def get_reality_question_filters(
|
647
|
-
user: HexAddress | None
|
648
|
-
claimed: bool | None
|
649
|
-
current_answer_before: DatetimeUTC | None
|
650
|
-
finalized_before: DatetimeUTC | None
|
651
|
-
finalized_after: DatetimeUTC | None
|
652
|
-
|
653
|
-
question_id: HexBytes | None
|
654
|
-
question_id_in: list[HexBytes] | None
|
644
|
+
user: HexAddress | None,
|
645
|
+
claimed: bool | None,
|
646
|
+
current_answer_before: DatetimeUTC | None,
|
647
|
+
finalized_before: DatetimeUTC | None,
|
648
|
+
finalized_after: DatetimeUTC | None,
|
649
|
+
with_answers: bool | None,
|
650
|
+
question_id: HexBytes | None,
|
651
|
+
question_id_in: list[HexBytes] | None,
|
652
|
+
opened_before: t.Optional[DatetimeUTC],
|
653
|
+
opened_after: t.Optional[DatetimeUTC],
|
654
|
+
excluded_titles: set[str] | None,
|
655
655
|
) -> dict[str, t.Any]:
|
656
|
+
"""
|
657
|
+
Be aware, both Omen subgraph and Reality subgraph are indexing questions, but their fields are a bit different.
|
658
|
+
"""
|
656
659
|
where_stms: dict[str, t.Any] = {}
|
657
660
|
|
658
661
|
if user is not None:
|
@@ -672,6 +675,12 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
672
675
|
current_answer_before
|
673
676
|
)
|
674
677
|
|
678
|
+
if opened_before:
|
679
|
+
where_stms["openingTimestamp_lt"] = to_int_timestamp(opened_before)
|
680
|
+
|
681
|
+
if opened_after:
|
682
|
+
where_stms["openingTimestamp_gt"] = to_int_timestamp(opened_after)
|
683
|
+
|
675
684
|
if finalized_before is not None:
|
676
685
|
where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
|
677
686
|
finalized_before
|
@@ -682,12 +691,77 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
682
691
|
finalized_after
|
683
692
|
)
|
684
693
|
|
685
|
-
if
|
686
|
-
|
694
|
+
if with_answers is not None:
|
695
|
+
if with_answers:
|
696
|
+
where_stms["answerFinalizedTimestamp_not"] = None
|
697
|
+
else:
|
698
|
+
where_stms["answerFinalizedTimestamp"] = None
|
687
699
|
|
688
700
|
if question_id_in is not None:
|
701
|
+
# Be aware: On Omen subgraph, question's `id` represents `questionId` on reality subgraph. And `id` on reality subraph is just a weird concat of multiple things from the question.
|
689
702
|
where_stms["questionId_in"] = [x.hex() for x in question_id_in]
|
690
703
|
|
704
|
+
if excluded_titles:
|
705
|
+
# Be aware: This is called `title_not_in` on Omen subgraph.
|
706
|
+
where_stms["qTitle_not_in"] = [i for i in excluded_titles]
|
707
|
+
|
708
|
+
return where_stms
|
709
|
+
|
710
|
+
@staticmethod
|
711
|
+
def get_omen_question_filters(
|
712
|
+
current_answer_before: DatetimeUTC | None,
|
713
|
+
finalized_before: DatetimeUTC | None,
|
714
|
+
finalized_after: DatetimeUTC | None,
|
715
|
+
with_answers: bool | None,
|
716
|
+
question_id: HexBytes | None,
|
717
|
+
question_id_in: list[HexBytes] | None,
|
718
|
+
opened_before: t.Optional[DatetimeUTC],
|
719
|
+
opened_after: t.Optional[DatetimeUTC],
|
720
|
+
excluded_titles: set[str] | None,
|
721
|
+
) -> dict[str, t.Any]:
|
722
|
+
"""
|
723
|
+
Be aware, both Omen subgraph and Reality subgraph are indexing questions, but their fields are a bit different.
|
724
|
+
"""
|
725
|
+
where_stms: dict[str, t.Any] = {}
|
726
|
+
|
727
|
+
if question_id is not None:
|
728
|
+
where_stms["questionId"] = question_id.hex()
|
729
|
+
|
730
|
+
if current_answer_before is not None:
|
731
|
+
where_stms["currentAnswerTimestamp_lt"] = to_int_timestamp(
|
732
|
+
current_answer_before
|
733
|
+
)
|
734
|
+
|
735
|
+
if opened_before:
|
736
|
+
where_stms["openingTimestamp_lt"] = to_int_timestamp(opened_before)
|
737
|
+
|
738
|
+
if opened_after:
|
739
|
+
where_stms["openingTimestamp_gt"] = to_int_timestamp(opened_after)
|
740
|
+
|
741
|
+
if finalized_before is not None:
|
742
|
+
where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
|
743
|
+
finalized_before
|
744
|
+
)
|
745
|
+
|
746
|
+
if finalized_after is not None:
|
747
|
+
where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
|
748
|
+
finalized_after
|
749
|
+
)
|
750
|
+
|
751
|
+
if with_answers is not None:
|
752
|
+
if with_answers:
|
753
|
+
where_stms["answerFinalizedTimestamp_not"] = None
|
754
|
+
else:
|
755
|
+
where_stms["answerFinalizedTimestamp"] = None
|
756
|
+
|
757
|
+
if question_id_in is not None:
|
758
|
+
# Be aware: On Omen subgraph, question's `id` represents `questionId` on reality subgraph. And `id` on reality subraph is just a weird concat of multiple things from the question.
|
759
|
+
where_stms["id_in"] = [x.hex() for x in question_id_in]
|
760
|
+
|
761
|
+
if excluded_titles:
|
762
|
+
# Be aware: This is called `qTitle_not_in` on Omen subgraph.
|
763
|
+
where_stms["title_not_in"] = [i for i in excluded_titles]
|
764
|
+
|
691
765
|
return where_stms
|
692
766
|
|
693
767
|
def get_questions(
|
@@ -698,17 +772,25 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
698
772
|
current_answer_before: DatetimeUTC | None = None,
|
699
773
|
finalized_before: DatetimeUTC | None = None,
|
700
774
|
finalized_after: DatetimeUTC | None = None,
|
701
|
-
|
775
|
+
with_answers: bool | None = None,
|
702
776
|
question_id_in: list[HexBytes] | None = None,
|
777
|
+
question_id: HexBytes | None = None,
|
778
|
+
opened_before: DatetimeUTC | None = None,
|
779
|
+
opened_after: DatetimeUTC | None = None,
|
780
|
+
excluded_titles: set[str] | None = None,
|
703
781
|
) -> list[RealityQuestion]:
|
704
782
|
where_stms: dict[str, t.Any] = self.get_reality_question_filters(
|
705
783
|
user=user,
|
706
784
|
claimed=claimed,
|
707
785
|
finalized_before=finalized_before,
|
708
786
|
finalized_after=finalized_after,
|
787
|
+
with_answers=with_answers,
|
709
788
|
current_answer_before=current_answer_before,
|
710
|
-
id_in=id_in,
|
711
789
|
question_id_in=question_id_in,
|
790
|
+
question_id=question_id,
|
791
|
+
opened_before=opened_before,
|
792
|
+
opened_after=opened_after,
|
793
|
+
excluded_titles=excluded_titles,
|
712
794
|
)
|
713
795
|
questions = self.realityeth_subgraph.Query.questions(
|
714
796
|
first=(
|
@@ -738,12 +820,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
738
820
|
self,
|
739
821
|
limit: int | None,
|
740
822
|
user: HexAddress | None = None,
|
741
|
-
|
823
|
+
question_user: HexAddress | None = None,
|
742
824
|
question_claimed: bool | None = None,
|
743
|
-
|
744
|
-
|
745
|
-
|
825
|
+
question_opened_before: t.Optional[DatetimeUTC] = None,
|
826
|
+
question_opened_after: t.Optional[DatetimeUTC] = None,
|
827
|
+
question_finalized_before: t.Optional[DatetimeUTC] = None,
|
828
|
+
question_finalized_after: t.Optional[DatetimeUTC] = None,
|
829
|
+
question_with_answers: bool | None = None,
|
830
|
+
question_id: HexBytes | None = None,
|
746
831
|
question_id_in: list[HexBytes] | None = None,
|
832
|
+
question_current_answer_before: DatetimeUTC | None = None,
|
833
|
+
question_excluded_titles: set[str] | None = None,
|
747
834
|
) -> list[RealityResponse]:
|
748
835
|
where_stms: dict[str, t.Any] = {}
|
749
836
|
|
@@ -751,12 +838,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
751
838
|
where_stms["user"] = user.lower()
|
752
839
|
|
753
840
|
where_stms["question_"] = self.get_reality_question_filters(
|
841
|
+
user=question_user,
|
754
842
|
question_id=question_id,
|
755
843
|
claimed=question_claimed,
|
844
|
+
opened_before=question_opened_before,
|
845
|
+
opened_after=question_opened_after,
|
756
846
|
finalized_before=question_finalized_before,
|
757
847
|
finalized_after=question_finalized_after,
|
848
|
+
with_answers=question_with_answers,
|
758
849
|
current_answer_before=question_current_answer_before,
|
759
850
|
question_id_in=question_id_in,
|
851
|
+
excluded_titles=question_excluded_titles,
|
760
852
|
)
|
761
853
|
|
762
854
|
responses = self.realityeth_subgraph.Query.responses(
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import tenacity
|
2
|
+
|
3
|
+
from prediction_market_agent_tooling.config import APIKeys
|
4
|
+
from prediction_market_agent_tooling.loggers import logger
|
5
|
+
from prediction_market_agent_tooling.tools.cache import persistent_inmemory_cache
|
6
|
+
from prediction_market_agent_tooling.tools.is_predictable import (
|
7
|
+
parse_decision_yes_no_completion,
|
8
|
+
)
|
9
|
+
from prediction_market_agent_tooling.tools.langfuse_ import (
|
10
|
+
get_langfuse_langchain_config,
|
11
|
+
observe,
|
12
|
+
)
|
13
|
+
from prediction_market_agent_tooling.tools.utils import (
|
14
|
+
LLM_SEED,
|
15
|
+
LLM_SUPER_LOW_TEMPERATURE,
|
16
|
+
)
|
17
|
+
|
18
|
+
# I tried to make it return a JSON, but it didn't work well in combo with asking it to do chain of thought.
|
19
|
+
# Rules are almost copy-pasted from https://cdn.kleros.link/ipfs/QmZM12kkguXFk2C94ykrKpambt4iUVKsVsxGxDEdLS68ws/omen-rules.pdf,
|
20
|
+
# with some small prompting mods and I removed the point about "The outcome of the market must be known by its Resolution Date.", because that can not be verified before-hand.
|
21
|
+
# and also point about "in which none of the answers are valid will resolve as invalid" and "in which multiple answers are valid will resolve as invalid.", because before hand we can not know if one of the outcomes happened or not.
|
22
|
+
QUESTION_IS_INVALID_PROMPT = """Main signs about an invalid question (sometimes referred to as a "market"):
|
23
|
+
- The market's question is about immoral violence, death or assassination.
|
24
|
+
- The violent event can be caused by a single conscious being.
|
25
|
+
- The violent event is done illegally.
|
26
|
+
- The market should not directly incentivize immoral violent (such as murder, rape or unjust imprisonment) actions which could likely be performed by any participant.
|
27
|
+
- Invalid: Will Donald Trump be alive on the 01/12/2021? (Anyone could bet on “No” and kill him for a guaranteed profit. Anyone could bet on “Yes” to effectively put a bounty on his head).
|
28
|
+
- Invalid: Will Hera be a victim of swatting in 2020? (Anyone could falsely call the emergency services on him in order to win the bet)
|
29
|
+
- This does not prevent markets:
|
30
|
+
- Whose topics are violent events not caused by conscious beings.
|
31
|
+
- Valid: How many people will die from COVID19 in 2020? (Viruses don’t use prediction markets).
|
32
|
+
- Whose main source of uncertainty is not related to a potential violent action.
|
33
|
+
- Valid: Will Trump win the 2020 US presidential election? (The main source of uncertainty is the vote of US citizens, not a potential murder of a presidential candidate).
|
34
|
+
- Which could give an incentive only to specific participants to commit an immoral violent action, but are in practice unlikely.
|
35
|
+
- Valid: Will the US be engaged in a military conflict with a UN member state in 2021? (It’s unlikely for the US to declare war in order to win a bet on this market).
|
36
|
+
- Valid: Will Derek Chauvin go to jail for the murder of George Flyod? (It’s unlikely that the jurors would collude to make a wrong verdict in order to win this market).
|
37
|
+
- Questions with relative dates will resolve as invalid. Dates must be stated in absolute terms, not relative depending on the current time.
|
38
|
+
- Invalid: Who will be the president of the United States in 6 months? (“in 6 months depends on the current time”).
|
39
|
+
- Questions about moral values and not facts will be resolved as invalid.
|
40
|
+
- Invalid: “Is it ethical to eat meat?”.
|
41
|
+
|
42
|
+
Follow a chain of thought to evaluate if the question is invalid:
|
43
|
+
|
44
|
+
First, write the parts of the following question:
|
45
|
+
|
46
|
+
"{question}"
|
47
|
+
|
48
|
+
Then, write down what is the future event of the question, what it refers to and when that event will happen if the question contains it.
|
49
|
+
|
50
|
+
Then, explain why do you think it is or isn't invalid.
|
51
|
+
|
52
|
+
Finally, write your final decision, write `decision: ` followed by either "yes it is invalid" or "no it isn't invalid" about the question. Don't write anything else after that. You must include "yes" or "no".
|
53
|
+
"""
|
54
|
+
|
55
|
+
|
56
|
+
@persistent_inmemory_cache
|
57
|
+
@tenacity.retry(stop=tenacity.stop_after_attempt(3), wait=tenacity.wait_fixed(1))
|
58
|
+
@observe()
|
59
|
+
def is_invalid(
|
60
|
+
question: str,
|
61
|
+
engine: str = "gpt-4o",
|
62
|
+
temperature: float = LLM_SUPER_LOW_TEMPERATURE,
|
63
|
+
seed: int = LLM_SEED,
|
64
|
+
prompt_template: str = QUESTION_IS_INVALID_PROMPT,
|
65
|
+
max_tokens: int = 1024,
|
66
|
+
) -> bool:
|
67
|
+
"""
|
68
|
+
Evaluate if the question is actually answerable.
|
69
|
+
"""
|
70
|
+
try:
|
71
|
+
from langchain.prompts import ChatPromptTemplate
|
72
|
+
from langchain_openai import ChatOpenAI
|
73
|
+
except ImportError:
|
74
|
+
logger.error("langchain not installed, skipping is_invalid")
|
75
|
+
return True
|
76
|
+
|
77
|
+
llm = ChatOpenAI(
|
78
|
+
model=engine,
|
79
|
+
temperature=temperature,
|
80
|
+
seed=seed,
|
81
|
+
api_key=APIKeys().openai_api_key_secretstr_v1,
|
82
|
+
)
|
83
|
+
|
84
|
+
prompt = ChatPromptTemplate.from_template(template=prompt_template)
|
85
|
+
messages = prompt.format_messages(question=question)
|
86
|
+
completion = str(
|
87
|
+
llm.invoke(
|
88
|
+
messages, max_tokens=max_tokens, config=get_langfuse_langchain_config()
|
89
|
+
).content
|
90
|
+
)
|
91
|
+
|
92
|
+
return parse_decision_yes_no_completion(question, completion)
|
@@ -22,8 +22,10 @@ from prediction_market_agent_tooling.loggers import logger
|
|
22
22
|
T = TypeVar("T")
|
23
23
|
|
24
24
|
# t=0 is mathematically impossible and it's not clear how OpenAI (and others) handle it, as a result, even with t=0, gpt-4-turbo produces very different outputs,
|
25
|
-
#
|
25
|
+
# see this experiment to figure out if you should use LLM_SUPER_LOW_TEMPERATURE or just 0: https://github.com/gnosis/prediction-market-agent/pull/438.
|
26
26
|
LLM_SUPER_LOW_TEMPERATURE = 0.00000001
|
27
|
+
# For consistent results, also include seed for models that supports it.
|
28
|
+
LLM_SEED = 0
|
27
29
|
|
28
30
|
|
29
31
|
def check_not_none(
|
@@ -1,97 +0,0 @@
|
|
1
|
-
from enum import Enum
|
2
|
-
from typing import Any
|
3
|
-
|
4
|
-
from pydantic import BaseModel
|
5
|
-
|
6
|
-
from prediction_market_agent_tooling.tools.utils import DatetimeUTC
|
7
|
-
|
8
|
-
|
9
|
-
class QuestionType(str, Enum):
|
10
|
-
forecast = "forecast"
|
11
|
-
notebook = "notebook"
|
12
|
-
discussion = "discussion"
|
13
|
-
claim = "claim"
|
14
|
-
group = "group"
|
15
|
-
conditional_group = "conditional_group"
|
16
|
-
multiple_choice = "multiple_choice"
|
17
|
-
|
18
|
-
|
19
|
-
class CommunityPrediction(BaseModel):
|
20
|
-
y: list[float]
|
21
|
-
q1: float | None = None
|
22
|
-
q2: float | None = None
|
23
|
-
q3: float | None = None
|
24
|
-
|
25
|
-
@property
|
26
|
-
def p_yes(self) -> float:
|
27
|
-
"""
|
28
|
-
q2 corresponds to the median, or 'second quartile' of the distribution.
|
29
|
-
|
30
|
-
If no value is provided (i.e. the question is new and has not been
|
31
|
-
answered yet), we default to 0.5.
|
32
|
-
"""
|
33
|
-
return self.q2 if self.q2 is not None else 0.5
|
34
|
-
|
35
|
-
|
36
|
-
class Prediction(BaseModel):
|
37
|
-
t: DatetimeUTC
|
38
|
-
x: float
|
39
|
-
|
40
|
-
|
41
|
-
class UserPredictions(BaseModel):
|
42
|
-
id: int
|
43
|
-
predictions: list[Prediction]
|
44
|
-
points_won: float | None = None
|
45
|
-
user: int
|
46
|
-
username: str
|
47
|
-
question: int
|
48
|
-
|
49
|
-
|
50
|
-
class CommunityPredictionStats(BaseModel):
|
51
|
-
full: CommunityPrediction
|
52
|
-
unweighted: CommunityPrediction
|
53
|
-
|
54
|
-
|
55
|
-
class MetaculusQuestion(BaseModel):
|
56
|
-
"""
|
57
|
-
https://www.metaculus.com/api2/schema/redoc/#tag/questions/operation/questions_retrieve
|
58
|
-
"""
|
59
|
-
|
60
|
-
active_state: Any
|
61
|
-
url: str
|
62
|
-
page_url: str
|
63
|
-
id: int
|
64
|
-
author: int
|
65
|
-
author_name: str
|
66
|
-
author_id: int
|
67
|
-
title: str
|
68
|
-
title_short: str
|
69
|
-
group_label: str | None = None
|
70
|
-
resolution: int | None
|
71
|
-
resolved_option: int | None
|
72
|
-
created_time: DatetimeUTC
|
73
|
-
publish_time: DatetimeUTC | None = None
|
74
|
-
close_time: DatetimeUTC | None = None
|
75
|
-
effected_close_time: DatetimeUTC | None
|
76
|
-
resolve_time: DatetimeUTC | None = None
|
77
|
-
possibilities: dict[Any, Any] | None = None
|
78
|
-
scoring: dict[Any, Any] = {}
|
79
|
-
type: QuestionType | None = None
|
80
|
-
user_perms: Any
|
81
|
-
weekly_movement: float | None
|
82
|
-
weekly_movement_direction: int | None = None
|
83
|
-
cp_reveal_time: DatetimeUTC | None = None
|
84
|
-
edited_time: DatetimeUTC
|
85
|
-
last_activity_time: DatetimeUTC
|
86
|
-
activity: float
|
87
|
-
comment_count: int
|
88
|
-
votes: int
|
89
|
-
community_prediction: CommunityPredictionStats
|
90
|
-
my_predictions: UserPredictions | None = None
|
91
|
-
# TODO add the rest of the fields https://github.com/gnosis/prediction-market-agent-tooling/issues/301
|
92
|
-
|
93
|
-
|
94
|
-
class MetaculusQuestions(BaseModel):
|
95
|
-
next: str | None
|
96
|
-
previous: str | None
|
97
|
-
results: list[MetaculusQuestion]
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|