weakincentives 0.9.0__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.
- weakincentives/__init__.py +67 -0
- weakincentives/adapters/__init__.py +37 -0
- weakincentives/adapters/_names.py +32 -0
- weakincentives/adapters/_provider_protocols.py +69 -0
- weakincentives/adapters/_tool_messages.py +80 -0
- weakincentives/adapters/core.py +102 -0
- weakincentives/adapters/litellm.py +254 -0
- weakincentives/adapters/openai.py +254 -0
- weakincentives/adapters/shared.py +1021 -0
- weakincentives/cli/__init__.py +23 -0
- weakincentives/cli/wink.py +58 -0
- weakincentives/dbc/__init__.py +412 -0
- weakincentives/deadlines.py +58 -0
- weakincentives/prompt/__init__.py +105 -0
- weakincentives/prompt/_generic_params_specializer.py +64 -0
- weakincentives/prompt/_normalization.py +48 -0
- weakincentives/prompt/_overrides_protocols.py +33 -0
- weakincentives/prompt/_types.py +34 -0
- weakincentives/prompt/chapter.py +146 -0
- weakincentives/prompt/composition.py +281 -0
- weakincentives/prompt/errors.py +57 -0
- weakincentives/prompt/markdown.py +108 -0
- weakincentives/prompt/overrides/__init__.py +59 -0
- weakincentives/prompt/overrides/_fs.py +164 -0
- weakincentives/prompt/overrides/inspection.py +141 -0
- weakincentives/prompt/overrides/local_store.py +275 -0
- weakincentives/prompt/overrides/validation.py +534 -0
- weakincentives/prompt/overrides/versioning.py +269 -0
- weakincentives/prompt/prompt.py +353 -0
- weakincentives/prompt/protocols.py +103 -0
- weakincentives/prompt/registry.py +375 -0
- weakincentives/prompt/rendering.py +288 -0
- weakincentives/prompt/response_format.py +60 -0
- weakincentives/prompt/section.py +166 -0
- weakincentives/prompt/structured_output.py +179 -0
- weakincentives/prompt/tool.py +397 -0
- weakincentives/prompt/tool_result.py +30 -0
- weakincentives/py.typed +0 -0
- weakincentives/runtime/__init__.py +82 -0
- weakincentives/runtime/events/__init__.py +126 -0
- weakincentives/runtime/events/_types.py +110 -0
- weakincentives/runtime/logging.py +284 -0
- weakincentives/runtime/session/__init__.py +46 -0
- weakincentives/runtime/session/_slice_types.py +24 -0
- weakincentives/runtime/session/_types.py +55 -0
- weakincentives/runtime/session/dataclasses.py +29 -0
- weakincentives/runtime/session/protocols.py +34 -0
- weakincentives/runtime/session/reducer_context.py +40 -0
- weakincentives/runtime/session/reducers.py +82 -0
- weakincentives/runtime/session/selectors.py +56 -0
- weakincentives/runtime/session/session.py +387 -0
- weakincentives/runtime/session/snapshots.py +310 -0
- weakincentives/serde/__init__.py +19 -0
- weakincentives/serde/_utils.py +240 -0
- weakincentives/serde/dataclass_serde.py +55 -0
- weakincentives/serde/dump.py +189 -0
- weakincentives/serde/parse.py +417 -0
- weakincentives/serde/schema.py +260 -0
- weakincentives/tools/__init__.py +154 -0
- weakincentives/tools/_context.py +38 -0
- weakincentives/tools/asteval.py +853 -0
- weakincentives/tools/errors.py +26 -0
- weakincentives/tools/planning.py +831 -0
- weakincentives/tools/podman.py +1655 -0
- weakincentives/tools/subagents.py +346 -0
- weakincentives/tools/vfs.py +1390 -0
- weakincentives/types/__init__.py +35 -0
- weakincentives/types/json.py +45 -0
- weakincentives-0.9.0.dist-info/METADATA +775 -0
- weakincentives-0.9.0.dist-info/RECORD +73 -0
- weakincentives-0.9.0.dist-info/WHEEL +4 -0
- weakincentives-0.9.0.dist-info/entry_points.txt +2 -0
- weakincentives-0.9.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
2
|
+
# you may not use this file except in compliance with the License.
|
|
3
|
+
# You may obtain a copy of the License at
|
|
4
|
+
#
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
#
|
|
7
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
8
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
9
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10
|
+
# See the License for the specific language governing permissions and
|
|
11
|
+
# limitations under the License.
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import cast, override
|
|
18
|
+
|
|
19
|
+
from ...runtime.logging import StructuredLogger, get_logger
|
|
20
|
+
from ...types import JSONValue
|
|
21
|
+
from ._fs import OverrideFilesystem
|
|
22
|
+
from .validation import (
|
|
23
|
+
FORMAT_VERSION,
|
|
24
|
+
filter_override_for_descriptor,
|
|
25
|
+
load_sections,
|
|
26
|
+
load_tools,
|
|
27
|
+
seed_sections,
|
|
28
|
+
seed_tools,
|
|
29
|
+
serialize_sections,
|
|
30
|
+
serialize_tools,
|
|
31
|
+
validate_header,
|
|
32
|
+
validate_sections_for_write,
|
|
33
|
+
validate_tools_for_write,
|
|
34
|
+
)
|
|
35
|
+
from .versioning import (
|
|
36
|
+
PromptDescriptor,
|
|
37
|
+
PromptLike,
|
|
38
|
+
PromptOverride,
|
|
39
|
+
PromptOverridesError,
|
|
40
|
+
PromptOverridesStore,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
_LOGGER: StructuredLogger = get_logger(
|
|
44
|
+
__name__, context={"component": "prompt_overrides"}
|
|
45
|
+
)
|
|
46
|
+
_DEFAULT_RELATIVE_PATH = Path(".weakincentives") / "prompts" / "overrides"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LocalPromptOverridesStore(PromptOverridesStore):
|
|
50
|
+
"""Persist prompt overrides to disk within the project workspace."""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
*,
|
|
55
|
+
root_path: str | Path | None = None,
|
|
56
|
+
overrides_relative_path: str | Path = _DEFAULT_RELATIVE_PATH,
|
|
57
|
+
) -> None:
|
|
58
|
+
super().__init__()
|
|
59
|
+
explicit_root = Path(root_path).resolve() if root_path else None
|
|
60
|
+
overrides_relative = Path(overrides_relative_path)
|
|
61
|
+
self._filesystem = OverrideFilesystem(
|
|
62
|
+
explicit_root=explicit_root,
|
|
63
|
+
overrides_relative_path=overrides_relative,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
@override
|
|
67
|
+
def resolve(
|
|
68
|
+
self,
|
|
69
|
+
descriptor: PromptDescriptor,
|
|
70
|
+
tag: str = "latest",
|
|
71
|
+
) -> PromptOverride | None:
|
|
72
|
+
normalized_tag = self._filesystem.validate_identifier(tag, "tag")
|
|
73
|
+
file_path = self._filesystem.override_file_path(
|
|
74
|
+
ns=descriptor.ns,
|
|
75
|
+
prompt_key=descriptor.key,
|
|
76
|
+
tag=normalized_tag,
|
|
77
|
+
)
|
|
78
|
+
with self._filesystem.locked_override_path(file_path):
|
|
79
|
+
if not file_path.exists():
|
|
80
|
+
_LOGGER.debug(
|
|
81
|
+
"Override file not found.",
|
|
82
|
+
event="prompt_override_missing",
|
|
83
|
+
context={
|
|
84
|
+
"ns": descriptor.ns,
|
|
85
|
+
"prompt_key": descriptor.key,
|
|
86
|
+
"tag": normalized_tag,
|
|
87
|
+
},
|
|
88
|
+
)
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
payload: dict[str, JSONValue]
|
|
92
|
+
try:
|
|
93
|
+
with file_path.open("r", encoding="utf-8") as handle:
|
|
94
|
+
payload = cast(dict[str, JSONValue], json.load(handle))
|
|
95
|
+
except json.JSONDecodeError as error:
|
|
96
|
+
raise PromptOverridesError(
|
|
97
|
+
f"Failed to parse prompt override JSON: {file_path}"
|
|
98
|
+
) from error
|
|
99
|
+
|
|
100
|
+
validate_header(payload, descriptor, normalized_tag, file_path)
|
|
101
|
+
|
|
102
|
+
sections_payload = payload.get("sections")
|
|
103
|
+
sections = load_sections(sections_payload, descriptor)
|
|
104
|
+
tools_payload = payload.get("tools")
|
|
105
|
+
tools = load_tools(tools_payload, descriptor)
|
|
106
|
+
|
|
107
|
+
raw_override = PromptOverride(
|
|
108
|
+
ns=descriptor.ns,
|
|
109
|
+
prompt_key=descriptor.key,
|
|
110
|
+
tag=tag,
|
|
111
|
+
sections=sections,
|
|
112
|
+
tool_overrides=tools,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
filtered_sections, filtered_tools = filter_override_for_descriptor(
|
|
116
|
+
descriptor, raw_override
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if not filtered_sections and not filtered_tools:
|
|
120
|
+
_LOGGER.debug(
|
|
121
|
+
"No applicable overrides remain after validation.",
|
|
122
|
+
event="prompt_override_empty",
|
|
123
|
+
context={
|
|
124
|
+
"ns": descriptor.ns,
|
|
125
|
+
"prompt_key": descriptor.key,
|
|
126
|
+
"tag": normalized_tag,
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
override = PromptOverride(
|
|
132
|
+
ns=descriptor.ns,
|
|
133
|
+
prompt_key=descriptor.key,
|
|
134
|
+
tag=tag,
|
|
135
|
+
sections=filtered_sections,
|
|
136
|
+
tool_overrides=filtered_tools,
|
|
137
|
+
)
|
|
138
|
+
_LOGGER.info(
|
|
139
|
+
"Resolved prompt override.",
|
|
140
|
+
event="prompt_override_resolved",
|
|
141
|
+
context={
|
|
142
|
+
"ns": descriptor.ns,
|
|
143
|
+
"prompt_key": descriptor.key,
|
|
144
|
+
"tag": normalized_tag,
|
|
145
|
+
"section_count": len(filtered_sections),
|
|
146
|
+
"tool_count": len(filtered_tools),
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
return override
|
|
150
|
+
|
|
151
|
+
@override
|
|
152
|
+
def upsert(
|
|
153
|
+
self,
|
|
154
|
+
descriptor: PromptDescriptor,
|
|
155
|
+
override: PromptOverride,
|
|
156
|
+
) -> PromptOverride:
|
|
157
|
+
if override.ns != descriptor.ns or override.prompt_key != descriptor.key:
|
|
158
|
+
raise PromptOverridesError(
|
|
159
|
+
"Override metadata does not match descriptor.",
|
|
160
|
+
)
|
|
161
|
+
normalized_tag = self._filesystem.validate_identifier(override.tag, "tag")
|
|
162
|
+
|
|
163
|
+
file_path = self._filesystem.override_file_path(
|
|
164
|
+
ns=descriptor.ns,
|
|
165
|
+
prompt_key=descriptor.key,
|
|
166
|
+
tag=normalized_tag,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
validated_sections = validate_sections_for_write(
|
|
170
|
+
override.sections,
|
|
171
|
+
descriptor,
|
|
172
|
+
)
|
|
173
|
+
validated_tools = validate_tools_for_write(
|
|
174
|
+
override.tool_overrides,
|
|
175
|
+
descriptor,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
payload = {
|
|
179
|
+
"version": FORMAT_VERSION,
|
|
180
|
+
"ns": descriptor.ns,
|
|
181
|
+
"prompt_key": descriptor.key,
|
|
182
|
+
"tag": normalized_tag,
|
|
183
|
+
"sections": serialize_sections(validated_sections),
|
|
184
|
+
"tools": serialize_tools(validated_tools),
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
with self._filesystem.locked_override_path(file_path):
|
|
188
|
+
self._filesystem.atomic_write(file_path, payload)
|
|
189
|
+
|
|
190
|
+
persisted = PromptOverride(
|
|
191
|
+
ns=descriptor.ns,
|
|
192
|
+
prompt_key=descriptor.key,
|
|
193
|
+
tag=normalized_tag,
|
|
194
|
+
sections=validated_sections,
|
|
195
|
+
tool_overrides=validated_tools,
|
|
196
|
+
)
|
|
197
|
+
_LOGGER.info(
|
|
198
|
+
"Persisted prompt override.",
|
|
199
|
+
event="prompt_override_persisted",
|
|
200
|
+
context={
|
|
201
|
+
"ns": descriptor.ns,
|
|
202
|
+
"prompt_key": descriptor.key,
|
|
203
|
+
"tag": normalized_tag,
|
|
204
|
+
"section_count": len(validated_sections),
|
|
205
|
+
"tool_count": len(validated_tools),
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
return persisted
|
|
209
|
+
|
|
210
|
+
@override
|
|
211
|
+
def delete(
|
|
212
|
+
self,
|
|
213
|
+
*,
|
|
214
|
+
ns: str,
|
|
215
|
+
prompt_key: str,
|
|
216
|
+
tag: str,
|
|
217
|
+
) -> None:
|
|
218
|
+
normalized_tag = self._filesystem.validate_identifier(tag, "tag")
|
|
219
|
+
file_path = self._filesystem.override_file_path(
|
|
220
|
+
ns=ns,
|
|
221
|
+
prompt_key=prompt_key,
|
|
222
|
+
tag=normalized_tag,
|
|
223
|
+
)
|
|
224
|
+
with self._filesystem.locked_override_path(file_path):
|
|
225
|
+
try:
|
|
226
|
+
file_path.unlink()
|
|
227
|
+
except FileNotFoundError:
|
|
228
|
+
_LOGGER.debug(
|
|
229
|
+
"No override file to delete.",
|
|
230
|
+
event="prompt_override_delete_missing",
|
|
231
|
+
context={
|
|
232
|
+
"ns": ns,
|
|
233
|
+
"prompt_key": prompt_key,
|
|
234
|
+
"tag": normalized_tag,
|
|
235
|
+
},
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
@override
|
|
239
|
+
def seed_if_necessary(
|
|
240
|
+
self,
|
|
241
|
+
prompt: PromptLike,
|
|
242
|
+
*,
|
|
243
|
+
tag: str = "latest",
|
|
244
|
+
) -> PromptOverride:
|
|
245
|
+
descriptor = PromptDescriptor.from_prompt(prompt)
|
|
246
|
+
normalized_tag = self._filesystem.validate_identifier(tag, "tag")
|
|
247
|
+
file_path = self._filesystem.override_file_path(
|
|
248
|
+
ns=descriptor.ns,
|
|
249
|
+
prompt_key=descriptor.key,
|
|
250
|
+
tag=normalized_tag,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
with self._filesystem.locked_override_path(file_path):
|
|
254
|
+
if file_path.exists():
|
|
255
|
+
existing = self.resolve(descriptor=descriptor, tag=normalized_tag)
|
|
256
|
+
if existing is None:
|
|
257
|
+
raise PromptOverridesError(
|
|
258
|
+
"Override file exists but could not be resolved."
|
|
259
|
+
)
|
|
260
|
+
return existing
|
|
261
|
+
|
|
262
|
+
sections = seed_sections(prompt, descriptor)
|
|
263
|
+
tools = seed_tools(prompt, descriptor)
|
|
264
|
+
|
|
265
|
+
seed_override = PromptOverride(
|
|
266
|
+
ns=descriptor.ns,
|
|
267
|
+
prompt_key=descriptor.key,
|
|
268
|
+
tag=normalized_tag,
|
|
269
|
+
sections=sections,
|
|
270
|
+
tool_overrides=tools,
|
|
271
|
+
)
|
|
272
|
+
return self.upsert(descriptor, seed_override)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
__all__ = ["LocalPromptOverridesStore"]
|