millforge 0.1.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.
Files changed (116) hide show
  1. millforge/__init__.py +1174 -0
  2. millforge/_forge/LICENSE +21 -0
  3. millforge/_forge/PROVENANCE.json +295 -0
  4. millforge/_forge/UPDATE_POLICY.md +24 -0
  5. millforge/_forge/__init__.py +14 -0
  6. millforge/_forge/adapter.py +2232 -0
  7. millforge/_forge/base_runner.py +121 -0
  8. millforge/_forge/clients/__init__.py +10 -0
  9. millforge/_forge/clients/base.py +200 -0
  10. millforge/_forge/context/__init__.py +23 -0
  11. millforge/_forge/context/manager.py +178 -0
  12. millforge/_forge/context/strategies.py +335 -0
  13. millforge/_forge/core/__init__.py +16 -0
  14. millforge/_forge/core/inference.py +433 -0
  15. millforge/_forge/core/messages.py +119 -0
  16. millforge/_forge/core/runner.py +479 -0
  17. millforge/_forge/core/steps.py +108 -0
  18. millforge/_forge/core/workflow.py +400 -0
  19. millforge/_forge/errors.py +222 -0
  20. millforge/_forge/guardrails/__init__.py +21 -0
  21. millforge/_forge/guardrails/error_tracker.py +71 -0
  22. millforge/_forge/guardrails/guardrails.py +194 -0
  23. millforge/_forge/guardrails/nudge.py +47 -0
  24. millforge/_forge/guardrails/response_validator.py +119 -0
  25. millforge/_forge/guardrails/step_enforcer.py +183 -0
  26. millforge/_forge/prompts/__init__.py +16 -0
  27. millforge/_forge/prompts/nudges.py +95 -0
  28. millforge/_forge/prompts/templates.py +285 -0
  29. millforge/_version.py +3 -0
  30. millforge/artifacts.py +570 -0
  31. millforge/base/__init__.py +97 -0
  32. millforge/base/composition.py +402 -0
  33. millforge/base/context.py +285 -0
  34. millforge/base/harness.py +138 -0
  35. millforge/base/identity.py +465 -0
  36. millforge/base/options.py +34 -0
  37. millforge/base/platform.py +17 -0
  38. millforge/base/prompt.py +317 -0
  39. millforge/base/runner.py +546 -0
  40. millforge/compiled_plan.py +970 -0
  41. millforge/compiler/__init__.py +231 -0
  42. millforge/compiler/artifact_validation.py +257 -0
  43. millforge/compiler/canonicalization.py +169 -0
  44. millforge/compiler/capabilities.py +66 -0
  45. millforge/compiler/catalogs.py +500 -0
  46. millforge/compiler/diagnostics.py +491 -0
  47. millforge/compiler/graph.py +678 -0
  48. millforge/compiler/lowering.py +198 -0
  49. millforge/compiler/output.py +692 -0
  50. millforge/compiler/parsing.py +1424 -0
  51. millforge/compiler/requests.py +1180 -0
  52. millforge/compiler/schema_validation.py +272 -0
  53. millforge/compiler/semantic.py +490 -0
  54. millforge/compiler/service.py +448 -0
  55. millforge/compiler/source.py +375 -0
  56. millforge/compiler/validators.py +184 -0
  57. millforge/connectors/__init__.py +95 -0
  58. millforge/connectors/admission.py +801 -0
  59. millforge/connectors/broker.py +202 -0
  60. millforge/connectors/contracts.py +1159 -0
  61. millforge/connectors/diagnostics.py +189 -0
  62. millforge/connectors/fake.py +66 -0
  63. millforge/connectors/runtime.py +236 -0
  64. millforge/contracts.py +2860 -0
  65. millforge/custom_tools/__init__.py +67 -0
  66. millforge/custom_tools/compiler.py +724 -0
  67. millforge/custom_tools/contracts.py +1093 -0
  68. millforge/custom_tools/diagnostics.py +205 -0
  69. millforge/eval_artifacts.py +952 -0
  70. millforge/eval_boundary.py +2435 -0
  71. millforge/eval_fixtures/__init__.py +1 -0
  72. millforge/eval_fixtures/default_pack/__init__.py +1 -0
  73. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.bug_diagnosis.traceback.v1.json +52 -0
  74. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.direct_edit.import_sort.v1.json +52 -0
  75. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.evidence_discipline.no_source_change.v1.json +51 -0
  76. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.false_closure.visible_green.v1.json +52 -0
  77. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.multi_file.api_contract.v1.json +54 -0
  78. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.recovery.malformed_artifact.v1.json +54 -0
  79. millforge/eval_fixtures/default_pack/manifest.json +12 -0
  80. millforge/eval_modes.py +1282 -0
  81. millforge/eval_presets.py +1398 -0
  82. millforge/eval_reports.py +2517 -0
  83. millforge/eval_suite.py +2429 -0
  84. millforge/eval_trials.py +2632 -0
  85. millforge/eval_workflow.py +794 -0
  86. millforge/exceptions.py +122 -0
  87. millforge/model_backend.py +2098 -0
  88. millforge/protocols.py +340 -0
  89. millforge/py.typed +0 -0
  90. millforge/runtime.py +1791 -0
  91. millforge/testing/__init__.py +1089 -0
  92. millforge/tools/__init__.py +83 -0
  93. millforge/tools/builtin_runtime.py +1339 -0
  94. millforge/tools/builtins.py +773 -0
  95. millforge/tools/execution.py +1545 -0
  96. millforge/tools/path_policy.py +155 -0
  97. millforge/tools/pi_compat/PI_LICENSE +21 -0
  98. millforge/tools/pi_compat/PROVENANCE.json +55 -0
  99. millforge/tools/pi_compat/UPDATE_POLICY.md +36 -0
  100. millforge/tools/pi_compat/__init__.py +34 -0
  101. millforge/tools/pi_compat/contracts.py +49 -0
  102. millforge/tools/pi_compat/editing.py +390 -0
  103. millforge/tools/pi_compat/mutations.py +57 -0
  104. millforge/tools/pi_compat/operations.py +401 -0
  105. millforge/tools/pi_compat/paths.py +155 -0
  106. millforge/tools/pi_compat/process.py +1375 -0
  107. millforge/tools/pi_compat/search.py +738 -0
  108. millforge/tools/pi_compat/truncation.py +267 -0
  109. millforge/tools/pi_compat_catalog.py +396 -0
  110. millforge/tools/pi_compat_runtime.py +460 -0
  111. millforge/tools/registry.py +553 -0
  112. millforge/tools/results.py +533 -0
  113. millforge-0.1.0.dist-info/METADATA +844 -0
  114. millforge-0.1.0.dist-info/RECORD +116 -0
  115. millforge-0.1.0.dist-info/WHEEL +4 -0
  116. millforge-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,205 @@
1
+ """Custom tool compiler diagnostic contracts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from enum import Enum
7
+ from typing import Any
8
+
9
+ from pydantic import (
10
+ BaseModel,
11
+ ConfigDict,
12
+ Field,
13
+ StrictStr,
14
+ field_validator,
15
+ model_validator,
16
+ )
17
+
18
+ from millforge.compiler.diagnostics import detect_secret_candidate
19
+ from millforge.compiler.validators import validate_lower_field_key, validate_utf8_size
20
+ from millforge.contracts import RedactionPolicy, redact_diagnostic_text
21
+
22
+ MAX_CUSTOM_TOOL_DIAGNOSTIC_MESSAGE_UTF8 = 1024
23
+ MAX_CUSTOM_TOOL_DIAGNOSTIC_EVIDENCE_UTF8 = 512
24
+
25
+
26
+ class CustomToolDiagnosticSeverity(str, Enum):
27
+ """Closed custom-tool diagnostic severity values."""
28
+
29
+ ERROR = "error"
30
+ WARNING = "warning"
31
+
32
+
33
+ class CustomToolDiagnosticPhase(str, Enum):
34
+ """Closed custom-tool diagnostic phase values."""
35
+
36
+ SOURCE = "source"
37
+ DECLARATION = "declaration"
38
+ POLICY = "policy"
39
+ COMPILATION = "compilation"
40
+ DIAGNOSTIC = "diagnostic"
41
+
42
+
43
+ class CustomToolDiagnosticCode(str, Enum):
44
+ """Stable custom-tool compiler diagnostic codes."""
45
+
46
+ SOURCE_MALFORMED = "MF-CT001_SOURCE_MALFORMED"
47
+ SECRET_MATERIAL = "MF-CT002_SECRET_MATERIAL"
48
+ RUNTIME_KIND_UNSUPPORTED = "MF-CT003_RUNTIME_KIND_UNSUPPORTED"
49
+ EXECUTABLE_MATERIAL = "MF-CT004_EXECUTABLE_MATERIAL"
50
+ DUPLICATE_TOOL = "MF-CT005_DUPLICATE_TOOL"
51
+ DUPLICATE_MODEL_TOOL_NAME = "MF-CT006_DUPLICATE_MODEL_TOOL_NAME"
52
+ DUPLICATE_IMPLEMENTATION_ID = "MF-CT007_DUPLICATE_IMPLEMENTATION_ID"
53
+ INPUT_SCHEMA_UNSUPPORTED = "MF-CT008_INPUT_SCHEMA_UNSUPPORTED"
54
+ OUTPUT_SCHEMA_UNSUPPORTED = "MF-CT009_OUTPUT_SCHEMA_UNSUPPORTED"
55
+ DESCRIPTION_UNSAFE = "MF-CT010_DESCRIPTION_UNSAFE"
56
+ CAPABILITY_MISSING = "MF-CT011_CAPABILITY_MISSING"
57
+ CAPABILITY_UNKNOWN = "MF-CT012_CAPABILITY_UNKNOWN"
58
+ ARTIFACT_POLICY_INVALID = "MF-CT013_ARTIFACT_POLICY_INVALID"
59
+ APPROVAL_POLICY_INVALID = "MF-CT014_APPROVAL_POLICY_INVALID"
60
+ FORBIDDEN_TOOL_COMPILED = "MF-CT015_FORBIDDEN_TOOL_COMPILED"
61
+ TIMEOUT_POLICY_INVALID = "MF-CT016_TIMEOUT_POLICY_INVALID"
62
+ OUTPUT_POLICY_INVALID = "MF-CT017_OUTPUT_POLICY_INVALID"
63
+ HASH_MISMATCH = "MF-CT018_HASH_MISMATCH"
64
+ DESCRIPTOR_PROJECTION_FAILED = "MF-CT019_DESCRIPTOR_PROJECTION_FAILED"
65
+
66
+ SOURCE_INVALID = SOURCE_MALFORMED
67
+ DECLARATION_INVALID = DESCRIPTOR_PROJECTION_FAILED
68
+ LIMIT_EXCEEDED = SOURCE_MALFORMED
69
+
70
+
71
+ class CustomToolDiagnosticEvidence(BaseModel):
72
+ """Immutable redacted scalar evidence for custom-tool diagnostics."""
73
+
74
+ model_config = ConfigDict(frozen=True, extra="forbid")
75
+
76
+ key: StrictStr
77
+ value: StrictStr
78
+
79
+ @field_validator("key")
80
+ @classmethod
81
+ def _key_valid(cls, value: str) -> str:
82
+ return validate_lower_field_key(value)
83
+
84
+ @field_validator("value")
85
+ @classmethod
86
+ def _value_redacted(cls, value: str) -> str:
87
+ return redact_custom_tool_text(
88
+ value, maximum=MAX_CUSTOM_TOOL_DIAGNOSTIC_EVIDENCE_UTF8
89
+ )
90
+
91
+
92
+ class CustomToolDiagnostic(BaseModel):
93
+ """Stable custom-tool diagnostic with redacted bounded evidence."""
94
+
95
+ model_config = ConfigDict(frozen=True, extra="forbid")
96
+
97
+ code: CustomToolDiagnosticCode
98
+ severity: CustomToolDiagnosticSeverity
99
+ phase: CustomToolDiagnosticPhase
100
+ location: StrictStr | None = None
101
+ path: StrictStr | None = None
102
+ message: StrictStr
103
+ evidence: tuple[CustomToolDiagnosticEvidence, ...] = Field(default_factory=tuple)
104
+
105
+ @field_validator("location", "path")
106
+ @classmethod
107
+ def _optional_location_valid(cls, value: str | None) -> str | None:
108
+ if value is None:
109
+ return None
110
+ return validate_utf8_size(value, "diagnostic location", 256)
111
+
112
+ @field_validator("message")
113
+ @classmethod
114
+ def _message_redacted(cls, value: str) -> str:
115
+ return redact_custom_tool_text(
116
+ value, maximum=MAX_CUSTOM_TOOL_DIAGNOSTIC_MESSAGE_UTF8
117
+ )
118
+
119
+ @model_validator(mode="after")
120
+ def _location_or_path_required(self) -> CustomToolDiagnostic:
121
+ if self.location is None and self.path is None:
122
+ raise ValueError("diagnostic requires location or path")
123
+ return self
124
+
125
+
126
+ def custom_tool_diagnostic_sort_key(
127
+ diagnostic: CustomToolDiagnostic,
128
+ ) -> tuple[str, str, str, str, str, str, tuple[tuple[str, str], ...]]:
129
+ """Return the canonical ordering key for non-semantic diagnostic lists."""
130
+ return (
131
+ diagnostic.code.value,
132
+ diagnostic.severity.value,
133
+ diagnostic.phase.value,
134
+ diagnostic.path or "",
135
+ diagnostic.location or "",
136
+ diagnostic.message,
137
+ tuple((item.key, item.value) for item in diagnostic.evidence),
138
+ )
139
+
140
+
141
+ def redact_custom_tool_text(value: Any, *, maximum: int) -> str:
142
+ """Return bounded diagnostic text with secret-looking material redacted."""
143
+ text = str(value)
144
+ policy = RedactionPolicy()
145
+ if detect_secret_candidate(
146
+ field_path="/custom_tool_diagnostic",
147
+ field_name="custom_tool_diagnostic",
148
+ value=text,
149
+ policy=policy,
150
+ ):
151
+ return policy.replacement
152
+ return validate_utf8_size(
153
+ redact_diagnostic_text(text, policy=policy), "diagnostic", maximum
154
+ )
155
+
156
+
157
+ def custom_tool_diagnostic(
158
+ code: CustomToolDiagnosticCode,
159
+ *,
160
+ phase: CustomToolDiagnosticPhase,
161
+ message: str,
162
+ location: str | None = None,
163
+ path: str | None = None,
164
+ severity: CustomToolDiagnosticSeverity = CustomToolDiagnosticSeverity.ERROR,
165
+ evidence: Mapping[str, Any] | None = None,
166
+ ) -> CustomToolDiagnostic:
167
+ """Build a deterministic custom-tool diagnostic."""
168
+ fields = tuple(
169
+ CustomToolDiagnosticEvidence(key=str(key), value=str(value))
170
+ for key, value in sorted(
171
+ (evidence or {}).items(), key=lambda item: str(item[0])
172
+ )
173
+ )
174
+ return CustomToolDiagnostic(
175
+ code=code,
176
+ severity=severity,
177
+ phase=phase,
178
+ location=location,
179
+ path=path,
180
+ message=message,
181
+ evidence=fields,
182
+ )
183
+
184
+
185
+ def malformed_input_diagnostic(
186
+ *,
187
+ phase: CustomToolDiagnosticPhase,
188
+ model_name: str,
189
+ path: str = "/",
190
+ missing_field: str | None = None,
191
+ code: CustomToolDiagnosticCode = CustomToolDiagnosticCode.SOURCE_MALFORMED,
192
+ ) -> CustomToolDiagnostic:
193
+ """Represent malformed raw input without exposing validator exception text."""
194
+ evidence: dict[str, str] = {"model": model_name}
195
+ message = "Custom tool input is malformed."
196
+ if missing_field is not None:
197
+ message = "Custom tool input is missing a required field."
198
+ evidence["field"] = missing_field
199
+ return custom_tool_diagnostic(
200
+ code,
201
+ phase=phase,
202
+ path=path,
203
+ message=message,
204
+ evidence=evidence,
205
+ )