Text Classification
PEFT
lora
document-question-answering
structured-decisions
calibration
synthetic-evaluation
Instructions to use botp/Solomon with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use botp/Solomon with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Commit ·
1d2de8a
0
Parent(s):
Duplicate from DoccyHealth/Solomon
Browse filesCo-authored-by: Archer Hume <ArcherHume@users.noreply.huggingface.co>
This view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +5 -0
- LICENSE +202 -0
- MANIFEST.json +829 -0
- MODIFICATIONS.md +118 -0
- NOTICE +98 -0
- README.md +661 -0
- adapter/adapter.safetensors +3 -0
- adapter/config.json +45 -0
- adapter/heads.npz +3 -0
- licenses/Qwen-Apache-2.0.txt +202 -0
- mlx/.gitignore +12 -0
- mlx/CONVERTER-SOURCE.json +21 -0
- mlx/LICENSE +202 -0
- mlx/MODIFICATIONS.md +25 -0
- mlx/NOTICE +78 -0
- mlx/README.md +146 -0
- mlx/bf16/LICENSE +202 -0
- mlx/bf16/MODIFICATIONS.md +75 -0
- mlx/bf16/NOTICE +78 -0
- mlx/bf16/README.md +51 -0
- mlx/bf16/base-manifest.json +197 -0
- mlx/bf16/binding.json +141 -0
- mlx/bf16/conversion.json +203 -0
- mlx/docs/UPSTREAM-MODIFICATIONS.md +75 -0
- mlx/docs/VALIDATION-20260921.md +46 -0
- mlx/examples/decide.py +21 -0
- mlx/pyproject.toml +35 -0
- mlx/requirements.cloud.lock +1072 -0
- mlx/requirements.lock +79 -0
- mlx/scripts/benchmark.py +122 -0
- mlx/scripts/benchmark_chunks.py +50 -0
- mlx/scripts/check_cuda_parity.py +172 -0
- mlx/scripts/score_parity.py +19 -0
- mlx/scripts/validate_api.py +128 -0
- mlx/src/solomon_mlx/__init__.py +5 -0
- mlx/src/solomon_mlx/_vendor/__init__.py +2 -0
- mlx/src/solomon_mlx/_vendor/contract.py +111 -0
- mlx/src/solomon_mlx/_vendor/evidence.py +156 -0
- mlx/src/solomon_mlx/_vendor/evidence_v3.py +425 -0
- mlx/src/solomon_mlx/_vendor/prompts.py +43 -0
- mlx/src/solomon_mlx/_vendor/retrieval.py +152 -0
- mlx/src/solomon_mlx/_vendor/semantics.py +71 -0
- mlx/src/solomon_mlx/api.py +321 -0
- mlx/src/solomon_mlx/artifacts.py +77 -0
- mlx/src/solomon_mlx/budget.py +71 -0
- mlx/src/solomon_mlx/cli.py +76 -0
- mlx/src/solomon_mlx/engine.py +333 -0
- mlx/src/solomon_mlx/evaluation.py +324 -0
- mlx/src/solomon_mlx/prepare.py +121 -0
- mlx/src/solomon_mlx_hub/__init__.py +5 -0
.gitattributes
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright 2026 Doccy Pty Ltd
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
MANIFEST.json
ADDED
|
@@ -0,0 +1,829 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"adapter_sha256": "d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0",
|
| 3 |
+
"approved": true,
|
| 4 |
+
"base_weights_referenced_not_redistributed": [
|
| 5 |
+
{
|
| 6 |
+
"copyright": "2026 Alibaba Cloud",
|
| 7 |
+
"license": "Apache-2.0",
|
| 8 |
+
"purpose": "the operator downloads these themselves; this repository ships only an adapter",
|
| 9 |
+
"repo": "Qwen/Qwen3.8-27B",
|
| 10 |
+
"revision": "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0"
|
| 11 |
+
}
|
| 12 |
+
],
|
| 13 |
+
"blockers": [],
|
| 14 |
+
"calibration_file_sha256": "1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9",
|
| 15 |
+
"calibration_payload_sha256": "945bad449b7f5ffc88e597277d632fbab81c3c8729e22c8babd3f4a45fe1378b",
|
| 16 |
+
"contract": "solomon-v1",
|
| 17 |
+
"descriptor": {
|
| 18 |
+
"path": "release/solomon-release.json",
|
| 19 |
+
"sha256": "7a8b02bc00465fb3a06e59604af4ab07e5b290d45b293e7ef72d4c5c7bf4a596"
|
| 20 |
+
},
|
| 21 |
+
"excluded_categories": [
|
| 22 |
+
"panels and document corpora (data/**, **/authoring/**, **/*.jsonl)",
|
| 23 |
+
"datasets and training inputs of every kind",
|
| 24 |
+
"caches, states, rendered images, score archives, annotation outputs and logs",
|
| 25 |
+
"test files, evaluation-panel builders and qualification machinery",
|
| 26 |
+
"acceptance fixture documents and any padded development document",
|
| 27 |
+
"base model weights (referenced by pinned revision, never redistributed)",
|
| 28 |
+
"GPU launch scripts, ops/ tooling, internal plans and internal cards"
|
| 29 |
+
],
|
| 30 |
+
"files": [
|
| 31 |
+
{
|
| 32 |
+
"destination": ".gitattributes",
|
| 33 |
+
"generated_by": "huggingface-cli / already committed in the clone",
|
| 34 |
+
"kind": "git_lfs_config",
|
| 35 |
+
"note": "tracks *.safetensors, *.bin, *.npz, *.pt, *.tar through git-lfs; the adapter (.safetensors) and the heads (.npz) are both covered, so no new LFS pattern is needed",
|
| 36 |
+
"staged_bytes": 217,
|
| 37 |
+
"staged_sha256": "8baff4be52225e26dd13dffb05fed3d0db821911c36d7ffd6f6d00d02ca421c7"
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"destination": "README.md",
|
| 41 |
+
"generated_by": "ops/solomon_package.py (authored for an external audience; every figure read from a measured artifact at generation time)",
|
| 42 |
+
"kind": "model_card",
|
| 43 |
+
"staged_bytes": 43920,
|
| 44 |
+
"staged_sha256": "09c96e67b59006ca0eb53113b71c08c5ab830781f86291b8721b173dcb861bc0"
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"destination": "LICENSE",
|
| 48 |
+
"generated_by": "ops/solomon_package.py (Apache-2.0 body from the archived upstream text, our copyright in the appendix)",
|
| 49 |
+
"kind": "project_license",
|
| 50 |
+
"staged_bytes": 11344,
|
| 51 |
+
"staged_sha256": "a61385b8bc4e786195136404b4975fede3c0bca526877f526482e9af93d47457"
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"destination": "NOTICE",
|
| 55 |
+
"generated_by": "ops/solomon_package.py",
|
| 56 |
+
"kind": "attribution_notice",
|
| 57 |
+
"staged_bytes": 5125,
|
| 58 |
+
"staged_sha256": "e0ff128e3b74f42d2f8de164da975d192192d9cb010330d6cf1a0fd73685bb74"
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"destination": "MODIFICATIONS.md",
|
| 62 |
+
"generated_by": "ops/solomon_package.py",
|
| 63 |
+
"kind": "change_notice_apache_4b",
|
| 64 |
+
"staged_bytes": 7207,
|
| 65 |
+
"staged_sha256": "c51ba45105ebd0a41181ca7b35f41795a3e73c86b1cd41d8d7e9e3cadac3737a"
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"destination": "requirements.lock",
|
| 69 |
+
"generated_by": "ops/solomon_package.py",
|
| 70 |
+
"kind": "dependency_pins",
|
| 71 |
+
"staged_bytes": 3943,
|
| 72 |
+
"staged_sha256": "56144aef9d15db53f7b33fd1c80e7a8d078b70800fa24d3ecc72d86e14cc2898"
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"destination": "MANIFEST.json",
|
| 76 |
+
"generated_by": "ops/solomon_package.py",
|
| 77 |
+
"kind": "manifest"
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"destination": "licenses/Qwen-Apache-2.0.txt",
|
| 81 |
+
"expected_bytes": 11544,
|
| 82 |
+
"expected_sha256": "bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a",
|
| 83 |
+
"kind": "upstream_model_license",
|
| 84 |
+
"staged_bytes": 11544,
|
| 85 |
+
"staged_sha256": "bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a"
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"destination": "adapter/adapter.safetensors",
|
| 89 |
+
"expected_bytes": 870363376,
|
| 90 |
+
"expected_sha256": "d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0",
|
| 91 |
+
"git_lfs": true,
|
| 92 |
+
"kind": "lora_adapter",
|
| 93 |
+
"staged_bytes": 870363376,
|
| 94 |
+
"staged_sha256": "d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0"
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"destination": "adapter/heads.npz",
|
| 98 |
+
"expected_bytes": 1643162,
|
| 99 |
+
"expected_sha256": "f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab",
|
| 100 |
+
"git_lfs": true,
|
| 101 |
+
"kind": "answer_heads",
|
| 102 |
+
"staged_bytes": 1643162,
|
| 103 |
+
"staged_sha256": "f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab"
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"destination": "adapter/config.json",
|
| 107 |
+
"generated_by": "ops/solomon_package.py",
|
| 108 |
+
"kind": "adapter_config",
|
| 109 |
+
"staged_bytes": 2240,
|
| 110 |
+
"staged_sha256": "7e78a6017d4400843dabf33acc9e1d43255f0f90021518eb36e991c492544436"
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"destination": "serving/serving-binding.json",
|
| 114 |
+
"kind": "serving_binding",
|
| 115 |
+
"note": "default serving binding (bf16)",
|
| 116 |
+
"staged_bytes": 6249,
|
| 117 |
+
"staged_sha256": "11b9352ab72b9e05a3d5ddbecc5a17f462c33cb6cc09dd401e062fc44dfb0831"
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"destination": "serving/serving-binding-fp32.json",
|
| 121 |
+
"expected_sha256": "eed6de24fafcbdd542858f2687cb1ca6f5e524cd9780390f4148330a0863a193",
|
| 122 |
+
"kind": "serving_binding",
|
| 123 |
+
"note": "serving binding for precision=fp32",
|
| 124 |
+
"staged_bytes": 6203,
|
| 125 |
+
"staged_sha256": "eed6de24fafcbdd542858f2687cb1ca6f5e524cd9780390f4148330a0863a193"
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"destination": "serving/serving-binding-int8.json",
|
| 129 |
+
"expected_sha256": "a711eca4c70bdcb22d41127af49ae8b90c1e23b54db4fb5308d9cb0e05fe40ea",
|
| 130 |
+
"kind": "serving_binding",
|
| 131 |
+
"note": "serving binding for precision=int8",
|
| 132 |
+
"staged_bytes": 6353,
|
| 133 |
+
"staged_sha256": "a711eca4c70bdcb22d41127af49ae8b90c1e23b54db4fb5308d9cb0e05fe40ea"
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"destination": "serving/readout-temperature-v3.json",
|
| 137 |
+
"expected_sha256": "1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9",
|
| 138 |
+
"kind": "calibration_artifact",
|
| 139 |
+
"staged_bytes": 3370,
|
| 140 |
+
"staged_sha256": "1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"destination": "serving/evidence-head.safetensors",
|
| 144 |
+
"expected_bytes": 31461804,
|
| 145 |
+
"expected_sha256": "5088019adb67e523ef7411cf75e354f1070e5752c132e50f5f3acc4feb1c0f6c",
|
| 146 |
+
"git_lfs": true,
|
| 147 |
+
"kind": "evidence_head_weights",
|
| 148 |
+
"note": "relevance head weights (float32)",
|
| 149 |
+
"staged_bytes": 31461804,
|
| 150 |
+
"staged_sha256": "5088019adb67e523ef7411cf75e354f1070e5752c132e50f5f3acc4feb1c0f6c"
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"destination": "serving/evidence-head.json",
|
| 154 |
+
"expected_bytes": 3106,
|
| 155 |
+
"expected_sha256": "b8bf1d642af9f3a830f1ee47c49bda7336d65b56b97fe3625ea1741f133fa244",
|
| 156 |
+
"kind": "evidence_head_config",
|
| 157 |
+
"note": "relevance head config incl. lexical_residual alpha",
|
| 158 |
+
"staged_bytes": 3106,
|
| 159 |
+
"staged_sha256": "b8bf1d642af9f3a830f1ee47c49bda7336d65b56b97fe3625ea1741f133fa244"
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"destination": "serving/evidence-policy.json",
|
| 163 |
+
"expected_bytes": 969,
|
| 164 |
+
"expected_sha256": "866888d26a5da9c91ffb1b418334e174a80320ea5f8d2216c2d459f2e25f3c84",
|
| 165 |
+
"kind": "evidence_policy",
|
| 166 |
+
"note": "ranked-pointer serving policy (top 3, suppressed when not stated)",
|
| 167 |
+
"staged_bytes": 969,
|
| 168 |
+
"staged_sha256": "866888d26a5da9c91ffb1b418334e174a80320ea5f8d2216c2d459f2e25f3c84"
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"destination": "serving/selection.json",
|
| 172 |
+
"generated_by": "ops/solomon_package.py",
|
| 173 |
+
"kind": "readout_selection",
|
| 174 |
+
"staged_bytes": 796,
|
| 175 |
+
"staged_sha256": "7f58b2e65e37df6409f2ac5fb774c7792fa93899269fdf76dc3446aacfae127f"
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"destination": "serving/service-export.json",
|
| 179 |
+
"generated_by": "ops/solomon_package.py",
|
| 180 |
+
"kind": "qualification_envelope",
|
| 181 |
+
"staged_bytes": 607,
|
| 182 |
+
"staged_sha256": "40ba3d4d2252554ff4e12a8f761097558af653be3ff23829e4c935bb3b0df4a8"
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"destination": "src/solomon/__init__.py",
|
| 186 |
+
"kind": "serving_code",
|
| 187 |
+
"staged_bytes": 1157,
|
| 188 |
+
"staged_sha256": "1e9e7993cd182b5ccac3eab801277cb00c802c75281bee81571890c6fdaed2c6"
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"destination": "src/solomon/api.py",
|
| 192 |
+
"kind": "serving_code",
|
| 193 |
+
"staged_bytes": 4284,
|
| 194 |
+
"staged_sha256": "21836850e511062c34c9a1c23cd78ae5ab00ea4b23c7bc1f79dc8838f1b41655"
|
| 195 |
+
},
|
| 196 |
+
{
|
| 197 |
+
"destination": "src/solomon/binding.py",
|
| 198 |
+
"kind": "serving_code",
|
| 199 |
+
"staged_bytes": 13767,
|
| 200 |
+
"staged_sha256": "09aaede5bc00b9cd77af024c92b53e7b020b7b38724a88aafa52ef8d61958f5c"
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"destination": "src/solomon/calibration.py",
|
| 204 |
+
"kind": "serving_code",
|
| 205 |
+
"staged_bytes": 11273,
|
| 206 |
+
"staged_sha256": "4e29eb430e33c7cbf074c5be153fe858210c6d4def6462c2bf9761251e91dee6"
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"destination": "src/solomon/engine.py",
|
| 210 |
+
"kind": "serving_code",
|
| 211 |
+
"staged_bytes": 7404,
|
| 212 |
+
"staged_sha256": "839442be642ac6449b32492b2ca0a4bce65de2d6095f097b053ed667304ec9fb"
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"destination": "src/solomon/engine_contract.py",
|
| 216 |
+
"kind": "serving_code",
|
| 217 |
+
"staged_bytes": 18263,
|
| 218 |
+
"staged_sha256": "3df6f2e515b765cbb07d5a281328989443795d7fdc920dc21756b4230ddf1fd5"
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"destination": "src/solomon/engine_cuda.py",
|
| 222 |
+
"kind": "serving_code",
|
| 223 |
+
"staged_bytes": 12700,
|
| 224 |
+
"staged_sha256": "28572bc9bafae9c9bd9ad42d4de2dc267ad083f126379beaf486bd4b1795641a"
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"destination": "src/solomon/engine_numerics.py",
|
| 228 |
+
"kind": "serving_code",
|
| 229 |
+
"staged_bytes": 3558,
|
| 230 |
+
"staged_sha256": "ff6779232b56469d2273cc548f4de7f7a0f6a15731c7c0986e453a2dd1180e5f"
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"destination": "src/solomon/engine_reasoning.py",
|
| 234 |
+
"kind": "serving_code",
|
| 235 |
+
"staged_bytes": 9209,
|
| 236 |
+
"staged_sha256": "87f417015f45293283bd3a2738c5745e5a2aac7a805ae89403fdc1fb7b226bb4"
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"destination": "src/solomon/engine_reference.py",
|
| 240 |
+
"kind": "serving_code",
|
| 241 |
+
"staged_bytes": 13037,
|
| 242 |
+
"staged_sha256": "5487a5b0536e481a8285ccd82dff7ff389340d4f59c36653d358088b6c4050c8"
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
"destination": "src/solomon/evidence.py",
|
| 246 |
+
"kind": "serving_code",
|
| 247 |
+
"staged_bytes": 7617,
|
| 248 |
+
"staged_sha256": "a0ece458b5c0546c1f80b48cea87ebc1c3732e83f2c0f8e58969645bc8bde2f7"
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"destination": "src/solomon/evidence_head.py",
|
| 252 |
+
"kind": "serving_code",
|
| 253 |
+
"staged_bytes": 19646,
|
| 254 |
+
"staged_sha256": "b68b93af8d956fc503c1a04bb188fc9f370a27aada4cef0a026f298c2f42dbf3"
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"destination": "src/solomon/evidence_packages.py",
|
| 258 |
+
"kind": "serving_code",
|
| 259 |
+
"staged_bytes": 24688,
|
| 260 |
+
"staged_sha256": "8e555f09c7fa96e1e135d5bb49d388b66ffbd4fc40fc1659b4cb7396ca3728c5"
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"destination": "src/solomon/evidence_selector.py",
|
| 264 |
+
"kind": "serving_code",
|
| 265 |
+
"staged_bytes": 18296,
|
| 266 |
+
"staged_sha256": "3cb6c6637c665dcb6ab401228a399ca8d5714bc9f91a2635d14b334abdf8b8de"
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
"destination": "src/solomon/heads.py",
|
| 270 |
+
"kind": "serving_code",
|
| 271 |
+
"staged_bytes": 13978,
|
| 272 |
+
"staged_sha256": "1934d3c50c57622fa2159211b5c9da024ab888ad6ba49d8b7e82365539a785a4"
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"destination": "src/solomon/prompts_two_letter.py",
|
| 276 |
+
"kind": "serving_code",
|
| 277 |
+
"staged_bytes": 4169,
|
| 278 |
+
"staged_sha256": "12e19c094e48be2881cbad79f5c1ea0ffefffdcb308013d1b45925d32b6aae6f"
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"destination": "src/solomon/readout.py",
|
| 282 |
+
"kind": "serving_code",
|
| 283 |
+
"staged_bytes": 14094,
|
| 284 |
+
"staged_sha256": "59f7f941262eba4f912dbadf4c0140f7cbb5997736f9dc3c7bae5f856763fc77"
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"destination": "src/solomon/reliability.py",
|
| 288 |
+
"kind": "serving_code",
|
| 289 |
+
"staged_bytes": 1523,
|
| 290 |
+
"staged_sha256": "08cc3b22371a314b06bc89a7807c7c0581063f8a70a86ad92b62eae442bad42a"
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"destination": "src/solomon/retrieval.py",
|
| 294 |
+
"kind": "serving_code",
|
| 295 |
+
"staged_bytes": 9155,
|
| 296 |
+
"staged_sha256": "2b7bd6603cb6df3bfe63496dd475206ff17655d48916cf974860adf335e9b155"
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"destination": "src/solomon/routing.py",
|
| 300 |
+
"kind": "serving_code",
|
| 301 |
+
"staged_bytes": 3038,
|
| 302 |
+
"staged_sha256": "9901da2c3d3a0e8dc453dae91f6c68c7a32b609418fb6e8fc41e95e3601b3f77"
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"destination": "src/solomon/semantics.py",
|
| 306 |
+
"kind": "serving_code",
|
| 307 |
+
"staged_bytes": 2910,
|
| 308 |
+
"staged_sha256": "86e1833b7f693e914cc55744ed5565ae0d436424c262f8773bb944a9f5ac65da"
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"destination": "src/solomon/service.py",
|
| 312 |
+
"kind": "serving_code",
|
| 313 |
+
"staged_bytes": 39483,
|
| 314 |
+
"staged_sha256": "8096810e0bd318255568817d0f022be8aed8e0999b7d01cf5fd2bbafb5dcc351"
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"destination": "src/solomon/service_answers.py",
|
| 318 |
+
"kind": "serving_code",
|
| 319 |
+
"staged_bytes": 20064,
|
| 320 |
+
"staged_sha256": "9075e9b9e7a713a9f843267dc5aebe8d6b9fc4dcaadbd9800c964d966e83fb06"
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"destination": "src/solomon/service_checked.py",
|
| 324 |
+
"kind": "serving_code",
|
| 325 |
+
"staged_bytes": 7596,
|
| 326 |
+
"staged_sha256": "cff9d85ea8dcb3f431dd2497a636f4d02cdc2c5d2add6f12aab9889bb29e9082"
|
| 327 |
+
},
|
| 328 |
+
{
|
| 329 |
+
"destination": "src/solomon/service_evidence.py",
|
| 330 |
+
"kind": "serving_code",
|
| 331 |
+
"staged_bytes": 7758,
|
| 332 |
+
"staged_sha256": "a2021700c36d9844f607497b7ab0d098e1f51fd775c6eb2a77940fa590335603"
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"destination": "src/solomon/service_heads.py",
|
| 336 |
+
"kind": "serving_code",
|
| 337 |
+
"staged_bytes": 9364,
|
| 338 |
+
"staged_sha256": "6dc2a0da037aea32c9bba0c3e5924c8f33779eed9b6f02c66465b3a9b960fb9c"
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"destination": "src/solomon/service_packages.py",
|
| 342 |
+
"kind": "serving_code",
|
| 343 |
+
"staged_bytes": 13181,
|
| 344 |
+
"staged_sha256": "5f30eaaac5daa80f1fc8399828ddd1c7128a34e79fe88a3440656e76629ac8d8"
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"destination": "src/solomon/service_states.py",
|
| 348 |
+
"kind": "serving_code",
|
| 349 |
+
"staged_bytes": 10657,
|
| 350 |
+
"staged_sha256": "329ecca03d06a53c3aa15568784b70cdde7c4ea63c3283e4aaec3f9018defdda"
|
| 351 |
+
},
|
| 352 |
+
{
|
| 353 |
+
"destination": "src/solomon/serving.py",
|
| 354 |
+
"kind": "serving_code",
|
| 355 |
+
"staged_bytes": 4009,
|
| 356 |
+
"staged_sha256": "978a6f1d1193dd535a5fc03fa393b6421a2cd7c85bb77b1dfa796b7fcfb92836"
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"destination": "src/solomon/units.py",
|
| 360 |
+
"kind": "serving_code",
|
| 361 |
+
"staged_bytes": 11852,
|
| 362 |
+
"staged_sha256": "0b2fbf586cf73a9f54b4fed5a7e996cc8b97196ac8ee2980888a7d8cb5713d79"
|
| 363 |
+
},
|
| 364 |
+
{
|
| 365 |
+
"destination": "mlx/.gitignore",
|
| 366 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 367 |
+
"kind": "mlx_package",
|
| 368 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 369 |
+
"staged_bytes": 126,
|
| 370 |
+
"staged_sha256": "dde5ff0f5e7a2c741e6ec76777be6a2e1d3679815bdf8f44d8ca2cee2ce0e351"
|
| 371 |
+
},
|
| 372 |
+
{
|
| 373 |
+
"destination": "mlx/CONVERTER-SOURCE.json",
|
| 374 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 375 |
+
"kind": "mlx_package",
|
| 376 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 377 |
+
"staged_bytes": 1515,
|
| 378 |
+
"staged_sha256": "60bc159ff656411b5d7fbec93fc696fc616bac88f9ad1c0e87390a003111c9c0"
|
| 379 |
+
},
|
| 380 |
+
{
|
| 381 |
+
"destination": "mlx/LICENSE",
|
| 382 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 383 |
+
"kind": "mlx_package",
|
| 384 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 385 |
+
"staged_bytes": 11344,
|
| 386 |
+
"staged_sha256": "a61385b8bc4e786195136404b4975fede3c0bca526877f526482e9af93d47457"
|
| 387 |
+
},
|
| 388 |
+
{
|
| 389 |
+
"destination": "mlx/MODIFICATIONS.md",
|
| 390 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 391 |
+
"kind": "mlx_package",
|
| 392 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 393 |
+
"staged_bytes": 1616,
|
| 394 |
+
"staged_sha256": "ff60b513fd97c5cbaa06af65972b234a6479216e94546f4852dd70f0dbf278ca"
|
| 395 |
+
},
|
| 396 |
+
{
|
| 397 |
+
"destination": "mlx/NOTICE",
|
| 398 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 399 |
+
"kind": "mlx_package",
|
| 400 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 401 |
+
"staged_bytes": 3897,
|
| 402 |
+
"staged_sha256": "7c62f7b3fde4f2f80f869be0bf592facd5e4a4d38dec826c1f6953bede6255ca"
|
| 403 |
+
},
|
| 404 |
+
{
|
| 405 |
+
"destination": "mlx/README.md",
|
| 406 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 407 |
+
"kind": "mlx_package",
|
| 408 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 409 |
+
"staged_bytes": 7417,
|
| 410 |
+
"staged_sha256": "586f53fd31ea723be1cbf0a2b5f35ed196960a231e132d8fd27e5842cc2b46a8"
|
| 411 |
+
},
|
| 412 |
+
{
|
| 413 |
+
"destination": "mlx/bf16/LICENSE",
|
| 414 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 415 |
+
"kind": "mlx_package",
|
| 416 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 417 |
+
"staged_bytes": 11344,
|
| 418 |
+
"staged_sha256": "a61385b8bc4e786195136404b4975fede3c0bca526877f526482e9af93d47457"
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"destination": "mlx/bf16/MODIFICATIONS.md",
|
| 422 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 423 |
+
"kind": "mlx_package",
|
| 424 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 425 |
+
"staged_bytes": 4195,
|
| 426 |
+
"staged_sha256": "eda88d63f04f03cb169579d527ceea4eb71bf44eae5c305bc688fc0e2a3fdc78"
|
| 427 |
+
},
|
| 428 |
+
{
|
| 429 |
+
"destination": "mlx/bf16/NOTICE",
|
| 430 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 431 |
+
"kind": "mlx_package",
|
| 432 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 433 |
+
"staged_bytes": 3897,
|
| 434 |
+
"staged_sha256": "7c62f7b3fde4f2f80f869be0bf592facd5e4a4d38dec826c1f6953bede6255ca"
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"destination": "mlx/bf16/README.md",
|
| 438 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 439 |
+
"kind": "mlx_package",
|
| 440 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 441 |
+
"staged_bytes": 3063,
|
| 442 |
+
"staged_sha256": "1e3aa92ff4687d6e46520473bcc9c207b492d9239f1f882bff185c716ecee320"
|
| 443 |
+
},
|
| 444 |
+
{
|
| 445 |
+
"destination": "mlx/bf16/base-manifest.json",
|
| 446 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 447 |
+
"kind": "mlx_package",
|
| 448 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 449 |
+
"staged_bytes": 6434,
|
| 450 |
+
"staged_sha256": "e62a6942465b43f7f47616e36a16d6f32a1bd9daa5124dd26bf61b8eab0c3b6d"
|
| 451 |
+
},
|
| 452 |
+
{
|
| 453 |
+
"destination": "mlx/bf16/binding.json",
|
| 454 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 455 |
+
"kind": "mlx_package",
|
| 456 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 457 |
+
"staged_bytes": 12306,
|
| 458 |
+
"staged_sha256": "6d45715aa040fad98b061ff2cbafb35b047143ef2475646cee3df7a334f4d530"
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"destination": "mlx/bf16/conversion.json",
|
| 462 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 463 |
+
"kind": "mlx_package",
|
| 464 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 465 |
+
"staged_bytes": 6934,
|
| 466 |
+
"staged_sha256": "fb3db797acdf96c9eca2b6dfef2d6d385705aeade387011d45ea16b91b510c66"
|
| 467 |
+
},
|
| 468 |
+
{
|
| 469 |
+
"destination": "mlx/docs/UPSTREAM-MODIFICATIONS.md",
|
| 470 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 471 |
+
"kind": "mlx_package",
|
| 472 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 473 |
+
"staged_bytes": 4195,
|
| 474 |
+
"staged_sha256": "eda88d63f04f03cb169579d527ceea4eb71bf44eae5c305bc688fc0e2a3fdc78"
|
| 475 |
+
},
|
| 476 |
+
{
|
| 477 |
+
"destination": "mlx/docs/VALIDATION-20260921.md",
|
| 478 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 479 |
+
"kind": "mlx_package",
|
| 480 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 481 |
+
"staged_bytes": 2928,
|
| 482 |
+
"staged_sha256": "86afe1be02ed55a75c2b2a1663898f20cc536371f5dcd2df0f701f7a30ae9a47"
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"destination": "mlx/examples/decide.py",
|
| 486 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 487 |
+
"kind": "mlx_package",
|
| 488 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 489 |
+
"staged_bytes": 763,
|
| 490 |
+
"staged_sha256": "1a004e8a474f0458a4b84024098dfcb44ec5a24a795d742d266e7557ac9fd170"
|
| 491 |
+
},
|
| 492 |
+
{
|
| 493 |
+
"destination": "mlx/pyproject.toml",
|
| 494 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 495 |
+
"kind": "mlx_package",
|
| 496 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 497 |
+
"staged_bytes": 1115,
|
| 498 |
+
"staged_sha256": "e7822f6addbb909f4424084e3cca5eb11a7f5cb929b4b5742b1690a2bed756b5"
|
| 499 |
+
},
|
| 500 |
+
{
|
| 501 |
+
"destination": "mlx/requirements.cloud.lock",
|
| 502 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 503 |
+
"kind": "mlx_package",
|
| 504 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 505 |
+
"staged_bytes": 74492,
|
| 506 |
+
"staged_sha256": "4b60f433f1f67289db1db68630d011aea1565b50cf518c1e7461d7c2b0e2599b"
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"destination": "mlx/requirements.lock",
|
| 510 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 511 |
+
"kind": "mlx_package",
|
| 512 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 513 |
+
"staged_bytes": 1338,
|
| 514 |
+
"staged_sha256": "cb2a81cc73252bc54570e035483d68e24253c98223e0e65373df5995bd99dc5a"
|
| 515 |
+
},
|
| 516 |
+
{
|
| 517 |
+
"destination": "mlx/scripts/benchmark.py",
|
| 518 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 519 |
+
"kind": "mlx_package",
|
| 520 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 521 |
+
"staged_bytes": 5074,
|
| 522 |
+
"staged_sha256": "7a9ee62cae81bf4d05d5ad17760bfa510886812a017eb0bc8d9cab68dcd1cab6"
|
| 523 |
+
},
|
| 524 |
+
{
|
| 525 |
+
"destination": "mlx/scripts/benchmark_chunks.py",
|
| 526 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 527 |
+
"kind": "mlx_package",
|
| 528 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 529 |
+
"staged_bytes": 1897,
|
| 530 |
+
"staged_sha256": "216e10981bdff42d04269082ae2317ab25a161c80504813aa74ee1a55b7ca167"
|
| 531 |
+
},
|
| 532 |
+
{
|
| 533 |
+
"destination": "mlx/scripts/check_cuda_parity.py",
|
| 534 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 535 |
+
"kind": "mlx_package",
|
| 536 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 537 |
+
"staged_bytes": 7614,
|
| 538 |
+
"staged_sha256": "082ae6c535f52d6b386d3348222515ef564b38efaf59fd8d6b262d00867b0a24"
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"destination": "mlx/scripts/score_parity.py",
|
| 542 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 543 |
+
"kind": "mlx_package",
|
| 544 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 545 |
+
"staged_bytes": 542,
|
| 546 |
+
"staged_sha256": "ddc84f869bccd5d2c270f6abf2a0862c59ec7c0ebdc3497959ba35c16bb11b7a"
|
| 547 |
+
},
|
| 548 |
+
{
|
| 549 |
+
"destination": "mlx/scripts/validate_api.py",
|
| 550 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 551 |
+
"kind": "mlx_package",
|
| 552 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 553 |
+
"staged_bytes": 5852,
|
| 554 |
+
"staged_sha256": "f29c49ac600314491c36c43b780b92958dea56253377b4b64a2da7ecb4b57a28"
|
| 555 |
+
},
|
| 556 |
+
{
|
| 557 |
+
"destination": "mlx/src/solomon_mlx/__init__.py",
|
| 558 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 559 |
+
"kind": "mlx_package",
|
| 560 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 561 |
+
"staged_bytes": 132,
|
| 562 |
+
"staged_sha256": "714a5439b33780d250c404938cd062c0d6809f83f21b59f89997bd168469925a"
|
| 563 |
+
},
|
| 564 |
+
{
|
| 565 |
+
"destination": "mlx/src/solomon_mlx/_vendor/__init__.py",
|
| 566 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 567 |
+
"kind": "mlx_package",
|
| 568 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 569 |
+
"staged_bytes": 113,
|
| 570 |
+
"staged_sha256": "77defd15cc47661e0e9a31275e7fd59e979f3f9a6429671d8199f6002dca6c2c"
|
| 571 |
+
},
|
| 572 |
+
{
|
| 573 |
+
"destination": "mlx/src/solomon_mlx/_vendor/contract.py",
|
| 574 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 575 |
+
"kind": "mlx_package",
|
| 576 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 577 |
+
"staged_bytes": 6474,
|
| 578 |
+
"staged_sha256": "7c6607179a028f30b462349a86f9cf7d0ec2652e0a1c7c8c24649b6ce71df697"
|
| 579 |
+
},
|
| 580 |
+
{
|
| 581 |
+
"destination": "mlx/src/solomon_mlx/_vendor/evidence.py",
|
| 582 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 583 |
+
"kind": "mlx_package",
|
| 584 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 585 |
+
"staged_bytes": 7730,
|
| 586 |
+
"staged_sha256": "18a4978a27d6bbd3f7daaa34836d1820303c4ff581b0dfda877aab586392293b"
|
| 587 |
+
},
|
| 588 |
+
{
|
| 589 |
+
"destination": "mlx/src/solomon_mlx/_vendor/evidence_v3.py",
|
| 590 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 591 |
+
"kind": "mlx_package",
|
| 592 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 593 |
+
"staged_bytes": 24783,
|
| 594 |
+
"staged_sha256": "6ff3da1e920c082e9b3629ca0230007262f2ce69fd921b89dd4b3e67511b3a64"
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"destination": "mlx/src/solomon_mlx/_vendor/prompts.py",
|
| 598 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 599 |
+
"kind": "mlx_package",
|
| 600 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 601 |
+
"staged_bytes": 4693,
|
| 602 |
+
"staged_sha256": "8bfb5a12d625664c8830f5cf243aac04d1e973bfe4f5ecfc8221021f09c318df"
|
| 603 |
+
},
|
| 604 |
+
{
|
| 605 |
+
"destination": "mlx/src/solomon_mlx/_vendor/retrieval.py",
|
| 606 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 607 |
+
"kind": "mlx_package",
|
| 608 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 609 |
+
"staged_bytes": 9261,
|
| 610 |
+
"staged_sha256": "11e7bbb1a84ba837eac3768d6e882f44a557be25d62729c8a39dd5cb870c0932"
|
| 611 |
+
},
|
| 612 |
+
{
|
| 613 |
+
"destination": "mlx/src/solomon_mlx/_vendor/semantics.py",
|
| 614 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 615 |
+
"kind": "mlx_package",
|
| 616 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 617 |
+
"staged_bytes": 3051,
|
| 618 |
+
"staged_sha256": "b580d3c114536a6faf58bcd92d2c61028f80891a19d78d6a17ed585948abfc15"
|
| 619 |
+
},
|
| 620 |
+
{
|
| 621 |
+
"destination": "mlx/src/solomon_mlx/api.py",
|
| 622 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 623 |
+
"kind": "mlx_package",
|
| 624 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 625 |
+
"staged_bytes": 13772,
|
| 626 |
+
"staged_sha256": "bae9fdd3ef6b395142ec5c099635cc9ba90f7f33c7423f99caf6009f51d4fd3c"
|
| 627 |
+
},
|
| 628 |
+
{
|
| 629 |
+
"destination": "mlx/src/solomon_mlx/artifacts.py",
|
| 630 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 631 |
+
"kind": "mlx_package",
|
| 632 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 633 |
+
"staged_bytes": 2614,
|
| 634 |
+
"staged_sha256": "0b3d102a2a04d88b2a1f3eb8a22506f626191615d779bfd53a4377824e6c239b"
|
| 635 |
+
},
|
| 636 |
+
{
|
| 637 |
+
"destination": "mlx/src/solomon_mlx/budget.py",
|
| 638 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 639 |
+
"kind": "mlx_package",
|
| 640 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 641 |
+
"staged_bytes": 2875,
|
| 642 |
+
"staged_sha256": "f72614686c19e1d923e6bc23d4353e8b1ac150863565939ae4a3831bc4ecd211"
|
| 643 |
+
},
|
| 644 |
+
{
|
| 645 |
+
"destination": "mlx/src/solomon_mlx/cli.py",
|
| 646 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 647 |
+
"kind": "mlx_package",
|
| 648 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 649 |
+
"staged_bytes": 2990,
|
| 650 |
+
"staged_sha256": "0a6be4cd03621963ec5f73a8af71224cb8b40ae88232477d8370b7d3b9b75021"
|
| 651 |
+
},
|
| 652 |
+
{
|
| 653 |
+
"destination": "mlx/src/solomon_mlx/engine.py",
|
| 654 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 655 |
+
"kind": "mlx_package",
|
| 656 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 657 |
+
"staged_bytes": 15359,
|
| 658 |
+
"staged_sha256": "13c27c3fbca576ae0d70262c2a75c9382df3b4fcfd8a11996d125750883b648a"
|
| 659 |
+
},
|
| 660 |
+
{
|
| 661 |
+
"destination": "mlx/src/solomon_mlx/evaluation.py",
|
| 662 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 663 |
+
"kind": "mlx_package",
|
| 664 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 665 |
+
"staged_bytes": 13906,
|
| 666 |
+
"staged_sha256": "bb9f50d184527e21139b9ffb5e9d1613bc30822ccd7cf06b7b7f8b1cc8b50674"
|
| 667 |
+
},
|
| 668 |
+
{
|
| 669 |
+
"destination": "mlx/src/solomon_mlx/prepare.py",
|
| 670 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 671 |
+
"kind": "mlx_package",
|
| 672 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 673 |
+
"staged_bytes": 5513,
|
| 674 |
+
"staged_sha256": "dda9879a9ddc1c3f6dcf0df52b3a244b2ca7920946bbd29ddc8e1c0f9944b887"
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"destination": "mlx/src/solomon_mlx_hub/__init__.py",
|
| 678 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 679 |
+
"kind": "mlx_package",
|
| 680 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 681 |
+
"staged_bytes": 248,
|
| 682 |
+
"staged_sha256": "9132679f7a5826d1f472cef6a42068ead04b9c4737d2c5fa667d8cb8437212e2"
|
| 683 |
+
},
|
| 684 |
+
{
|
| 685 |
+
"destination": "mlx/src/solomon_mlx_hub/__main__.py",
|
| 686 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 687 |
+
"kind": "mlx_package",
|
| 688 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 689 |
+
"staged_bytes": 1852,
|
| 690 |
+
"staged_sha256": "86cf93d7c2a2342e1f9babc4981f4dbd1255db08d79406ec0c3faaff91762f1c"
|
| 691 |
+
},
|
| 692 |
+
{
|
| 693 |
+
"destination": "mlx/src/solomon_mlx_hub/data/base-manifest.json",
|
| 694 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 695 |
+
"kind": "mlx_package",
|
| 696 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 697 |
+
"staged_bytes": 6434,
|
| 698 |
+
"staged_sha256": "e62a6942465b43f7f47616e36a16d6f32a1bd9daa5124dd26bf61b8eab0c3b6d"
|
| 699 |
+
},
|
| 700 |
+
{
|
| 701 |
+
"destination": "mlx/src/solomon_mlx_hub/data/release.json",
|
| 702 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 703 |
+
"kind": "mlx_package",
|
| 704 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 705 |
+
"staged_bytes": 8582,
|
| 706 |
+
"staged_sha256": "3b07f07cdb19897ecec0694cfe2eb745a8d8e99c573ec74dc2411b965715f70a"
|
| 707 |
+
},
|
| 708 |
+
{
|
| 709 |
+
"destination": "mlx/src/solomon_mlx_hub/prepare.py",
|
| 710 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 711 |
+
"kind": "mlx_package",
|
| 712 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 713 |
+
"staged_bytes": 8707,
|
| 714 |
+
"staged_sha256": "9d433eb7b242aaa83e1f3c3f4a2b9f99cf410299f99c133732f6ff5559a9b202"
|
| 715 |
+
},
|
| 716 |
+
{
|
| 717 |
+
"destination": "mlx/tests/test_artifacts_and_evaluation.py",
|
| 718 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 719 |
+
"kind": "mlx_package",
|
| 720 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 721 |
+
"staged_bytes": 2745,
|
| 722 |
+
"staged_sha256": "10bbfb9b9e7d66c7dae6fd1e2ca2980572e4a81f93f847c3a0f49525d8053a23"
|
| 723 |
+
},
|
| 724 |
+
{
|
| 725 |
+
"destination": "mlx/tests/test_budget.py",
|
| 726 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 727 |
+
"kind": "mlx_package",
|
| 728 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 729 |
+
"staged_bytes": 780,
|
| 730 |
+
"staged_sha256": "4faef6c3ad8aa65df057babb86d4092943a4a262bb859445ee1dde1e29a826d5"
|
| 731 |
+
},
|
| 732 |
+
{
|
| 733 |
+
"destination": "mlx/tests/test_contract.py",
|
| 734 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 735 |
+
"kind": "mlx_package",
|
| 736 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 737 |
+
"staged_bytes": 3393,
|
| 738 |
+
"staged_sha256": "b4ac6dba4ac70f1f8c8c145fba62d276d3af9dc7ab833652c92f85a3048e5f26"
|
| 739 |
+
},
|
| 740 |
+
{
|
| 741 |
+
"destination": "mlx/tests/test_hub.py",
|
| 742 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 743 |
+
"kind": "mlx_package",
|
| 744 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 745 |
+
"staged_bytes": 7227,
|
| 746 |
+
"staged_sha256": "5926ceb8e970f1cc3c7a0b9fda2d35638f31eb12009d7232fabde4308247c633"
|
| 747 |
+
},
|
| 748 |
+
{
|
| 749 |
+
"destination": "mlx/tests/test_metal_primitives.py",
|
| 750 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 751 |
+
"kind": "mlx_package",
|
| 752 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 753 |
+
"staged_bytes": 1704,
|
| 754 |
+
"staged_sha256": "2d88596fba6cb6b16acb9af958add22e9b21d367dbd4fcc277878973a5e3c30a"
|
| 755 |
+
},
|
| 756 |
+
{
|
| 757 |
+
"destination": "mlx/tests/test_parity.py",
|
| 758 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 759 |
+
"kind": "mlx_package",
|
| 760 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 761 |
+
"staged_bytes": 763,
|
| 762 |
+
"staged_sha256": "77487c307fe272a99e1f17b9e26e30dc987127a7c47fc7c2c8a545bca174b881"
|
| 763 |
+
},
|
| 764 |
+
{
|
| 765 |
+
"destination": "mlx/tests/test_processor.py",
|
| 766 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 767 |
+
"kind": "mlx_package",
|
| 768 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 769 |
+
"staged_bytes": 853,
|
| 770 |
+
"staged_sha256": "521586bf405dced3dc8ebe890c2ad3f42dd99792c08fd84e9d0a4398642b3727"
|
| 771 |
+
},
|
| 772 |
+
{
|
| 773 |
+
"destination": "mlx/tests/test_tiny_decoder.py",
|
| 774 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 775 |
+
"kind": "mlx_package",
|
| 776 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 777 |
+
"staged_bytes": 2369,
|
| 778 |
+
"staged_sha256": "e2a7496551da6d6690ee55c2d299a4759122bcfa77d48f0424bac2892a555dcf"
|
| 779 |
+
},
|
| 780 |
+
{
|
| 781 |
+
"destination": "mlx/tests/test_tiny_library.py",
|
| 782 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 783 |
+
"kind": "mlx_package",
|
| 784 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 785 |
+
"staged_bytes": 6658,
|
| 786 |
+
"staged_sha256": "03a2887be6713671ce1307d24c1e41e5d5025423c24230c4d7e99743a9b50bc8"
|
| 787 |
+
},
|
| 788 |
+
{
|
| 789 |
+
"destination": "mlx/uv.lock",
|
| 790 |
+
"generated_by": "the MLX packaging step (separate owner); staged in place",
|
| 791 |
+
"kind": "mlx_package",
|
| 792 |
+
"note": "part of the optional Apple-silicon package under mlx/; not loaded by the serving layer under src/",
|
| 793 |
+
"staged_bytes": 285374,
|
| 794 |
+
"staged_sha256": "e413d49af059f183f7fd4a39fccae8cc2c3908a4e7562926ea8de248880ddbc7"
|
| 795 |
+
}
|
| 796 |
+
],
|
| 797 |
+
"hash_or_size_mismatch": [],
|
| 798 |
+
"heads_sha256": "f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab",
|
| 799 |
+
"license": "apache-2.0",
|
| 800 |
+
"live_acceptance_passed_for_this_binding": true,
|
| 801 |
+
"missing_sources": [],
|
| 802 |
+
"model": "Solomon",
|
| 803 |
+
"not_shipped_though_statically_reachable": [
|
| 804 |
+
"a smoke test carrying an embedded synthetic document",
|
| 805 |
+
"the answer-head training loop",
|
| 806 |
+
"the benchmark-panel builder (panel authoring and validation, not a serving file)",
|
| 807 |
+
"the evaluation harness",
|
| 808 |
+
"the superseded training-side confidence layer",
|
| 809 |
+
"the training-side calibration fit",
|
| 810 |
+
"the training/evaluation data module"
|
| 811 |
+
],
|
| 812 |
+
"not_staged": [],
|
| 813 |
+
"owner_release_decision_recorded": true,
|
| 814 |
+
"policy": "DEFAULT DENY. Only the destinations listed in `files` may exist in the repository. `ops/solomon_package.py --enforce` walks the working tree and fails on anything else.",
|
| 815 |
+
"publishing_performed": false,
|
| 816 |
+
"readout": "four_collapsed",
|
| 817 |
+
"repo_id": "DoccyHealth/Solomon",
|
| 818 |
+
"runtime_fingerprint": "7d529382321e0e14131a643920d7522b85d1b521d249db89fba839b3fd0f8bea",
|
| 819 |
+
"schema": "solomon.distribution-manifest.v1",
|
| 820 |
+
"serving_binding_sha256": "0add0efda28902180db757a12160953e0f5d8dc303decc27b2cfda84db900da8",
|
| 821 |
+
"staged_count": 104,
|
| 822 |
+
"staged_into": "release/Solomon",
|
| 823 |
+
"totals": {
|
| 824 |
+
"bytes_from_disk": 903843866,
|
| 825 |
+
"entries": 104,
|
| 826 |
+
"ready": 104
|
| 827 |
+
},
|
| 828 |
+
"version": "1.1.0"
|
| 829 |
+
}
|
MODIFICATIONS.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Statement of changes
|
| 2 |
+
|
| 3 |
+
Apache License 2.0, section 4(b): prominent notice that files carry modifications.
|
| 4 |
+
|
| 5 |
+
## What is modified
|
| 6 |
+
|
| 7 |
+
**No upstream source file is modified.** No file from `Qwen/Qwen3.8-27B` is edited,
|
| 8 |
+
renamed, patched or redistributed in this repository, with one exception: the
|
| 9 |
+
upstream licence text is reproduced byte-for-byte at `licenses/Qwen-Apache-2.0.txt`
|
| 10 |
+
(sha256 `bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a`) because section 4(a) requires it. That file is
|
| 11 |
+
unmodified and carries the upstream copyright.
|
| 12 |
+
|
| 13 |
+
The modification this work carries is not an edit to a source file. It is a set
|
| 14 |
+
of **trained parameters applied to the base model at inference time**, plus an
|
| 15 |
+
original serving layer that reads the model's logits. Concretely:
|
| 16 |
+
|
| 17 |
+
| Change | Artifact | sha256 |
|
| 18 |
+
|---|---|---|
|
| 19 |
+
| LoRA adapter, rank 64, question-side placement, float32 | `adapter/adapter.safetensors` | `d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0` |
|
| 20 |
+
| Trained linear answer heads | `adapter/heads.npz` | `f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab` |
|
| 21 |
+
| Readout calibration, one positive scalar per answer type | `serving/readout-temperature-v3.json` | file `1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9` / payload `945bad449b7f5ffc88e597277d632fbab81c3c8729e22c8babd3f4a45fe1378b` |
|
| 22 |
+
| Runtime identity binding (bf16, default) | `serving/serving-binding.json` | payload `0add0efda28902180db757a12160953e0f5d8dc303decc27b2cfda84db900da8` |
|
| 23 |
+
| Runtime identity binding (fp32) | `serving/serving-binding-fp32.json` | payload `517f263000cf65457751c4fba519221d48ac550e060b241f198b007ae88c59db` |
|
| 24 |
+
| Runtime identity binding (int8) | `serving/serving-binding-int8.json` | payload `b550254777ceb3f53e7e10e15f7dc9f80f620ddd9c1ed69592190da5f2107f16` |
|
| 25 |
+
| Experimental evidence head weights | `serving/evidence-head.safetensors` | `5088019adb67e523ef7411cf75e354f1070e5752c132e50f5f3acc4feb1c0f6c` |
|
| 26 |
+
| Experimental evidence head config | `serving/evidence-head.json` | `b8bf1d642af9f3a830f1ee47c49bda7336d65b56b97fe3625ea1741f133fa244` |
|
| 27 |
+
| Experimental evidence policy | `serving/evidence-policy.json` | `866888d26a5da9c91ffb1b418334e174a80320ea5f8d2216c2d459f2e25f3c84` |
|
| 28 |
+
| Serving layer (original work, not derived from upstream code) | `src/` | see `MANIFEST.json` |
|
| 29 |
+
|
| 30 |
+
Base model, unmodified and not redistributed: `Qwen/Qwen3.8-27B` at revision
|
| 31 |
+
`1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`, Copyright 2026 Alibaba Cloud, Apache-2.0.
|
| 32 |
+
|
| 33 |
+
The v1.1 adapter and heads were trained on 21 September 2026 (v1.0: 16 to 20 September 2026). The shipped artifacts are
|
| 34 |
+
identified by the checksums in the table above and in `MANIFEST.json`.
|
| 35 |
+
|
| 36 |
+
## Which files carry a change notice
|
| 37 |
+
|
| 38 |
+
| File | Why |
|
| 39 |
+
|---|---|
|
| 40 |
+
| `NOTICE` | Section 4(b) and 4(c) statement, carried with every copy |
|
| 41 |
+
| `MODIFICATIONS.md` | this file |
|
| 42 |
+
| `README.md` | names the base model, the pinned revision and the derivative relationship in the front matter and in the body |
|
| 43 |
+
| `adapter/config.json` | machine-readable record of the base repo, the pinned revision and both weight checksums |
|
| 44 |
+
| `serving/serving-binding.json` | pins the exact runtime the weights were measured on and refuses to load against a different one |
|
| 45 |
+
|
| 46 |
+
No file under `src/` carries an upstream change notice, because no file under
|
| 47 |
+
`src/` contains upstream code. Every file there is original work, written for
|
| 48 |
+
this project, and is covered by the repository's own Apache-2.0 `LICENSE` and by
|
| 49 |
+
the copyright line in `NOTICE`.
|
| 50 |
+
|
| 51 |
+
All of the changes described above — the adapter, the heads, the calibration, the
|
| 52 |
+
serving binding and the serving layer — are Copyright 2026
|
| 53 |
+
Doccy Pty Ltd and licensed under Apache-2.0.
|
| 54 |
+
|
| 55 |
+
## Third-party text scan
|
| 56 |
+
|
| 57 |
+
Before release, **every file staged into this repository was scanned for text
|
| 58 |
+
originating in third-party source documents.** The scan compared normalised
|
| 59 |
+
6-gram and 8-gram shingles of every staged text file against:
|
| 60 |
+
|
| 61 |
+
1. the 42 third-party source records the training and evaluation panels were
|
| 62 |
+
built from (Apache-2.0, MIT, BSD-3-Clause, CC BY 4.0, CC BY-SA 4.0, CC0,
|
| 63 |
+
OGL v3.0 and US-government public-domain assertions); and
|
| 64 |
+
2. every generated panel and document corpus on disk.
|
| 65 |
+
|
| 66 |
+
**Result: no third-party document text is present in any shipped file.** The
|
| 67 |
+
only matches were:
|
| 68 |
+
|
| 69 |
+
* the reproduced Apache-2.0 licence text at `licenses/Qwen-Apache-2.0.txt`, which
|
| 70 |
+
matches an Apache-2.0 licence document held in the evaluation corpus and is
|
| 71 |
+
required to be here verbatim; and
|
| 72 |
+
* the phrase *"A missing fact is not a negative fact"*, which is **our own
|
| 73 |
+
prompt-template wording** appearing in our own evaluation panels, not
|
| 74 |
+
third-party text entering our prompts.
|
| 75 |
+
|
| 76 |
+
Acceptance fixtures are excluded from this repository entirely. The fixture
|
| 77 |
+
documents used in live acceptance are original synthetic text authored for this
|
| 78 |
+
project and held in tooling that is not distributed.
|
| 79 |
+
|
| 80 |
+
Re-run the scan with `ops/solomon_package.py --scan` in the source project.
|
| 81 |
+
|
| 82 |
+
## Maintainer notes
|
| 83 |
+
|
| 84 |
+
These warnings used to live in a `PUSH.md` that carried its own instruction to be
|
| 85 |
+
deleted before the repository was made public. The repository is public now, so
|
| 86 |
+
that file is gone — from the manifest and from the tree — and the parts of it that
|
| 87 |
+
are still true are kept here.
|
| 88 |
+
|
| 89 |
+
**Never mutate a published revision.** The serving binding pins by hash and
|
| 90 |
+
consumers pin by revision. If something is wrong with a published revision, push a
|
| 91 |
+
**new** revision and a **new** tag. Do not force-push over a revision that has
|
| 92 |
+
already been fetched: a consumer who pinned it would silently get different weights
|
| 93 |
+
under a hash they already trusted.
|
| 94 |
+
|
| 95 |
+
**Do not trust a fetch tool's exit code.** The remote-volume fetch used to retrieve the adapter PRINTS "No such file or directory" AND EXITS 0 on a wrong path: a failed download is indistinguishable from a successful one by return code. Never trust the exit status; check that the file exists and that its sha256 matches before treating a fetch as done.
|
| 96 |
+
The 870 MB adapter in this repository was fetched that way, and the only thing that
|
| 97 |
+
made the fetch trustworthy was re-hashing the file afterwards. Verify what you
|
| 98 |
+
downloaded from here the same way:
|
| 99 |
+
|
| 100 |
+
```sh
|
| 101 |
+
shasum -a 256 adapter/adapter.safetensors # d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0
|
| 102 |
+
shasum -a 256 adapter/heads.npz # f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
`MANIFEST.json` carries the size and sha256 of every file here.
|
| 106 |
+
|
| 107 |
+
**Both weight files must go through git-lfs.** `.gitattributes` tracks
|
| 108 |
+
`*.safetensors` and `*.npz`; confirm with `git lfs ls-files` before committing. An
|
| 109 |
+
870 MB blob committed outside LFS has to be undone by rewriting history.
|
| 110 |
+
|
| 111 |
+
**Every generated file here comes from `release/solomon-release.json`.** Editing a
|
| 112 |
+
generated file by hand breaks the manifest hash and is caught by
|
| 113 |
+
`ops/solomon_package.py --enforce` as `DRIFTED_SINCE_STAGING`. Change the descriptor
|
| 114 |
+
or the generator and re-stage.
|
| 115 |
+
|
| 116 |
+
**A calibration may not be carried onto a different adapter.** The temperatures were
|
| 117 |
+
fitted on this model's logits. Refit and register them for a new adapter, or ship no
|
| 118 |
+
calibration and serve at T = 1.0, which is always permitted.
|
NOTICE
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Solomon v1.1.0
|
| 2 |
+
Copyright 2026 Doccy Pty Ltd
|
| 3 |
+
|
| 4 |
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
| 5 |
+
this work except in compliance with the License. You may obtain a copy of the
|
| 6 |
+
License in the LICENSE file distributed with this work, or at
|
| 7 |
+
|
| 8 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
|
| 10 |
+
--------------------------------------------------------------------------------
|
| 11 |
+
ATTRIBUTION FOR THE BASE MODEL (Apache License 2.0, section 4(c))
|
| 12 |
+
--------------------------------------------------------------------------------
|
| 13 |
+
|
| 14 |
+
This work is a DERIVATIVE WORK of:
|
| 15 |
+
|
| 16 |
+
Qwen/Qwen3.8-27B
|
| 17 |
+
Copyright 2026 Alibaba Cloud
|
| 18 |
+
Licensed under the Apache License, Version 2.0
|
| 19 |
+
Pinned revision: 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0
|
| 20 |
+
Licence text: licenses/Qwen-Apache-2.0.txt (sha256 bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a, 11544 bytes,
|
| 21 |
+
the exact bytes served at the pinned revision)
|
| 22 |
+
|
| 23 |
+
The base model weights are NOT redistributed in this repository. They are
|
| 24 |
+
referenced by the pinned revision above and downloaded by the operator directly
|
| 25 |
+
from the upstream repository under the upstream licence.
|
| 26 |
+
|
| 27 |
+
Upstream NOTICE file: NONE. A NOTICE file is absent from Qwen/Qwen3.8-27B at the
|
| 28 |
+
pinned revision (HTTP 404, retrieved 2026-09-18T03:49Z without credentials).
|
| 29 |
+
Apache-2.0 section 4(d) therefore imposes no carry-forward obligation here. No
|
| 30 |
+
upstream attribution text has been invented or paraphrased.
|
| 31 |
+
|
| 32 |
+
"Qwen" and "Alibaba Cloud" are used nominatively, to identify the base model
|
| 33 |
+
this adapter was trained against. Apache-2.0 section 6 grants no trademark
|
| 34 |
+
rights and none are claimed or implied. Nothing here states or implies any
|
| 35 |
+
endorsement, sponsorship or affiliation.
|
| 36 |
+
|
| 37 |
+
--------------------------------------------------------------------------------
|
| 38 |
+
STATEMENT OF CHANGES (Apache License 2.0, section 4(b))
|
| 39 |
+
--------------------------------------------------------------------------------
|
| 40 |
+
|
| 41 |
+
No upstream source file is modified, and no upstream file is redistributed
|
| 42 |
+
except the unmodified licence text at licenses/Qwen-Apache-2.0.txt.
|
| 43 |
+
|
| 44 |
+
The modification this work carries is a trained LoRA adapter and a set of
|
| 45 |
+
trained linear answer heads, applied to the base model at inference time:
|
| 46 |
+
|
| 47 |
+
* LoRA adapter, rank 64, question-side placement, float32
|
| 48 |
+
adapter/adapter.safetensors
|
| 49 |
+
sha256 d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0
|
| 50 |
+
870363376 bytes
|
| 51 |
+
* Trained linear answer heads
|
| 52 |
+
adapter/heads.npz
|
| 53 |
+
sha256 f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab
|
| 54 |
+
1643162 bytes
|
| 55 |
+
* Readout calibration (one positive scalar per task)
|
| 56 |
+
serving/readout-temperature-v3.json
|
| 57 |
+
file sha256 1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9
|
| 58 |
+
payload sha256 945bad449b7f5ffc88e597277d632fbab81c3c8729e22c8babd3f4a45fe1378b
|
| 59 |
+
|
| 60 |
+
The v1.1 adapter and heads were trained on 21 September 2026 (v1.0: 16 to 20 September 2026). The adapter and the heads
|
| 61 |
+
are identified by the checksums above. Full change detail is in MODIFICATIONS.md.
|
| 62 |
+
|
| 63 |
+
--------------------------------------------------------------------------------
|
| 64 |
+
THIRD-PARTY CONTENT IN THIS REPOSITORY
|
| 65 |
+
--------------------------------------------------------------------------------
|
| 66 |
+
|
| 67 |
+
The only third-party content distributed here is the unmodified Apache License
|
| 68 |
+
2.0 text at licenses/Qwen-Apache-2.0.txt, reproduced to satisfy section 4(a).
|
| 69 |
+
|
| 70 |
+
No training document, evaluation panel, dataset, corpus, rendered page, cached
|
| 71 |
+
state, score archive or acceptance fixture is distributed. Every file in this
|
| 72 |
+
repository was scanned for text originating in third-party source documents
|
| 73 |
+
before release; see MODIFICATIONS.md, "Third-party text scan".
|
| 74 |
+
|
| 75 |
+
Everything else in this repository -- the serving code under src/, the adapter
|
| 76 |
+
and head weights, the calibration artifact, the serving binding and the
|
| 77 |
+
documentation -- is original work of Doccy Pty Ltd, licensed under
|
| 78 |
+
Apache-2.0.
|
| 79 |
+
|
| 80 |
+
--------------------------------------------------------------------------------
|
| 81 |
+
TRAINING-DATA PROVENANCE
|
| 82 |
+
--------------------------------------------------------------------------------
|
| 83 |
+
|
| 84 |
+
The v1.1 adapter was trained on real public documents (Australian government
|
| 85 |
+
pages under CC BY 4.0, UK Crown copyright under the Open Government Licence v3.0,
|
| 86 |
+
and US federal government works) and on synthetic documents, some of which were
|
| 87 |
+
produced by editing third-party natural texts. None of those texts, and no
|
| 88 |
+
document, panel or dataset built from them, is distributed here. The real-document
|
| 89 |
+
counts and licences are summarised in README.md, "Training data (v1.1)"; the
|
| 90 |
+
synthetic-document sources are listed with their titles, URLs and recorded
|
| 91 |
+
licences in README.md, "Training-data provenance", including the three recorded
|
| 92 |
+
as CC BY-SA 4.0.
|
| 93 |
+
|
| 94 |
+
That listing is provenance disclosure and attribution as good practice. It is not
|
| 95 |
+
a statement that the trained weights are a derivative work or an adaptation of
|
| 96 |
+
those texts. Whether share-alike terms reach model weights is unsettled; this
|
| 97 |
+
package takes no position on it and the owner accepted the residual risk on
|
| 98 |
+
21 September 2026 rather than resolving it.
|
README.md
ADDED
|
@@ -0,0 +1,661 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
base_model: Qwen/Qwen3.8-27B
|
| 4 |
+
base_model_relation: adapter
|
| 5 |
+
library_name: peft
|
| 6 |
+
pipeline_tag: text-classification
|
| 7 |
+
tags:
|
| 8 |
+
- lora
|
| 9 |
+
- document-question-answering
|
| 10 |
+
- structured-decisions
|
| 11 |
+
- calibration
|
| 12 |
+
- synthetic-evaluation
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
<!-- Generated by the release packager from release/solomon-release.json and the measured artifacts.
|
| 16 |
+
Do not edit this file by hand: it is hashed in MANIFEST.json and an edit trips enforcement. -->
|
| 17 |
+
|
| 18 |
+
# Solomon
|
| 19 |
+
|
| 20 |
+
A LoRA adapter and trained answer heads for **Qwen/Qwen3.8-27B** that turn a document plus a set of
|
| 21 |
+
structured questions into one probability per decision, each with a retrieval pointer to where the
|
| 22 |
+
support for it plausibly sits in the source. It does not generate text.
|
| 23 |
+
|
| 24 |
+
> ### Read this before you trust a number on this page
|
| 25 |
+
>
|
| 26 |
+
> **v1.1 was measured on real documents, and the headline gain is not statistically established.** On a
|
| 27 |
+
> held-out panel of 802 questions over
|
| 28 |
+
> 54 real documents it answers
|
| 29 |
+
> **706** whole
|
| 30 |
+
> questions right against 679
|
| 31 |
+
> for v1.0: +3.4 points, 95% document-bootstrap interval
|
| 32 |
+
> [-1.3, +7.4].
|
| 33 |
+
> The interval includes zero.
|
| 34 |
+
>
|
| 35 |
+
> **The evaluation labels are AI-generated and have not been checked by a human.** See **Evaluation labels**.
|
| 36 |
+
>
|
| 37 |
+
> Nothing on this page is a certified error rate and nothing is guaranteed.
|
| 38 |
+
|
| 39 |
+
## What it is, and what it is for
|
| 40 |
+
|
| 41 |
+
Give it a document once and ask structured questions against it. Each answer comes back as a
|
| 42 |
+
probability. On request it also returns **ranked pointers** — the three sentences an experimental relevance
|
| 43 |
+
head scores highest — as a place to start reading, not as the reason for the answer (**Evidence**, below).
|
| 44 |
+
There is no chat, no reasoning trace and no sampling: every answer is read from letter logits at a fixed
|
| 45 |
+
position through trained linear heads, so the same document and the same question return the same
|
| 46 |
+
numbers every time.
|
| 47 |
+
|
| 48 |
+
Four answer types:
|
| 49 |
+
|
| 50 |
+
| Type | Question shape | What comes back |
|
| 51 |
+
|---|---|---|
|
| 52 |
+
| Yes / no | does the document establish X? | one probability |
|
| 53 |
+
| Single choice | which of these does it state? | one probability over the listed options |
|
| 54 |
+
| Ordered choice | which threshold does it state? | one probability over the ordered options |
|
| 55 |
+
| Multi-label | which of these apply? | **one probability per candidate** |
|
| 56 |
+
|
| 57 |
+
**v1.1 removed the entity answer type.** "Which of these parties is the X?" is a yes/no question with the
|
| 58 |
+
party written in: ask one yes/no question per candidate, or send the parties as multi-label candidates. An
|
| 59 |
+
old entity request (`candidate_kind: "entity"`, or a `{candidate}` placeholder) is answered with a 400 that
|
| 60 |
+
says exactly this.
|
| 61 |
+
|
| 62 |
+
**It is for** turning documents into structured, machine-readable answers where you need a number
|
| 63 |
+
attached to each one, and where determinism and a refusal to drift matter more than fluency.
|
| 64 |
+
|
| 65 |
+
**It is not for** general knowledge question-answering, chat, generation, or summarisation. It is not
|
| 66 |
+
for any setting where a wrong answer is costly and cannot be checked: see **Limitations**.
|
| 67 |
+
|
| 68 |
+
## How it works
|
| 69 |
+
|
| 70 |
+
| | |
|
| 71 |
+
|---|---|
|
| 72 |
+
| Base model | `Qwen/Qwen3.8-27B`, Apache-2.0, pinned revision `1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`. **Not redistributed here** |
|
| 73 |
+
| Adaptation | LoRA, rank 64, **question-side** placement, float32 |
|
| 74 |
+
| Answer projection | trained linear heads (`adapter/heads.npz`), not the language-model head |
|
| 75 |
+
| Readout | structured letter logits; yes/no-shaped units collapse to a binary log-odds before temperature |
|
| 76 |
+
| Calibration | one scalar per answer type; **all 1.0 (unscaled) in v1.1** |
|
| 77 |
+
| Runtime identity | a 21-key binding (BF16; one binding per precision) that refuses to load if the engine is not the one measured |
|
| 78 |
+
|
| 79 |
+
**The document is prefilled once; the questions branch off it.** The document goes through the model a
|
| 80 |
+
single time and becomes a reusable state (`POST /states`). Every question is then answered as an
|
| 81 |
+
isolated branch off that prefix. Two consequences are worth stating because they are tested on real
|
| 82 |
+
hardware and not merely intended: asking the same questions in a different order returns the same
|
| 83 |
+
answers, and answering from the cached document state matches a full forward pass with the same decision and
|
| 84 |
+
within 0.05 in probability (the v1.1 acceptance runs: BF16 full, int8 subset; largest difference
|
| 85 |
+
0.0108 in BF16, and 0.0097 in an earlier BF16
|
| 86 |
+
run). That limit is looser than the 1e-3 used for fp32, because BF16 differences of about 0.01 are expected; the
|
| 87 |
+
fp32 configuration was not re-run through acceptance for v1.1.
|
| 88 |
+
|
| 89 |
+
**The adapter is off while the document is read, and on from the question onward.** That is what
|
| 90 |
+
question-side placement means. Applying it across the whole sequence gives a different model to
|
| 91 |
+
the one that was measured, and the identity binding exists partly to stop that happening by accident.
|
| 92 |
+
|
| 93 |
+
**The readout is structured, not generated.** Rather than sampling an answer and parsing it, the model
|
| 94 |
+
is asked to commit at a fixed position and the letter logits at that position are read through trained
|
| 95 |
+
heads (readout mode `four_collapsed`). Yes/no-shaped units — a yes/no question, and each individual candidate
|
| 96 |
+
inside a multi-label answer — are read through **one merged yes/no head** and collapsed to a single binary
|
| 97 |
+
log-odds, `p = sigmoid(z / T)` with `z = log P(yes)/P(no)`, before the temperature is applied. The head is
|
| 98 |
+
shared, and results are reported per type. Choice questions apply the temperature to the listed slice,
|
| 99 |
+
`softmax(logits[:n] / T)`. **v1.1 serves every type at T = 1.0** (boolean 1.0 · multilabel 1.0 · single 1.0 · ordered 1.0): per-type temperatures were fitted on
|
| 100 |
+
the real dev panel and did not improve held-out calibration, so none is applied (see **Calibration**).
|
| 101 |
+
|
| 102 |
+
A branch whose `head_key` is not in the calibration artifact's map is **refused, not served at an
|
| 103 |
+
assumed 1.0**.
|
| 104 |
+
|
| 105 |
+
**The temperatures live inside the runtime binding**, covered by its checksum. A calibration fitted on
|
| 106 |
+
one model may not be served on another: the loader refuses by name rather than serving scalars that
|
| 107 |
+
mean nothing. Serving at temperature 1.0 everywhere is always permitted, on any model.
|
| 108 |
+
|
| 109 |
+
### What the returned score means
|
| 110 |
+
|
| 111 |
+
`ordering_score` means two different things depending on the question, and the difference matters.
|
| 112 |
+
|
| 113 |
+
- **Single-unit** — a yes/no question, a single or ordered choice, and **every per-candidate value**
|
| 114 |
+
inside a multi-label answer. Here the score *is* the readout probability (unscaled in v1.1); how well that
|
| 115 |
+
magnitude holds on real documents is measured under **Reliability on real documents**, below.
|
| 116 |
+
- **Multi-unit** — the rolled-up question-level score for a multi-label question with more
|
| 117 |
+
than one candidate. It is the **product** of the per-candidate probabilities, which assumes those
|
| 118 |
+
candidates are independent. **That assumption has never been validated as a joint probability.** It
|
| 119 |
+
orders such questions well; it is a heuristic ordering, not a calibrated joint. If you need a
|
| 120 |
+
magnitude for one of these, read the per-candidate numbers.
|
| 121 |
+
|
| 122 |
+
The field is not called `probability` because that would be accurate for the first case and an
|
| 123 |
+
overclaim for the second.
|
| 124 |
+
|
| 125 |
+
There is **no abstention**. Every question is answered. The service will not emit a field named
|
| 126 |
+
`abstain`, `confidence`, `threshold` or `certified_error_rate`; it raises rather than return one. If
|
| 127 |
+
you want to decline low-confidence answers, that is your policy, made on your population, and this
|
| 128 |
+
release makes no claim about where to put the line.
|
| 129 |
+
|
| 130 |
+
## How to run it
|
| 131 |
+
|
| 132 |
+
The package is a library, not a daemon: you build the engine, wrap it in the serving layer and start the
|
| 133 |
+
HTTP surface in four lines. **The reference CUDA configuration is BF16**: base weights in bfloat16 with the
|
| 134 |
+
linear-attention recurrence promoted to float32 (`precision='bf16'`, the configuration the model was trained
|
| 135 |
+
in). The v1.1 BF16 and fp32 measurements on this card were run on NVIDIA B200 GPUs. Two alternatives are selectable, each with
|
| 136 |
+
its own measured numbers below and its own identity: `precision='fp32'` (float32 weights and attention,
|
| 137 |
+
float64 recurrence; roughly twice the memory) and `precision='int8'` (weight-only 8-bit decoder linears via
|
| 138 |
+
torchao, compute in bf16; the smallest footprint, not faster: on an NVIDIA RTX A6000
|
| 139 |
+
(48 GB) it held 29.2 GiB after load and peaked at
|
| 140 |
+
32.8 GiB on the real test text documents and
|
| 141 |
+
40.4 GiB on page images). The binding pins the precision, so a
|
| 142 |
+
configuration can only be served against numbers measured on it. **The Apple-silicon MLX package in `mlx/` has
|
| 143 |
+
not been updated for v1.1**: it is pinned to the v1.0 revision of this repository and loads the v1.0 adapter,
|
| 144 |
+
heads and calibration, not the files described on this card. It is experimental, and none of the numbers on this
|
| 145 |
+
card describe it.
|
| 146 |
+
|
| 147 |
+
```sh
|
| 148 |
+
pip install -r requirements.lock
|
| 149 |
+
|
| 150 |
+
huggingface-cli download DoccyHealth/Solomon --local-dir ./solomon
|
| 151 |
+
huggingface-cli download Qwen/Qwen3.8-27B --revision 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0 --local-dir ./solomon/base
|
| 152 |
+
|
| 153 |
+
cd solomon
|
| 154 |
+
export PYTHONPATH=$PWD/src
|
| 155 |
+
```
|
| 156 |
+
|
| 157 |
+
Run from inside that directory: the engine looks for the base model in `base/`, and the serving layer
|
| 158 |
+
reads `serving/selection.json` and the binding it names, both relative to the package root.
|
| 159 |
+
|
| 160 |
+
```python
|
| 161 |
+
from solomon import api, service
|
| 162 |
+
from solomon.serving import ServiceEngine
|
| 163 |
+
|
| 164 |
+
engine = ServiceEngine('adapter/adapter.safetensors', 'adapter/heads.npz') # precision='bf16' (default) | 'fp32' | 'int8'
|
| 165 |
+
layer = service.service('./store', engine) # './store' holds cached document states
|
| 166 |
+
# fp32 / int8: build the engine with that precision AND pass its binding, e.g.
|
| 167 |
+
# engine = ServiceEngine(..., precision='int8')
|
| 168 |
+
# layer = service.service('./store', engine, binding='serving/serving-binding-int8.json')
|
| 169 |
+
server = api.serve(layer) # GET /health, POST /states, POST /v1/decide
|
| 170 |
+
print('http://127.0.0.1:%d' % server.server_port)
|
| 171 |
+
server.serve_forever() # or skip the server and call layer.decide(...) directly
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
`ServiceEngine` also takes `expected_adapter=` and `expected_heads=`, the two sha256 values printed
|
| 175 |
+
below; pass them and the engine refuses to start on a file that is not the one this card describes.
|
| 176 |
+
|
| 177 |
+
### Asking questions
|
| 178 |
+
|
| 179 |
+
One request carries a document (or a saved `state_id`) and any number of questions. The four shapes:
|
| 180 |
+
|
| 181 |
+
```jsonc
|
| 182 |
+
POST /v1/decide
|
| 183 |
+
{
|
| 184 |
+
"state": "…the document text…",
|
| 185 |
+
"evidence": "support", // none | support | sufficiency | removal
|
| 186 |
+
"questions": {
|
| 187 |
+
"certified": "Is Rookwood Ltd certified to supply produce?", // yes / no
|
| 188 |
+
"growers": {"type": "noul", "instructions": "Which growers may supply produce?",
|
| 189 |
+
"candidates": ["Rookwood Ltd", "Ostler Ltd"]}, // multi-label
|
| 190 |
+
"scheme": {"type": "choice", "instructions": "Which certification scheme applies?",
|
| 191 |
+
"options": ["Freshcare", "SQF", "GlobalG.A.P."]}, // single choice
|
| 192 |
+
"risk": {"type": "choice", "instructions": "What supply risk rating is recorded?",
|
| 193 |
+
"options": ["low", "medium", "high"], "ordered": true} // ordered choice
|
| 194 |
+
}
|
| 195 |
+
}
|
| 196 |
+
```
|
| 197 |
+
|
| 198 |
+
```jsonc
|
| 199 |
+
{
|
| 200 |
+
"answers": {
|
| 201 |
+
"certified": {"type": "noul", "noul": 0.97, "ordering_score": 0.97, "temperature": 1.0,
|
| 202 |
+
"evidence_method": "trained_relevance_head_ranked", "evidence": [{"start": 212, "end": 256, "text": "…", "score": 0.83, "rank": 1}, …], "evidence_suppressed": false},
|
| 203 |
+
"growers": {"type": "noul", "candidate_kind": "label",
|
| 204 |
+
"candidates": {"Rookwood Ltd": 0.96, "Ostler Ltd": 0.04},
|
| 205 |
+
"candidate_ordering_scores": {"Rookwood Ltd": 0.96, "Ostler Ltd": 0.96},
|
| 206 |
+
"candidate_evidence": {"Rookwood Ltd": [{"start": 212, "end": 256, "text": "…", "score": 0.91, "rank": 1}, …],
|
| 207 |
+
"Ostler Ltd": [{"start": 257, "end": 309, "text": "…", "score": 0.77, "rank": 1}, …]},
|
| 208 |
+
"candidate_evidence_suppressed": {"Rookwood Ltd": false, "Ostler Ltd": false}},
|
| 209 |
+
"scheme": {"type": "choice", "answer": "Freshcare", "probabilities": {"Freshcare": 0.91, "SQF": 0.06, "GlobalG.A.P.": 0.03}},
|
| 210 |
+
"risk": {"type": "choice", "ordered": true, "answer": "medium", "probabilities": {"low": 0.12, "medium": 0.81, "high": 0.07}}
|
| 211 |
+
}
|
| 212 |
+
}
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
+
(Illustrative numbers, not measurements.) The entity form `{"instructions": "Is {candidate} a grower?",
|
| 216 |
+
"candidates": [...]}` was removed in v1.1: write `"growers"` above, or one yes/no question per party.
|
| 217 |
+
|
| 218 |
+
**Evidence.** At `evidence: "support"` the response carries up to three ranked sentence pointers with scores
|
| 219 |
+
from an experimental relevance head, per answer branch. `evidence_method` names the selector:
|
| 220 |
+
`trained_relevance_head_ranked`, or `lexical_overlap_fallback` (word overlap, used for page images and whenever
|
| 221 |
+
the head is not configured, with `evidence_fallback_reason` saying why). Neither establishes that the
|
| 222 |
+
answer was caused by the span (`evidence_faithfulness_established: false`). See **Evidence (experimental)**.
|
| 223 |
+
|
| 224 |
+
`GET /health` reports the contract, the readout mode and the runtime identity. If the engine you built
|
| 225 |
+
differs from the one the numbers were measured on — a different torch build, a different adapter, a
|
| 226 |
+
different arithmetic mode — **the binding refuses to load rather than quietly serving different
|
| 227 |
+
numbers**. That is intended behaviour; do not work around it.
|
| 228 |
+
|
| 229 |
+
### What is in this repository
|
| 230 |
+
|
| 231 |
+
```
|
| 232 |
+
README.md this file
|
| 233 |
+
LICENSE Apache-2.0
|
| 234 |
+
NOTICE attribution and the Apache-2.0 4(b)/4(c) notices
|
| 235 |
+
MODIFICATIONS.md statement of changes, third-party text scan, maintainer notes
|
| 236 |
+
MANIFEST.json every file, its size and its sha256
|
| 237 |
+
requirements.lock the pins of the image this was qualified on, and dependency licences
|
| 238 |
+
licenses/Qwen-Apache-2.0.txt the upstream licence, verbatim
|
| 239 |
+
adapter/adapter.safetensors the LoRA adapter
|
| 240 |
+
adapter/heads.npz the trained answer heads
|
| 241 |
+
adapter/config.json base repo, pinned revision, checksums, placement
|
| 242 |
+
serving/serving-binding.json runtime identity binding (bf16, default) and the frozen temperatures
|
| 243 |
+
serving/serving-binding-fp32.json runtime identity binding for precision=fp32
|
| 244 |
+
serving/serving-binding-int8.json runtime identity binding for precision=int8
|
| 245 |
+
serving/evidence-head.safetensors relevance head weights (float32)
|
| 246 |
+
serving/evidence-head.json relevance head config incl. lexical_residual alpha
|
| 247 |
+
serving/evidence-policy.json ranked-pointer serving policy (top 3, suppressed when not stated)
|
| 248 |
+
serving/readout-temperature-v3.json the calibration artifact, standalone
|
| 249 |
+
serving/selection.json readout mode and model identity
|
| 250 |
+
serving/service-export.json qualification envelope hashes
|
| 251 |
+
src/solomon/__init__.py solomon: a document plus structured questions in, one probability per decision out
|
| 252 |
+
src/solomon/api.py HTTP surface for the Solomon layer (solomon/service.py)
|
| 253 |
+
src/solomon/binding.py serving identity: which readout is served, and proof that it is the one that was measured
|
| 254 |
+
src/solomon/calibration.py the readout calibration: one positive scalar per answer type, and nothing else
|
| 255 |
+
src/solomon/engine.py question-only CUDA runtime for immutable semantic-head checkpoints
|
| 256 |
+
src/solomon/engine_contract.py the answer contract engine: contract v3 on the reference engine's float32 cached path
|
| 257 |
+
src/solomon/engine_cuda.py CUDA contract-v3 engine
|
| 258 |
+
src/solomon/engine_numerics.py versioned CUDA repair: bounded FP32 attention, FP64 recurrent accumulation
|
| 259 |
+
src/solomon/engine_reasoning.py the confidence layer text reasoning on immutable answer-contract base-prefix states
|
| 260 |
+
src/solomon/engine_reference.py the reference engine: task-agnostic document prefix, float32 arithmetic, chunked prefill
|
| 261 |
+
src/solomon/evidence.py deterministic source references and explicit evidence interventions
|
| 262 |
+
src/solomon/evidence_head.py v1.1 evidence head: the ONE forward shared by the trainer (the training tooling via
|
| 263 |
+
src/solomon/evidence_packages.py evidence packages (v3): selected spans plus source-derived governing context, per question unit
|
| 264 |
+
src/solomon/evidence_selector.py evidence selection for the Solomon layer (v1.1): the trained relevance head, with word overlap as a labelled fallback
|
| 265 |
+
src/solomon/heads.py final normalized feature extraction, preserving the qualified CUDA engine
|
| 266 |
+
src/solomon/prompts_two_letter.py two-letter (Noul) prompts and block conversions
|
| 267 |
+
src/solomon/readout.py contract v3 readouts: branch jobs for every answer type, predictions from letter logits, and metrics
|
| 268 |
+
src/solomon/reliability.py what the readout says about its own answer, with nothing fitted behind it
|
| 269 |
+
src/solomon/retrieval.py inference-only source candidates and explicitly labelled retrieval baselines
|
| 270 |
+
src/solomon/routing.py real callback-driven escalation
|
| 271 |
+
src/solomon/semantics.py answer semantics (design note, not distributed)
|
| 272 |
+
src/solomon/service.py decision layer: the Solomon serving contract over the pinned readout chain
|
| 273 |
+
src/solomon/service_answers.py confidence-aware five-task service, reusing immutable answer-contract input persistence
|
| 274 |
+
src/solomon/service_checked.py backend-neutral contract-v3 service; restart replays immutable inputs, not tensors
|
| 275 |
+
src/solomon/service_evidence.py optional source-grounded evidence around the existing confidence service
|
| 276 |
+
src/solomon/service_heads.py trained-head fast/views service; unchanged decoder and separate stage confidence
|
| 277 |
+
src/solomon/service_packages.py evidence packages (v3) in the answer service: per-unit, source-grounded, page-referenced
|
| 278 |
+
src/solomon/service_states.py local contract-v3 prototype: task-neutral text/image states and five answer types
|
| 279 |
+
src/solomon/serving.py preserve five-task trained-head confidence/routing with optional evidence
|
| 280 |
+
src/solomon/units.py v1.1 shared sentence/list-item splitter
|
| 281 |
+
mlx/ the optional Apple-silicon package: its own library, tests and notices
|
| 282 |
+
```
|
| 283 |
+
|
| 284 |
+
**What is deliberately not here:** no training data, no evaluation panels, no document corpora, no
|
| 285 |
+
datasets, no cached states, no rendered images, no score archives, no test fixtures, no logs and no
|
| 286 |
+
base model weights. The package is default-deny: a manifest names every permitted file and the build
|
| 287 |
+
fails if anything else is present.
|
| 288 |
+
|
| 289 |
+
The files under `serving/` carry identity only: hashes, the readout mode, the served design and the
|
| 290 |
+
per-type temperatures. The loader verifies the binding's checksum and every runtime key it carries. The
|
| 291 |
+
measured provenance behind those hashes (which panels, which fit, which qualification run) is held in
|
| 292 |
+
the maintainer's records and is not distributed.
|
| 293 |
+
|
| 294 |
+
## Evidence (experimental)
|
| 295 |
+
|
| 296 |
+
**Evidence here is a set of ranked pointers, not an explanation.** At `evidence: "support"` the service returns
|
| 297 |
+
the **top 3 sentences** of the document with a relevance score each (`evidence_method:
|
| 298 |
+
"trained_relevance_head_ranked"`). The scores come from a small relevance head fitted after training, on the
|
| 299 |
+
model's layer-42 states plus a word-overlap term. It reads states the answer already computed; it
|
| 300 |
+
makes no extra model call and **cannot change an answer**: with the head on and off, all 3,230 real
|
| 301 |
+
test answer branches were identical (maximum logit difference 0.0).
|
| 302 |
+
|
| 303 |
+
- `evidence_faithfulness_established` is `false`. Nothing shows the pointed-to sentence caused the answer.
|
| 304 |
+
- **No pointers are returned when the answer is "not stated"** (the answer's collapsed state is not-stated, or a
|
| 305 |
+
choice answer resolved to the reserved not-stated option). That state is the absence signal; the head itself
|
| 306 |
+
has no reliable "no evidence" signal.
|
| 307 |
+
- On the development panel the head put a labelled supporting sentence in its top 3 more often than plain word
|
| 308 |
+
overlap: hit@3 0.817 against 0.669
|
| 309 |
+
over 753 labelled rows. That comparison was used to choose the head, so it is
|
| 310 |
+
optimistic, and **no test-panel measurement exists**. The precision and recall targets for evidence were not established.
|
| 311 |
+
- **Word overlap is the labelled fallback** (`lexical_overlap_fallback`, with `evidence_fallback_reason`), used for
|
| 312 |
+
page-image documents and whenever the head is not configured.
|
| 313 |
+
|
| 314 |
+
Treat pointers as a place to start reading and verify them yourself.
|
| 315 |
+
|
| 316 |
+
## What it scores
|
| 317 |
+
|
| 318 |
+
Every figure in this section was measured on the adapter this repository ships
|
| 319 |
+
(`d122466d430a…`) in the BF16 reference configuration unless stated. The scoring runs
|
| 320 |
+
loaded a heads file (`96ea51416bbe…`) that is the shipped `adapter/heads.npz`
|
| 321 |
+
(`f766d752d776…`) plus two legacy slots that were never read; every array the two files share is
|
| 322 |
+
byte-identical, so the served logits are the measured logits. The packager checks those hashes against the measurement records and refuses to
|
| 323 |
+
build if they differ. Figures for v1.0 are that model re-scored on the same panels, for comparison only.
|
| 324 |
+
|
| 325 |
+
### Real documents
|
| 326 |
+
|
| 327 |
+
Real public documents (government notices, policies, agreements, correspondence, minutes and similar), split by
|
| 328 |
+
document into training, dev and test. Test documents were never trained on and never used for any fit.
|
| 329 |
+
|
| 330 |
+
| Panel | Questions / documents | This model | v1.0 | External reference¹ | v1.1 − v1.0, points [95% CI] |
|
| 331 |
+
|---|---|---|---|---|---|
|
| 332 |
+
| Test | 802 / 54 | **706 (88.0%)** | 679 (84.7%) | 690 (86.0%) | +3.4 [-1.3, +7.4] |
|
| 333 |
+
| Dev | 624 / 15 | **555 (88.9%)** | 529 (84.8%) | 553 (88.6%) | +4.2 [+1.0, +7.5] |
|
| 334 |
+
|
| 335 |
+
¹ a commercial structured-decision API (external reference), scored on the same questions and labels.
|
| 336 |
+
|
| 337 |
+
Intervals are document-cluster bootstrap (2,000 resamples). **On test the interval includes zero**: the release
|
| 338 |
+
rule asked for a lower bound of −1.0 points and the measured bound is
|
| 339 |
+
-1.3. The owner accepted this miss for v1.1; see **Release decisions**.
|
| 340 |
+
|
| 341 |
+
Per answer type, real test:
|
| 342 |
+
|
| 343 |
+
| Answer type | Questions | This model | v1.0 | External reference | v1.1 − v1.0, points [95% CI] |
|
| 344 |
+
|---|---|---|---|---|---|
|
| 345 |
+
| Yes / no | 149 | 132 / 149 | 132 / 149 | 135 / 149 | +0.0 [-10.1, +7.2] |
|
| 346 |
+
| Party-role questions (formerly entity; now asked as yes/no per party) | 213 | 185 / 213 | 165 / 213 | 180 / 213 | +9.4 [+0.0, +19.2] |
|
| 347 |
+
| Multi-label | 226 | 191 / 226 | 190 / 226 | 184 / 226 | +0.4 [-4.8, +5.9] |
|
| 348 |
+
| Ordered choice | 109 | 95 / 109 | 90 / 109 | 91 / 109 | +4.6 [-1.9, +10.7] |
|
| 349 |
+
| Single choice | 105 | 103 / 105 | 102 / 105 | 100 / 105 | +1.0 [+0.0, +3.0] |
|
| 350 |
+
| Multi-label, per candidate (slots) | 1,204 | 96.5% | 95.8% | not tallied | +0.7 [-1.0, +2.3] |
|
| 351 |
+
| Party-role, per party (slots) | 1,329 | 97.2% | 94.9% | not tallied | +2.3 [+0.4, +4.1] |
|
| 352 |
+
|
| 353 |
+
Counts are whole questions right, with the same question definition applied to all three models.
|
| 354 |
+
|
| 355 |
+
### Page images against text
|
| 356 |
+
|
| 357 |
+
The same 802 real test questions, asked from rendered page images instead
|
| 358 |
+
of extracted text: 713
|
| 359 |
+
whole questions right from images against 706
|
| 360 |
+
from text, with 98.5% of 2,936
|
| 361 |
+
answer branches agreeing between the two.
|
| 362 |
+
|
| 363 |
+
### Natural images
|
| 364 |
+
|
| 365 |
+
A panel of photographs and pictures with structured questions (no document text). Two populations are reported
|
| 366 |
+
and they are different numbers:
|
| 367 |
+
|
| 368 |
+
- **Per answer unit** (731 units): this model 97.3%,
|
| 369 |
+
v1.0 96.2%, base Qwen 95.5%.
|
| 370 |
+
Answers stated at 0.99 or above that were wrong: this model 0.0%
|
| 371 |
+
of 293, base Qwen 1.5% of
|
| 372 |
+
401.
|
| 373 |
+
- **Whole questions** (415): this model 95.2%, v1.0
|
| 374 |
+
93.3%, base Qwen 92.0%.
|
| 375 |
+
|
| 376 |
+
### General knowledge, with no document (out of domain)
|
| 377 |
+
|
| 378 |
+
800 multiple-choice items, 400 from MMLU and 400 from MMLU-Pro, every model on the same items and prompt.
|
| 379 |
+
|
| 380 |
+
| Model | Accuracy (800) | Answers stated ≥ 0.99 | Of those, wrong | ECE (top label, 15 bins) |
|
| 381 |
+
|---|---|---|---|---|
|
| 382 |
+
| **This model (v1.1)** | 72.9% | 24 | 0 (0.0%) | 0.052 |
|
| 383 |
+
| v1.0 | 72.8% | 401 | 20 (5.0%) | 0.146 |
|
| 384 |
+
| External reference¹ | 87.1% | 314 | 5 (1.6%) | 0.040 |
|
| 385 |
+
| Base Qwen, same prompt | 71.8% | 187 | 4 (2.1%) | 0.049 |
|
| 386 |
+
|
| 387 |
+
All four rows come from one computation on the same 800 items. Probabilities are unscaled (T = 1) for every row,
|
| 388 |
+
which is how v1.1 serves them.
|
| 389 |
+
|
| 390 |
+
v1.0 stated half of its answers at 0.99 or above and was wrong on 1 in 20 of them. This model almost never
|
| 391 |
+
claims 0.99 on general knowledge. MMLU moved +1.5 points and
|
| 392 |
+
MMLU-Pro -1.25 points against v1.0; the release rule allowed at
|
| 393 |
+
most 1 point either way, so **MMLU-Pro missed it**. The owner accepted this miss for v1.1.
|
| 394 |
+
|
| 395 |
+
### Reliability on real documents
|
| 396 |
+
|
| 397 |
+
Real test, text, every answer unit (each option or candidate scored against its label): of the probabilities
|
| 398 |
+
stated in each band, the share that were actually right. A calibrated model's column would track the band.
|
| 399 |
+
|
| 400 |
+
| Stated P(yes) | this model | external reference |
|
| 401 |
+
|---|---|---|
|
| 402 |
+
| 0.00–0.01 | 0.0% (n=2,095) | 0.1% (n=2,619) |
|
| 403 |
+
| 0.01–0.02 | 0.8% (n=1,038) | 0.7% (n=305) |
|
| 404 |
+
| 0.02–0.05 | 3.2% (n=569) | 1.8% (n=325) |
|
| 405 |
+
| 0.05–0.10 | 14.4% (n=132) | 3.0% (n=202) |
|
| 406 |
+
| 0.10–0.20 | 46.0% (n=87) | 7.5% (n=213) |
|
| 407 |
+
| 0.20–0.30 | 51.6% (n=31) | 18.1% (n=116) |
|
| 408 |
+
| 0.30–0.40 | 18.2% (n=22) | 28.6% (n=63) |
|
| 409 |
+
| 0.40–0.50 | 66.7% (n=18) | 30.4% (n=56) |
|
| 410 |
+
| 0.50–0.60 | 47.1% (n=17) | 39.5% (n=43) |
|
| 411 |
+
| 0.60–0.70 | 61.5% (n=13) | 55.6% (n=63) |
|
| 412 |
+
| 0.70–0.80 | 53.1% (n=32) | 68.6% (n=70) |
|
| 413 |
+
| 0.80–0.90 | 83.7% (n=43) | 82.9% (n=111) |
|
| 414 |
+
| 0.90–0.95 | 89.3% (n=84) | 91.0% (n=89) |
|
| 415 |
+
| 0.95–0.98 | 97.3% (n=295) | 92.5% (n=106) |
|
| 416 |
+
| 0.98–0.99 | 99.6% (n=485) | 95.6% (n=90) |
|
| 417 |
+
| 0.99–1.00 | 100.0% (n=126) | 99.5% (n=616) |
|
| 418 |
+
|
| 419 |
+
The top end is at or above the external reference. **The low end under-calls**: answers stated at 5–20% are yes
|
| 420 |
+
more often than stated. (This table is the unscaled readout, which is what v1.1 serves.)
|
| 421 |
+
|
| 422 |
+
### Calibration
|
| 423 |
+
|
| 424 |
+
Per-type temperatures were fitted on the real dev panel (boolean 0.8175 · multilabel 0.8423 · single 1.1077 · ordered 1.2562) and checked on held-out real test.
|
| 425 |
+
**They did not improve held-out calibration**: test ECE got worse in 8 of 10 answer-type × modality
|
| 426 |
+
cells, and the question-weighted ECE across all cells was 0.0212 with the fitted temperatures against
|
| 427 |
+
0.0199 unscaled. Only multi-label improved. **v1.1 therefore ships unscaled probabilities (T = 1.0 for
|
| 428 |
+
every type).** Real test ECE per cell (10 bins):
|
| 429 |
+
|
| 430 |
+
| Answer type | Input | Units | ECE, unscaled (served) | ECE, dev-fitted temperature | Meets 0.03 target |
|
| 431 |
+
|---|---|---|---|---|---|
|
| 432 |
+
| yes/no | image | 149 | **0.055** | 0.068 | **no** |
|
| 433 |
+
| yes/no | text | 149 | **0.067** | 0.081 | **no** |
|
| 434 |
+
| party-role (per party) | image | 1,329 | **0.009** | 0.020 | yes |
|
| 435 |
+
| party-role (per party) | text | 1,329 | **0.011** | 0.013 | yes |
|
| 436 |
+
| multi-label (per candidate) | image | 1,204 | **0.020** | 0.012 | yes |
|
| 437 |
+
| multi-label (per candidate) | text | 1,204 | **0.024** | 0.013 | yes |
|
| 438 |
+
| ordered | image | 109 | **0.073** | 0.086 | **no** |
|
| 439 |
+
| ordered | text | 109 | **0.054** | 0.077 | **no** |
|
| 440 |
+
| single | image | 105 | **0.022** | 0.053 | yes |
|
| 441 |
+
| single | text | 105 | **0.014** | 0.040 | yes |
|
| 442 |
+
|
| 443 |
+
The 0.03 target is **missed for yes/no** (0.067 text,
|
| 444 |
+
0.055 image) **and ordered choice** (0.054 text,
|
| 445 |
+
0.073 image). Those cells have only
|
| 446 |
+
105–149 questions each (yes/no, single and ordered). Party-role rows are
|
| 447 |
+
the former entity questions, now asked as one yes/no question per party.
|
| 448 |
+
|
| 449 |
+
### Precision configurations
|
| 450 |
+
|
| 451 |
+
Real test, text, 3,230 answer branches. Accuracy is whole
|
| 452 |
+
questions; flips are served decisions that differ from BF16.
|
| 453 |
+
|
| 454 |
+
| Configuration | Status | Whole-question accuracy | vs BF16, points [95% CI] | Decisions flipped vs BF16 | ECE (unscaled) |
|
| 455 |
+
|---|---|---|---|---|---|
|
| 456 |
+
| `bf16` | **default, reference** | 88.03% | — | — | 0.018 |
|
| 457 |
+
| `fp32` | comparison | 87.66% | -0.37 [-0.77, +0.00] | 0.10% | 0.016 |
|
| 458 |
+
| `int8` | option | 87.53% | -0.50 [-1.02, +0.00] | 0.27% | 0.016 |
|
| 459 |
+
|
| 460 |
+
`int8` is weight-only 8-bit (torchao) with bf16 compute. **`int8` page-image accuracy has not been scored against
|
| 461 |
+
the labels**; a decision-agreement run against fp32 on page images agreed on
|
| 462 |
+
99.71% of served decisions. On page
|
| 463 |
+
images `fp32` scored 88.78% against BF16
|
| 464 |
+
88.90%. No speed claim is made for any configuration.
|
| 465 |
+
|
| 466 |
+
### Failure modes (synthetic probes)
|
| 467 |
+
|
| 468 |
+
6,000 generated questions across 38 targeted failure modes, paired
|
| 469 |
+
against v1.0. Most modes are flat. Modes whose interval excludes zero:
|
| 470 |
+
|
| 471 |
+
| Mode | Questions | v1.0 | This model | Difference, points [95% CI] |
|
| 472 |
+
|---|---|---|---|---|
|
| 473 |
+
| indirect reference | 160 | 80.6% | 72.5% | -8.1 [-13.1, -3.8] |
|
| 474 |
+
| opposite polarity question | 135 | 94.1% | 97.0% | +3.0 [+0.7, +5.9] |
|
| 475 |
+
|
| 476 |
+
- **Paraphrase agreement** on yes/no questions: 0.951 (v1.0
|
| 477 |
+
0.946); the target was 0.98 and is not met.
|
| 478 |
+
- **Adversarial confident flips** (answer changed at ≥ 0.9 by an injected instruction, false summary or
|
| 479 |
+
self-classifying text): 2.0% (v1.0 2.1%);
|
| 480 |
+
the target was 1% and is not met.
|
| 481 |
+
- **Per-type calibration on real test** misses the 0.03 ECE target for yes/no and ordered questions (see
|
| 482 |
+
**Calibration**, below; reported, not blocking).
|
| 483 |
+
|
| 484 |
+
## Limitations
|
| 485 |
+
|
| 486 |
+
- **Evaluation labels are not human-verified.** Every real-document reference label was produced by AI
|
| 487 |
+
labellers: two blind passes plus adjudication, with 99% agreement on binary slots between the passes. The owner
|
| 488 |
+
decided to release v1.1 without a human label review. Some measured errors may be label errors, and some
|
| 489 |
+
measured successes may share a labeller's mistake.
|
| 490 |
+
- **The headline improvement is not significant** (interval includes zero) and the real panels are small:
|
| 491 |
+
54 test documents.
|
| 492 |
+
- **The low end of the probability scale under-calls** on real documents (see the reliability table).
|
| 493 |
+
- **Indirect references regressed** on the synthetic probes (table above).
|
| 494 |
+
- **The multi-candidate roll-up is an ordering, not a joint probability.** Read per-candidate values if you
|
| 495 |
+
need a magnitude.
|
| 496 |
+
- **Nothing here is a certified error rate.** No threshold is enforced anywhere on the serving path.
|
| 497 |
+
- **Page images:** measured on the real test panel in BF16 and fp32 only.
|
| 498 |
+
|
| 499 |
+
## Release decisions
|
| 500 |
+
|
| 501 |
+
Two release rules were missed and **both were accepted by the owner for v1.1**:
|
| 502 |
+
|
| 503 |
+
1. Real test, whole questions: lower bound of the 95% interval -1.3
|
| 504 |
+
points against a rule of −1.0.
|
| 505 |
+
2. General knowledge: MMLU-Pro -1.25 points against a limit
|
| 506 |
+
of 1 point (MMLU +1.5).
|
| 507 |
+
|
| 508 |
+
## Evaluation labels
|
| 509 |
+
|
| 510 |
+
Reference labels on the real panels are AI-generated (two blind passes plus adjudication) and **have not been
|
| 511 |
+
reviewed by a human**. No Claude or GPT output is used anywhere as training input.
|
| 512 |
+
|
| 513 |
+
## Training data (v1.1)
|
| 514 |
+
|
| 515 |
+
**Real documents.** 200 real public documents: 160 collected for this release plus
|
| 516 |
+
40 from an earlier evaluation panel (those 40 are test-only). Split by document: 113 train,
|
| 517 |
+
24 dev, 63 test (the evaluation panels above use the labelled subset). Licences of the
|
| 518 |
+
160 collected documents, as recorded at collection: 59 Australian government pages under CC BY 4.0,
|
| 519 |
+
76 UK Crown copyright under the Open Government Licence v3.0, 25 US federal government works (public domain).
|
| 520 |
+
No document is distributed here.
|
| 521 |
+
|
| 522 |
+
**Where the training labels came from.**
|
| 523 |
+
|
| 524 |
+
- Real-document training labels: Qwen3.8 2.4T (open weights), called through OpenRouter and routed to
|
| 525 |
+
third-party hosts serving full-precision weights, not the Alibaba API.
|
| 526 |
+
- Anchor targets from the unmodified base Qwen model, so general behaviour does not drift.
|
| 527 |
+
- Code generators for the synthetic documents and targeted failure-mode questions.
|
| 528 |
+
- Replay of the v1.0 training data (whose third-party sources are listed below).
|
| 529 |
+
|
| 530 |
+
**No Claude or GPT output is ever training input or a training label.** The build enforces this with an
|
| 531 |
+
allow-list of row producers.
|
| 532 |
+
|
| 533 |
+
## Training-data provenance (third-party texts in the synthetic documents)
|
| 534 |
+
|
| 535 |
+
**No training document, panel, corpus or source text is distributed in this repository.**
|
| 536 |
+
The adapter was trained on synthetic documents, and some of those documents were produced by **editing
|
| 537 |
+
third-party natural texts**. Those texts are listed here so that their provenance is on the record, and
|
| 538 |
+
so that a reviewer doing lawful-sourcing diligence can see what was used without having to ask.
|
| 539 |
+
|
| 540 |
+
The model card discloses the provenance of the third-party texts the training panel was edited from, and attributes them. This is provenance disclosure and attribution as good practice, and it supports documented-lawful-sourcing procurement review. It is NOT a concession that the trained weights are a derivative work or an adaptation of those texts; that question is open and nothing in this package answers it.
|
| 541 |
+
|
| 542 |
+
13 of the 42 reviewed sources were used in the training panel:
|
| 543 |
+
|
| 544 |
+
| | Source | URL | Licence, as recorded |
|
| 545 |
+
|---|---|---|---|
|
| 546 |
+
| | Django's security policies | [https://docs.djangoproject.com/en/dev/internals/security/](https://docs.djangoproject.com/en/dev/internals/security/) | BSD 3-Clause (Django project LICENSE, which covers the documentation in the django/django repository) |
|
| 547 |
+
| **CC BY-SA** | Wikipedia:Arbitration/Policy (English Wikipedia arbitration policy) | [https://en.wikipedia.org/wiki/Wikipedia:Arbitration/Policy](https://en.wikipedia.org/wiki/Wikipedia:Arbitration/Policy) | CC BY-SA 4.0 (Wikipedia text; attribution: English Wikipedia contributors, 'Wikipedia:Arbitration/Policy') |
|
| 548 |
+
| | Common Paper Mutual Non-Disclosure Agreement, Version 1.0 – Standard Terms | [https://commonpaper.com/standards/mutual-nda/1.0/](https://commonpaper.com/standards/mutual-nda/1.0/) | CC BY 4.0 (stated in the agreement footer and in the CommonPaper/Mutual-NDA repository README: 'free to use and modify under CC BY 4.0') |
|
| 549 |
+
| | 36 CFR Part 2 (National Park Service) - Resource Protection, Public Use and Recreation: sections 2.10, 2.13, 2.14, 2.15, 2.16, 2.21 and 2.22 | [https://www.ecfr.gov/current/title-36/chapter-I/part-2](https://www.ecfr.gov/current/title-36/chapter-I/part-2) | US Government work (public domain): Code of Federal Regulations text, not subject to copyright (17 U.S.C. 105) |
|
| 550 |
+
| | NSF Proposal & Award Policies & Procedures Guide (PAPPG, NSF 24-1), Chapter IV: Non-Award Decisions and Transactions | [https://www.nsf.gov/policies/pappg/24-1/ch-4-non-award-decisions-transactions](https://www.nsf.gov/policies/pappg/24-1/ch-4-non-award-decisions-transactions) | US Government work (public domain): U.S. National Science Foundation policy guide, not subject to copyright (17 U.S.C. 105) |
|
| 551 |
+
| | GOV.UK: Make a court claim for money | [https://www.gov.uk/api/content/make-court-claim-for-money](https://www.gov.uk/api/content/make-court-claim-for-money) | Open Government Licence v3.0 |
|
| 552 |
+
| | 42 CFR 68: NIH Loan Repayment Programs (2025 edition) | [https://www.govinfo.gov/content/pkg/CFR-2025-title42-vol1/xml/CFR-2025-title42-vol1-part68.xml](https://www.govinfo.gov/content/pkg/CFR-2025-title42-vol1/xml/CFR-2025-title42-vol1-part68.xml) | US Government work (public domain) |
|
| 553 |
+
| **CC BY-SA** | WordPress.com (Automattic) Terms of Service, last updated April 10, 2026 | [https://github.com/Automattic/legalmattic/blob/master/Terms%20of%20Service/WordPress.com/EN-Terms-of-Service.md](https://github.com/Automattic/legalmattic/blob/master/Terms%20of%20Service/WordPress.com/EN-Terms-of-Service.md) | CC BY-SA 4.0 (Automattic/legalmattic LICENSE.txt and README; the Terms themselves state they are available under a Creative Commons Sharealike license) |
|
| 554 |
+
| **CC BY-SA** | GitLab Handbook: Global Travel and Expense Policy (sections 1 to 3) | [https://handbook.gitlab.com/handbook/finance/expenses/](https://handbook.gitlab.com/handbook/finance/expenses/) | CC BY-SA 4.0 (GitLab handbook content; licence badge in the footer of handbook.gitlab.com pages) |
|
| 555 |
+
| | Sourcegraph Handbook: Spending company money | [https://github.com/sourcegraph/handbook/blob/main/content/benefits-pay-perks/benefits-perks/spending-company-money.md](https://github.com/sourcegraph/handbook/blob/main/content/benefits-pay-perks/benefits-perks/spending-company-money.md) | Apache License 2.0 (LICENSE of the public sourcegraph/handbook repository) |
|
| 556 |
+
| | Project Jupyter Governance: Executive Council | [https://raw.githubusercontent.com/jupyter/governance/main/docs/executive_council.md](https://raw.githubusercontent.com/jupyter/governance/main/docs/executive_council.md) | CC0 1.0 Universal (jupyter/governance repository LICENSE.md) |
|
| 557 |
+
| | 29 CFR 1904.30–1904.34: establishment records and annual summaries (2025 edition) | [https://www.govinfo.gov/content/pkg/CFR-2025-title29-vol5/xml/CFR-2025-title29-vol5-part1904.xml](https://www.govinfo.gov/content/pkg/CFR-2025-title29-vol5/xml/CFR-2025-title29-vol5-part1904.xml) | US Government work (public domain) |
|
| 558 |
+
| | 31 CFR 1.2, 1.4 and 1.6: Treasury FOIA requests and appeals (2025 edition) | [https://www.govinfo.gov/content/pkg/CFR-2025-title31-vol1/xml/CFR-2025-title31-vol1-part1.xml](https://www.govinfo.gov/content/pkg/CFR-2025-title31-vol1/xml/CFR-2025-title31-vol1-part1.xml) | US Government work (public domain) |
|
| 559 |
+
|
| 560 |
+
**3 of these are recorded as CC BY-SA 4.0** — *Wikipedia:Arbitration/Policy (English Wikipedia arbitration policy)*, *WordPress.com (Automattic) Terms of Service, last updated April 10, 2026*, *GitLab Handbook: Global Travel and Expense Policy (sections 1 to 3)*. Share-alike is the one term
|
| 561 |
+
attribution cannot cure. Whether a share-alike obligation can propagate through training into model
|
| 562 |
+
weights **is legally unsettled**; there is no authority settling it in either direction, and the
|
| 563 |
+
project's own licence review explicitly declines to infer one. The owner of this release
|
| 564 |
+
**accepted that residual risk on 2026-09-21 rather than resolving
|
| 565 |
+
it**, and kept this package under Apache-2.0. A reader should treat the question as open, not answered.
|
| 566 |
+
|
| 567 |
+
**On the strength of this evidence.** The licences above are **as recorded by the person who collected
|
| 568 |
+
each source**, from the source's own stated terms at the time of collection. The review records
|
| 569 |
+
`evidence_level: "authoring metadata assertion, not archived governing licence text"` and
|
| 570 |
+
`upstream_terms_independently_verified: false` for every row. No governing licence text was archived
|
| 571 |
+
alongside most of these sources, and this listing should not be read as a licence audit.
|
| 572 |
+
|
| 573 |
+
Listing these sources is **provenance disclosure and attribution as good practice**. It is not a
|
| 574 |
+
statement that the trained weights are a derivative work, an adaptation, or a copy of any of these
|
| 575 |
+
texts.
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
## Third-party dependency licences
|
| 579 |
+
|
| 580 |
+
`requirements.lock` names the packages the serving layer needs. **None of them is redistributed in
|
| 581 |
+
this repository** — you install them yourself from their own publishers — so Apache-2.0 section 4(a)
|
| 582 |
+
imposes no bundled-notice obligation here and no dependency licence text is packaged. This summary
|
| 583 |
+
exists because a reviewer will ask for one.
|
| 584 |
+
|
| 585 |
+
Each licence in the table is the one declared in that distribution's OWN package metadata -- the `METADATA` file of an installed wheel -- read from a copy on the maintainer's machine. Where no copy existed, the row says NOT VERIFIED instead of guessing.
|
| 586 |
+
|
| 587 |
+
| Package | Pinned as | Licence, as declared by the distribution itself |
|
| 588 |
+
|---|---|---|
|
| 589 |
+
| `torch` | 2.13.0 | BSD-3-Clause — read from version 2.8.0 |
|
| 590 |
+
| `torchvision` | 0.28.0 | NOT VERIFIED |
|
| 591 |
+
| `transformers` | 5.17.0 | Apache 2.0 License |
|
| 592 |
+
| `flash-linear-attention` | 0.5.2 | NOT VERIFIED |
|
| 593 |
+
| `safetensors` | unpinned in the qualified image | Apache Software License — read from version 0.8.0 |
|
| 594 |
+
| `accelerate` | unpinned in the qualified image | Apache (Apache Software License) — read from version 1.15.0 |
|
| 595 |
+
| `numpy` | unpinned in the qualified image | BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0 — read from version 2.5.3 |
|
| 596 |
+
| `scipy` | unpinned in the qualified image | BSD License (classifier); the METADATA `License` field carries the Enthought / SciPy Developers copyright line rather than an SPDX identifier — read from version 1.18.1 |
|
| 597 |
+
| `pillow` | unpinned in the qualified image | MIT-CMU — read from version 12.3.0 |
|
| 598 |
+
|
| 599 |
+
**Two rows say NOT VERIFIED and mean it.** A licence read from one installed version is evidence about that version only. Where the table names a version different from the pin, that is the version whose metadata was actually read, and the pinned version's own metadata could differ. Treat this table as a starting point for
|
| 600 |
+
your own review, not as a legal opinion, and re-check the distributions you actually install.
|
| 601 |
+
|
| 602 |
+
Full evidence paths for each row are in the release descriptor
|
| 603 |
+
(`release/solomon-release.json` → `dependency_licences`), which is not distributed; the same
|
| 604 |
+
information is repeated in the comments of `requirements.lock`.
|
| 605 |
+
|
| 606 |
+
|
| 607 |
+
## Licence and attribution
|
| 608 |
+
|
| 609 |
+
Copyright 2026 Doccy Pty Ltd.
|
| 610 |
+
|
| 611 |
+
This repository is licensed **Apache-2.0** — the adapter and head weights, the calibration artifact,
|
| 612 |
+
the serving code and the documentation alike. See `LICENSE` and `NOTICE`.
|
| 613 |
+
|
| 614 |
+
It is a **derivative work** of `Qwen/Qwen3.8-27B`, Copyright 2026 Alibaba Cloud, licensed under Apache-2.0.
|
| 615 |
+
The upstream licence text is reproduced verbatim at `licenses/Qwen-Apache-2.0.txt` (sha256
|
| 616 |
+
`bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a`). `NOTICE` carries the attribution required by section 4(c) and
|
| 617 |
+
`MODIFICATIONS.md` the statement of changes required by section 4(b).
|
| 618 |
+
|
| 619 |
+
No `NOTICE` file exists in the upstream repository at the pinned revision (HTTP 404, checked
|
| 620 |
+
2026-09-18), so section 4(d) carries nothing forward and no upstream attribution text has been
|
| 621 |
+
invented.
|
| 622 |
+
|
| 623 |
+
"Qwen" and "Alibaba Cloud" are used nominatively to identify the base model. Apache-2.0 section 6
|
| 624 |
+
grants no trademark rights and none are claimed. No endorsement or affiliation is implied.
|
| 625 |
+
|
| 626 |
+
## Verify what you downloaded
|
| 627 |
+
|
| 628 |
+
```sh
|
| 629 |
+
shasum -a 256 adapter/adapter.safetensors # d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0
|
| 630 |
+
shasum -a 256 adapter/heads.npz # f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab
|
| 631 |
+
shasum -a 256 serving/readout-temperature-v3.json
|
| 632 |
+
# -> 1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9
|
| 633 |
+
```
|
| 634 |
+
|
| 635 |
+
`MANIFEST.json` carries the size and sha256 of every file in this repository.
|
| 636 |
+
|
| 637 |
+
The calibration artifact has **two legitimate and different hashes**, and confusing them makes a sound
|
| 638 |
+
provenance chain look tampered with. `1a2285d8…` is the *file* hash, what `shasum`
|
| 639 |
+
returns. `945bad44…` is the artifact's own internal `sha256` field, computed over its
|
| 640 |
+
contents with that field removed — a self-referential field cannot hash the file containing it. The
|
| 641 |
+
loader verifies the payload hash; use the file hash to check the file you were given. Both are recorded
|
| 642 |
+
in the serving binding's `provenance`, under those names.
|
| 643 |
+
|
| 644 |
+
## Release record
|
| 645 |
+
|
| 646 |
+
Machine-readable identity for citation and pinning. The model identity, the calibration and the runtime
|
| 647 |
+
binding move together; pin by revision.
|
| 648 |
+
|
| 649 |
+
| | |
|
| 650 |
+
|---|---|
|
| 651 |
+
| Repository | `DoccyHealth/Solomon` |
|
| 652 |
+
| Release | `1.1.0`, 2026-09-21 |
|
| 653 |
+
| Serving contract | `solomon-v1` |
|
| 654 |
+
| Adapter sha256 | `d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0` |
|
| 655 |
+
| Heads sha256 | `f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab` |
|
| 656 |
+
| Base model | `Qwen/Qwen3.8-27B` at `1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0` |
|
| 657 |
+
| Runtime binding sha256 (payload) | `0add0efda28902180db757a12160953e0f5d8dc303decc27b2cfda84db900da8` |
|
| 658 |
+
| Calibration sha256 (file / payload) | `1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9` / `945bad449b7f5ffc88e597277d632fbab81c3c8729e22c8babd3f4a45fe1378b` |
|
| 659 |
+
| Runtime fingerprint | `7d529382321e0e14131a643920d7522b85d1b521d249db89fba839b3fd0f8bea` |
|
| 660 |
+
| Readout | `four_collapsed` |
|
| 661 |
+
| Served temperatures | boolean 1.0 · multilabel 1.0 · single 1.0 · ordered 1.0 |
|
adapter/adapter.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0
|
| 3 |
+
size 870363376
|
adapter/config.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"adapter_bytes": 870363376,
|
| 3 |
+
"adapter_file": "adapter/adapter.safetensors",
|
| 4 |
+
"adapter_sha256": "d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0",
|
| 5 |
+
"answer_projection": "trained-semantic-head-float32",
|
| 6 |
+
"base_model_copyright": "2026 Alibaba Cloud",
|
| 7 |
+
"base_model_license": "Apache-2.0",
|
| 8 |
+
"base_model_name_or_path": "Qwen/Qwen3.8-27B",
|
| 9 |
+
"base_model_redistributed": false,
|
| 10 |
+
"base_model_revision": "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0",
|
| 11 |
+
"calibration_artifact": "serving/readout-temperature-v3.json",
|
| 12 |
+
"calibration_file_sha256": "1a2285d8fd56d17ee1d06a1e9fce866cc0d3b0263730754babb11deea5f1f7c9",
|
| 13 |
+
"calibration_fitted_on": {
|
| 14 |
+
"adapter_sha256": "d122466d430a058bb6457d919f811160e97fbd20149f4f24ca455c5d83e360a0",
|
| 15 |
+
"trained_heads_sha256": "f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab"
|
| 16 |
+
},
|
| 17 |
+
"calibration_note": "a temperature is fitted on ONE model's logits. The loader refuses to serve these scalars on any adapter other than the one named in calibration_fitted_on. Serving at T = 1.0 everywhere is always permitted on any model.",
|
| 18 |
+
"calibration_payload_sha256": "945bad449b7f5ffc88e597277d632fbab81c3c8729e22c8babd3f4a45fe1378b",
|
| 19 |
+
"contract": "solomon-v1",
|
| 20 |
+
"copyright": "2026 Doccy Pty Ltd",
|
| 21 |
+
"design": {
|
| 22 |
+
"ordered": "S",
|
| 23 |
+
"single_choice": "R"
|
| 24 |
+
},
|
| 25 |
+
"dtype": "float32",
|
| 26 |
+
"heads_bytes": 1643162,
|
| 27 |
+
"heads_file": "adapter/heads.npz",
|
| 28 |
+
"heads_sha256": "f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab",
|
| 29 |
+
"license": "apache-2.0",
|
| 30 |
+
"lora_alpha": 64,
|
| 31 |
+
"measured_arithmetic": "fp32",
|
| 32 |
+
"measured_backend": "cuda",
|
| 33 |
+
"model_name": "Solomon",
|
| 34 |
+
"peft_type": "LORA",
|
| 35 |
+
"placement": "question",
|
| 36 |
+
"placement_note": "question-side: the adapter is OFF while the document prefix is prefilled and ON from the question branch onward. Applying it to the whole sequence gives a different model to the one that was measured.",
|
| 37 |
+
"r": 64,
|
| 38 |
+
"readout": "four_collapsed",
|
| 39 |
+
"runtime_fingerprint": "7d529382321e0e14131a643920d7522b85d1b521d249db89fba839b3fd0f8bea",
|
| 40 |
+
"schema": "solomon-adapter-config-v1",
|
| 41 |
+
"serving_binding": "serving/serving-binding.json",
|
| 42 |
+
"serving_binding_sha256": "0add0efda28902180db757a12160953e0f5d8dc303decc27b2cfda84db900da8",
|
| 43 |
+
"task_type": "FEATURE_EXTRACTION",
|
| 44 |
+
"version": "1.1.0"
|
| 45 |
+
}
|
adapter/heads.npz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f766d752d7768a419a9657155cf27f042834d9de29392cf7470d8725130e67ab
|
| 3 |
+
size 1643162
|
licenses/Qwen-Apache-2.0.txt
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright 2026 Alibaba Cloud
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
mlx/.gitignore
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
.pytest_cache/
|
| 4 |
+
.ruff_cache/
|
| 5 |
+
*.egg-info/
|
| 6 |
+
snapshots/
|
| 7 |
+
models/
|
| 8 |
+
evaluations/
|
| 9 |
+
*.log
|
| 10 |
+
|
| 11 |
+
document-replay.json
|
| 12 |
+
dist/
|
mlx/CONVERTER-SOURCE.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"converter_code_sha256": "810ec77e6a1e4972a942bc5bcea502183b97e048c9b317a6cc38c2cab45fcaeb",
|
| 3 |
+
"files": {
|
| 4 |
+
"__init__.py": "714a5439b33780d250c404938cd062c0d6809f83f21b59f89997bd168469925a",
|
| 5 |
+
"_vendor/__init__.py": "77defd15cc47661e0e9a31275e7fd59e979f3f9a6429671d8199f6002dca6c2c",
|
| 6 |
+
"_vendor/contract.py": "7c6607179a028f30b462349a86f9cf7d0ec2652e0a1c7c8c24649b6ce71df697",
|
| 7 |
+
"_vendor/evidence.py": "18a4978a27d6bbd3f7daaa34836d1820303c4ff581b0dfda877aab586392293b",
|
| 8 |
+
"_vendor/evidence_v3.py": "6ff3da1e920c082e9b3629ca0230007262f2ce69fd921b89dd4b3e67511b3a64",
|
| 9 |
+
"_vendor/prompts.py": "8bfb5a12d625664c8830f5cf243aac04d1e973bfe4f5ecfc8221021f09c318df",
|
| 10 |
+
"_vendor/retrieval.py": "11e7bbb1a84ba837eac3768d6e882f44a557be25d62729c8a39dd5cb870c0932",
|
| 11 |
+
"_vendor/semantics.py": "b580d3c114536a6faf58bcd92d2c61028f80891a19d78d6a17ed585948abfc15",
|
| 12 |
+
"api.py": "bae9fdd3ef6b395142ec5c099635cc9ba90f7f33c7423f99caf6009f51d4fd3c",
|
| 13 |
+
"artifacts.py": "0b3d102a2a04d88b2a1f3eb8a22506f626191615d779bfd53a4377824e6c239b",
|
| 14 |
+
"budget.py": "f72614686c19e1d923e6bc23d4353e8b1ac150863565939ae4a3831bc4ecd211",
|
| 15 |
+
"cli.py": "0a6be4cd03621963ec5f73a8af71224cb8b40ae88232477d8370b7d3b9b75021",
|
| 16 |
+
"engine.py": "13c27c3fbca576ae0d70262c2a75c9382df3b4fcfd8a11996d125750883b648a",
|
| 17 |
+
"evaluation.py": "bb9f50d184527e21139b9ffb5e9d1613bc30822ccd7cf06b7b7f8b1cc8b50674",
|
| 18 |
+
"prepare.py": "dda9879a9ddc1c3f6dcf0df52b3a244b2ca7920946bbd29ddc8e1c0f9944b887"
|
| 19 |
+
},
|
| 20 |
+
"schema": "solomon-mlx-converter-source-v1"
|
| 21 |
+
}
|
mlx/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright 2026 Doccy Pty Ltd
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
mlx/MODIFICATIONS.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Solomon MLX modifications
|
| 2 |
+
|
| 3 |
+
This port adapts Doccy Pty Ltd’s Apache-2.0 Solomon source at revision
|
| 4 |
+
`5c0a4a82ddaeca6da2e3013f7045a8196c86957d`. Original modification notices are preserved in
|
| 5 |
+
`docs/UPSTREAM-MODIFICATIONS.md`.
|
| 6 |
+
|
| 7 |
+
Changes:
|
| 8 |
+
|
| 9 |
+
- Replaced CUDA execution with MLX-VLM Qwen3.5 execution for the declared Qwen3.8 architecture.
|
| 10 |
+
- Added BF16 shard conversion with FP32 normalization parameters, adapter, trained heads and recurrent states.
|
| 11 |
+
- Replaced global adapter state with instance-owned state and isolated question cache containers.
|
| 12 |
+
- Removed vocabulary projection from decision inference.
|
| 13 |
+
- Added a document-state API, replay recipes, artifact checksums and MLX-specific runtime identities.
|
| 14 |
+
- Extracted the original prompts, question contract, semantics and evidence utilities into `_vendor`.
|
| 15 |
+
- Implemented the documented ordering-score product locally because the release omits `scope9.reliability`.
|
| 16 |
+
- Added download, CUDA parity comparison, benchmark and test tools. New temperature fitting is outside the current scope.
|
| 17 |
+
|
| 18 |
+
No claim is made that this port inherits CUDA calibration or qualification. See
|
| 19 |
+
`docs/VALIDATION-20260921.md` for measured results and outstanding validation.
|
| 20 |
+
|
| 21 |
+
Adapter-only distribution update (21 September 2026): added a separate verified Hub
|
| 22 |
+
loader, atomic local assembly and cache reuse; retained the exact historical converter
|
| 23 |
+
source and FP32 normalization handling. Base weights are downloaded from the pinned
|
| 24 |
+
Qwen repository. Duplicate adapter/head files under `mlx/bf16` are replaced by the
|
| 25 |
+
root `adapter/` copies. CUDA parity status is reported separately from conversion.
|
mlx/NOTICE
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Solomon v1.1.0
|
| 2 |
+
Copyright 2026 Doccy Pty Ltd
|
| 3 |
+
|
| 4 |
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
| 5 |
+
this work except in compliance with the License. You may obtain a copy of the
|
| 6 |
+
License in the LICENSE file distributed with this work, or at
|
| 7 |
+
|
| 8 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
|
| 10 |
+
--------------------------------------------------------------------------------
|
| 11 |
+
ATTRIBUTION FOR THE BASE MODEL (Apache License 2.0, section 4(c))
|
| 12 |
+
--------------------------------------------------------------------------------
|
| 13 |
+
|
| 14 |
+
This work is a DERIVATIVE WORK of:
|
| 15 |
+
|
| 16 |
+
Qwen/Qwen3.8-27B
|
| 17 |
+
Copyright 2026 Alibaba Cloud
|
| 18 |
+
Licensed under the Apache License, Version 2.0
|
| 19 |
+
Pinned revision: 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0
|
| 20 |
+
Licence text: licenses/Qwen-Apache-2.0.txt (sha256 bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a, 11544 bytes,
|
| 21 |
+
the exact bytes served at the pinned revision)
|
| 22 |
+
|
| 23 |
+
The base model weights are NOT redistributed in this repository. They are
|
| 24 |
+
referenced by the pinned revision above and downloaded by the operator directly
|
| 25 |
+
from the upstream repository under the upstream licence.
|
| 26 |
+
|
| 27 |
+
Upstream NOTICE file: NONE. A NOTICE file is absent from Qwen/Qwen3.8-27B at the
|
| 28 |
+
pinned revision (HTTP 404, retrieved 2026-09-18T03:49Z without credentials).
|
| 29 |
+
Apache-2.0 section 4(d) therefore imposes no carry-forward obligation here. No
|
| 30 |
+
upstream attribution text has been invented or paraphrased.
|
| 31 |
+
|
| 32 |
+
"Qwen" and "Alibaba Cloud" are used nominatively, to identify the base model
|
| 33 |
+
this adapter was trained against. Apache-2.0 section 6 grants no trademark
|
| 34 |
+
rights and none are claimed or implied. Nothing here states or implies any
|
| 35 |
+
endorsement, sponsorship or affiliation.
|
| 36 |
+
|
| 37 |
+
--------------------------------------------------------------------------------
|
| 38 |
+
STATEMENT OF CHANGES (Apache License 2.0, section 4(b))
|
| 39 |
+
--------------------------------------------------------------------------------
|
| 40 |
+
|
| 41 |
+
No upstream source file is modified, and no upstream file is redistributed
|
| 42 |
+
except the unmodified licence text at licenses/Qwen-Apache-2.0.txt.
|
| 43 |
+
|
| 44 |
+
The modification this work carries is a trained LoRA adapter and a set of
|
| 45 |
+
trained linear answer heads, applied to the base model at inference time:
|
| 46 |
+
|
| 47 |
+
* LoRA adapter, rank 64, question-side placement, float32
|
| 48 |
+
adapter/adapter.safetensors
|
| 49 |
+
sha256 2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca
|
| 50 |
+
870363376 bytes
|
| 51 |
+
* Trained linear answer heads
|
| 52 |
+
adapter/heads.npz
|
| 53 |
+
sha256 126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f
|
| 54 |
+
2053938 bytes
|
| 55 |
+
* Readout calibration (one positive scalar per task)
|
| 56 |
+
serving/scope9-readout-temperature-v2.json
|
| 57 |
+
file sha256 baa7263ca9e865dda230617563e6a615de5050adc620c28924dffef68d527118
|
| 58 |
+
payload sha256 682d611ec53c3322905c7e265bf9b9b35a1cd581f6d8b7ea924df864a3d74278
|
| 59 |
+
|
| 60 |
+
Training took place between 16 and 20 September 2026. The adapter and the heads
|
| 61 |
+
are identified by the checksums above. Full change detail is in MODIFICATIONS.md.
|
| 62 |
+
|
| 63 |
+
--------------------------------------------------------------------------------
|
| 64 |
+
THIRD-PARTY CONTENT IN THIS REPOSITORY
|
| 65 |
+
--------------------------------------------------------------------------------
|
| 66 |
+
|
| 67 |
+
The only third-party content distributed here is the unmodified Apache License
|
| 68 |
+
2.0 text at licenses/Qwen-Apache-2.0.txt, reproduced to satisfy section 4(a).
|
| 69 |
+
|
| 70 |
+
No training document, evaluation panel, dataset, corpus, rendered page, cached
|
| 71 |
+
state, score archive or acceptance fixture is distributed. Every file in this
|
| 72 |
+
repository was scanned for text originating in third-party source documents
|
| 73 |
+
before release; see MODIFICATIONS.md, "Third-party text scan".
|
| 74 |
+
|
| 75 |
+
Everything else in this repository -- the serving code under src/, the adapter
|
| 76 |
+
and head weights, the calibration artifact, the serving binding and the
|
| 77 |
+
documentation -- is original work of Doccy Pty Ltd, licensed under
|
| 78 |
+
Apache-2.0.
|
mlx/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Solomon MLX
|
| 2 |
+
|
| 3 |
+
Full BF16 Solomon v1.1 inference on Apple Silicon. The repository distributes
|
| 4 |
+
adapters and source code; the Qwen backbone is downloaded separately from its
|
| 5 |
+
pinned upstream revision and converted locally. No quantization or LoRA merging
|
| 6 |
+
is performed. Full-model measurements use an M5 Max with 128 GB memory, with
|
| 7 |
+
about 59.9 GB peak Metal allocation on the focused fixtures. Longer documents
|
| 8 |
+
and more images require additional memory; 24–32 GB Macs cannot run this profile.
|
| 9 |
+
|
| 10 |
+
**Status: experimental.** Focused text and image decisions match CUDA. Complete
|
| 11 |
+
held-out parity remains pending. Qualification is CUDA parity only: no new
|
| 12 |
+
calibration or temperature fitting. See [validation results](docs/VALIDATION-20260921.md).
|
| 13 |
+
|
| 14 |
+
## Install from this repository
|
| 15 |
+
|
| 16 |
+
Use Python 3.12 or 3.13 on Apple Silicon. Pin the full repository commit shown on
|
| 17 |
+
Hugging Face, including after any repository history rewrite. The historical
|
| 18 |
+
Solomon source revision remains provenance; it is not required to be downloadable.
|
| 19 |
+
|
| 20 |
+
```sh
|
| 21 |
+
# From a source checkout, enter its mlx/ directory first.
|
| 22 |
+
uv sync --frozen --extra dev
|
| 23 |
+
|
| 24 |
+
# Obtain the current commit once, then retain it for repeatable downloads.
|
| 25 |
+
SOLOMON_COMMIT=$(uv run python -c 'from huggingface_hub import HfApi; print(HfApi().model_info("DoccyHealth/Solomon").sha)')
|
| 26 |
+
uv run solomon-mlx-hub prepare --revision "$SOLOMON_COMMIT" --output models/quality
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
Authenticate with `hf auth login` first if the repository requires access. This
|
| 30 |
+
package is supplied here as source; it is not claimed to be published on PyPI.
|
| 31 |
+
For a checkout without downloading model files through Git LFS:
|
| 32 |
+
|
| 33 |
+
```sh
|
| 34 |
+
GIT_LFS_SKIP_SMUDGE=1 git clone https://huggingface.co/DoccyHealth/Solomon
|
| 35 |
+
cd Solomon/mlx
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
The setup tool explicitly fetches `adapter/**` and the retained MLX licensing
|
| 39 |
+
metadata. It downloads `Qwen/Qwen3.8-27B` at
|
| 40 |
+
`1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`, verifies every input against the
|
| 41 |
+
bundled manifest, and converts one shard at a time. Budget about 112 GB of disk
|
| 42 |
+
for original and converted weights, plus temporary space and caches. Existing
|
| 43 |
+
original base files can be reused with `--base /path/to/original-qwen`.
|
| 44 |
+
|
| 45 |
+
The output contains `backbone/`, the unmerged adapter, trained heads, notices
|
| 46 |
+
and a fresh `binding.json`. Existing valid outputs are verified and reused;
|
| 47 |
+
corrupt or incompatible outputs fail without being overwritten. Conversion is
|
| 48 |
+
atomic and concurrent preparations into the same output are rejected. Interrupted
|
| 49 |
+
conversions may leave a hidden temporary directory; the final output is never
|
| 50 |
+
marked ready before verification completes.
|
| 51 |
+
|
| 52 |
+
For fully offline preparation, provide both downloaded inputs:
|
| 53 |
+
|
| 54 |
+
```sh
|
| 55 |
+
uv run solomon-mlx-hub prepare --revision "$SOLOMON_COMMIT" \
|
| 56 |
+
--snapshot /path/to/solomon-snapshot --base /path/to/original-qwen \
|
| 57 |
+
--output models/quality
|
| 58 |
+
uv run solomon-mlx-hub verify models/quality
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
CPU conversion is the default. `--device gpu` selects Metal conversion on a Mac.
|
| 62 |
+
Linux CPU conversion is also supported by the existing converter and can use
|
| 63 |
+
`uv sync --frozen --extra cloud` with MLX's CPU backend. Linux conversion does
|
| 64 |
+
not run Apple Metal inference or establish CUDA parity.
|
| 65 |
+
|
| 66 |
+
## Converter and provenance
|
| 67 |
+
|
| 68 |
+
The exact converter is [src/solomon_mlx/prepare.py](src/solomon_mlx/prepare.py).
|
| 69 |
+
The runtime Python sources are unchanged in behaviour. The only edits made for
|
| 70 |
+
this release rename the runtime identity's `source_contract` field to `solomon-v1`
|
| 71 |
+
and adjust comments, docstrings and one error message, so their combined
|
| 72 |
+
`converter_code_sha256` is
|
| 73 |
+
`bbcae17fc1c35db80a79d5865133a42ef9a1b0cf342fff71949972e69cce43ec`.
|
| 74 |
+
It is computed by `solomon_mlx.artifacts.code_identity()` from the sorted mapping
|
| 75 |
+
of relative Python paths to SHA-256 values. The new download/assembly wrapper is
|
| 76 |
+
in the separate `solomon_mlx_hub` package.
|
| 77 |
+
|
| 78 |
+
The converter retains large weights in BF16 and promotes normalization weights,
|
| 79 |
+
`A_log` and `dt_bias` to FP32 **before** applying upstream normalization offsets.
|
| 80 |
+
It validates tensor names and shapes with MLX-VLM's Qwen3.5 implementation. The
|
| 81 |
+
original FP32 adapter and ten trained heads are copied without changes. The
|
| 82 |
+
runtime applies the adapter only to question tokens, with its explicit 2.0 scale.
|
| 83 |
+
|
| 84 |
+
`bf16/conversion.json` and `bf16/binding.json` describe the historical cloud
|
| 85 |
+
conversion; paths inside them describe the original local model layout. They
|
| 86 |
+
are provenance, not a manifest of files currently present on the Hub, and they
|
| 87 |
+
record the converter hash of that historical conversion, `648e440cface0838f2dcc8d89b3ab172d97f4ffc1f88fe0b7cbbe3ca73b8a575`,
|
| 88 |
+
which predates the documentation edits described above. The root
|
| 89 |
+
adapter files have the same hashes as their removed duplicates. Newly converted
|
| 90 |
+
safetensors may serialize differently across CPU and Metal, so new outputs get
|
| 91 |
+
actual output checksums and their own runtime binding. Historical CUDA or MLX
|
| 92 |
+
qualification identities are never reused for a different artifact binding.
|
| 93 |
+
|
| 94 |
+
## Python API
|
| 95 |
+
|
| 96 |
+
```python
|
| 97 |
+
from solomon_mlx import Solomon
|
| 98 |
+
|
| 99 |
+
model = Solomon.load("models/quality", profile="quality")
|
| 100 |
+
with model.prefill("Rookwood Ltd holds a current certification.") as state:
|
| 101 |
+
result = model.decide(
|
| 102 |
+
state=state,
|
| 103 |
+
questions={"certified": {
|
| 104 |
+
"type": "noul",
|
| 105 |
+
"instructions": "Does Rookwood Ltd hold a current certification?",
|
| 106 |
+
}},
|
| 107 |
+
evidence="support",
|
| 108 |
+
)
|
| 109 |
+
print(result["answers"]["certified"])
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
Or use `solomon_mlx_hub.load("models/quality", revision=COMMIT)` to prepare and
|
| 113 |
+
load in one call. `revision` must be a full 40-character commit SHA. Cached valid
|
| 114 |
+
outputs are reused without network access and retain their original binding.
|
| 115 |
+
|
| 116 |
+
Documents accept text, structured JSON objects, or ordered `{"text": ...}` and
|
| 117 |
+
`{"image": local_path}` parts. Image features are computed once per document.
|
| 118 |
+
There is no PDF renderer or OCR. Question forms preserve Boolean, entity and
|
| 119 |
+
multilabel `noul`, single `choice`, and ordered `score` semantics; candidate order
|
| 120 |
+
is retained. Missing/conflicting facts collapse before temperature application.
|
| 121 |
+
The API defaults to T=1. No new temperatures are fitted by setup or parity checks.
|
| 122 |
+
|
| 123 |
+
Evidence levels are `none`, `support`, `sufficiency`, and `removal`. Text spans use
|
| 124 |
+
exact code-point offsets. Sufficiency and removal re-encode the relevant source;
|
| 125 |
+
they do not establish causal faithfulness. Image evidence requires `page_selector=`;
|
| 126 |
+
otherwise the result reports `unsupported_page_selector`. States belong to one
|
| 127 |
+
model instance and support `close()`, `save(path)`, and `model.replay(path)`.
|
| 128 |
+
Replay persists a checksummed source recipe and recomputes caches.
|
| 129 |
+
|
| 130 |
+
## Tests
|
| 131 |
+
|
| 132 |
+
```sh
|
| 133 |
+
uv run pytest -q
|
| 134 |
+
uv run ruff check src tests scripts
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
Tests use synthetic small models to cover conversion precision, CPU/Metal tensor
|
| 138 |
+
agreement, cache isolation, text/image processing, answer semantics, evidence,
|
| 139 |
+
artifact corruption, and adapter-only setup. These tests do not replace trained
|
| 140 |
+
model parity measurements. The included parity checker compares saved CUDA and
|
| 141 |
+
MLX scores using the same frozen temperatures exactly once, reports probability
|
| 142 |
+
drift separately, and cannot pass a complete-panel gate from partial results.
|
| 143 |
+
Evaluation inputs and private infrastructure configuration are not distributed.
|
| 144 |
+
|
| 145 |
+
Preserve `LICENSE`, `NOTICE`, `MODIFICATIONS.md`, and upstream model notices with
|
| 146 |
+
permitted copies. Model downloads and conversion do not alter repository visibility.
|
mlx/bf16/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright 2026 Doccy Pty Ltd
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
mlx/bf16/MODIFICATIONS.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Statement of changes
|
| 2 |
+
|
| 3 |
+
Apache License 2.0, section 4(b): prominent notice that files carry modifications.
|
| 4 |
+
|
| 5 |
+
## What is modified
|
| 6 |
+
|
| 7 |
+
**No upstream source file is modified.** No file from `Qwen/Qwen3.8-27B` is edited,
|
| 8 |
+
renamed, patched or redistributed in this repository, with one exception: the
|
| 9 |
+
upstream licence text is reproduced byte-for-byte at `licenses/Qwen-Apache-2.0.txt`
|
| 10 |
+
(sha256 `bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a`) because section 4(a) requires it. That file is
|
| 11 |
+
unmodified and carries the upstream copyright.
|
| 12 |
+
|
| 13 |
+
The modification this work carries is not an edit to a source file. It is a set
|
| 14 |
+
of **trained parameters applied to the base model at inference time**, plus an
|
| 15 |
+
original serving layer that reads the model's logits. Concretely:
|
| 16 |
+
|
| 17 |
+
| Change | Artifact | sha256 |
|
| 18 |
+
|---|---|---|
|
| 19 |
+
| LoRA adapter, rank 64, question-side placement, float32 | `adapter/adapter.safetensors` | `2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca` |
|
| 20 |
+
| Trained linear answer heads | `adapter/heads.npz` | `126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f` |
|
| 21 |
+
| Readout calibration, one positive scalar per task | `serving/scope9-readout-temperature-v2.json` | file `baa7263ca9e865dda230617563e6a615de5050adc620c28924dffef68d527118` / payload `682d611ec53c3322905c7e265bf9b9b35a1cd581f6d8b7ea924df864a3d74278` |
|
| 22 |
+
| Runtime identity binding | `serving/serving-binding.json` | payload `95683c1f87ec3f71b7657669dc311918ff53b7d41a981eaa8d827047e72cb505` |
|
| 23 |
+
| Serving layer (original work, not derived from upstream code) | `src/` | see `MANIFEST.json` |
|
| 24 |
+
|
| 25 |
+
Base model, unmodified and not redistributed: `Qwen/Qwen3.8-27B` at revision
|
| 26 |
+
`1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`, Copyright 2026 Alibaba Cloud, Apache-2.0.
|
| 27 |
+
|
| 28 |
+
Training took place between 16 and 20 September 2026. The shipped artifacts are
|
| 29 |
+
identified by the checksums in the table above and in `MANIFEST.json`.
|
| 30 |
+
|
| 31 |
+
## Which files carry a change notice
|
| 32 |
+
|
| 33 |
+
| File | Why |
|
| 34 |
+
|---|---|
|
| 35 |
+
| `NOTICE` | Section 4(b) and 4(c) statement, carried with every copy |
|
| 36 |
+
| `MODIFICATIONS.md` | this file |
|
| 37 |
+
| `README.md` | names the base model, the pinned revision and the derivative relationship in the front matter and in the body |
|
| 38 |
+
| `adapter/config.json` | machine-readable record of the base repo, the pinned revision and both weight checksums |
|
| 39 |
+
| `serving/serving-binding.json` | pins the exact runtime the weights were measured on and refuses to load against a different one |
|
| 40 |
+
|
| 41 |
+
No file under `src/` carries an upstream change notice, because no file under
|
| 42 |
+
`src/` contains upstream code. Every file there is original work, written for
|
| 43 |
+
this project, and is covered by the repository's own Apache-2.0 `LICENSE` and by
|
| 44 |
+
the copyright line in `NOTICE`.
|
| 45 |
+
|
| 46 |
+
All of the changes described above — the adapter, the heads, the calibration, the
|
| 47 |
+
serving binding and the serving layer — are Copyright 2026
|
| 48 |
+
Doccy Pty Ltd and licensed under Apache-2.0.
|
| 49 |
+
|
| 50 |
+
## Third-party text scan
|
| 51 |
+
|
| 52 |
+
Before release, **every file staged into this repository was scanned for text
|
| 53 |
+
originating in third-party source documents.** The scan compared normalised
|
| 54 |
+
6-gram and 8-gram shingles of every staged text file against:
|
| 55 |
+
|
| 56 |
+
1. the 42 third-party source records the training and evaluation panels were
|
| 57 |
+
built from (Apache-2.0, MIT, BSD-3-Clause, CC BY 4.0, CC BY-SA 4.0, CC0,
|
| 58 |
+
OGL v3.0 and US-government public-domain assertions); and
|
| 59 |
+
2. every generated panel and document corpus on disk.
|
| 60 |
+
|
| 61 |
+
**Result: no third-party document text is present in any shipped file.** The
|
| 62 |
+
only matches were:
|
| 63 |
+
|
| 64 |
+
* the reproduced Apache-2.0 licence text at `licenses/Qwen-Apache-2.0.txt`, which
|
| 65 |
+
matches an Apache-2.0 licence document held in the evaluation corpus and is
|
| 66 |
+
required to be here verbatim; and
|
| 67 |
+
* the phrase *"A missing fact is not a negative fact"*, which is **our own
|
| 68 |
+
prompt-template wording** appearing in our own evaluation panels, not
|
| 69 |
+
third-party text entering our prompts.
|
| 70 |
+
|
| 71 |
+
Acceptance fixtures are excluded from this repository entirely. The fixture
|
| 72 |
+
documents used in live acceptance are original synthetic text authored for this
|
| 73 |
+
project and held in tooling that is not distributed.
|
| 74 |
+
|
| 75 |
+
Re-run the scan with `ops/solomon_package.py --scan` in the source project.
|
mlx/bf16/NOTICE
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Solomon v1.1.0
|
| 2 |
+
Copyright 2026 Doccy Pty Ltd
|
| 3 |
+
|
| 4 |
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
| 5 |
+
this work except in compliance with the License. You may obtain a copy of the
|
| 6 |
+
License in the LICENSE file distributed with this work, or at
|
| 7 |
+
|
| 8 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
|
| 10 |
+
--------------------------------------------------------------------------------
|
| 11 |
+
ATTRIBUTION FOR THE BASE MODEL (Apache License 2.0, section 4(c))
|
| 12 |
+
--------------------------------------------------------------------------------
|
| 13 |
+
|
| 14 |
+
This work is a DERIVATIVE WORK of:
|
| 15 |
+
|
| 16 |
+
Qwen/Qwen3.8-27B
|
| 17 |
+
Copyright 2026 Alibaba Cloud
|
| 18 |
+
Licensed under the Apache License, Version 2.0
|
| 19 |
+
Pinned revision: 1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0
|
| 20 |
+
Licence text: licenses/Qwen-Apache-2.0.txt (sha256 bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a, 11544 bytes,
|
| 21 |
+
the exact bytes served at the pinned revision)
|
| 22 |
+
|
| 23 |
+
The base model weights are NOT redistributed in this repository. They are
|
| 24 |
+
referenced by the pinned revision above and downloaded by the operator directly
|
| 25 |
+
from the upstream repository under the upstream licence.
|
| 26 |
+
|
| 27 |
+
Upstream NOTICE file: NONE. A NOTICE file is absent from Qwen/Qwen3.8-27B at the
|
| 28 |
+
pinned revision (HTTP 404, retrieved 2026-09-18T03:49Z without credentials).
|
| 29 |
+
Apache-2.0 section 4(d) therefore imposes no carry-forward obligation here. No
|
| 30 |
+
upstream attribution text has been invented or paraphrased.
|
| 31 |
+
|
| 32 |
+
"Qwen" and "Alibaba Cloud" are used nominatively, to identify the base model
|
| 33 |
+
this adapter was trained against. Apache-2.0 section 6 grants no trademark
|
| 34 |
+
rights and none are claimed or implied. Nothing here states or implies any
|
| 35 |
+
endorsement, sponsorship or affiliation.
|
| 36 |
+
|
| 37 |
+
--------------------------------------------------------------------------------
|
| 38 |
+
STATEMENT OF CHANGES (Apache License 2.0, section 4(b))
|
| 39 |
+
--------------------------------------------------------------------------------
|
| 40 |
+
|
| 41 |
+
No upstream source file is modified, and no upstream file is redistributed
|
| 42 |
+
except the unmodified licence text at licenses/Qwen-Apache-2.0.txt.
|
| 43 |
+
|
| 44 |
+
The modification this work carries is a trained LoRA adapter and a set of
|
| 45 |
+
trained linear answer heads, applied to the base model at inference time:
|
| 46 |
+
|
| 47 |
+
* LoRA adapter, rank 64, question-side placement, float32
|
| 48 |
+
adapter/adapter.safetensors
|
| 49 |
+
sha256 2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca
|
| 50 |
+
870363376 bytes
|
| 51 |
+
* Trained linear answer heads
|
| 52 |
+
adapter/heads.npz
|
| 53 |
+
sha256 126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f
|
| 54 |
+
2053938 bytes
|
| 55 |
+
* Readout calibration (one positive scalar per task)
|
| 56 |
+
serving/scope9-readout-temperature-v2.json
|
| 57 |
+
file sha256 baa7263ca9e865dda230617563e6a615de5050adc620c28924dffef68d527118
|
| 58 |
+
payload sha256 682d611ec53c3322905c7e265bf9b9b35a1cd581f6d8b7ea924df864a3d74278
|
| 59 |
+
|
| 60 |
+
Training took place between 16 and 20 September 2026. The adapter and the heads
|
| 61 |
+
are identified by the checksums above. Full change detail is in MODIFICATIONS.md.
|
| 62 |
+
|
| 63 |
+
--------------------------------------------------------------------------------
|
| 64 |
+
THIRD-PARTY CONTENT IN THIS REPOSITORY
|
| 65 |
+
--------------------------------------------------------------------------------
|
| 66 |
+
|
| 67 |
+
The only third-party content distributed here is the unmodified Apache License
|
| 68 |
+
2.0 text at licenses/Qwen-Apache-2.0.txt, reproduced to satisfy section 4(a).
|
| 69 |
+
|
| 70 |
+
No training document, evaluation panel, dataset, corpus, rendered page, cached
|
| 71 |
+
state, score archive or acceptance fixture is distributed. Every file in this
|
| 72 |
+
repository was scanned for text originating in third-party source documents
|
| 73 |
+
before release; see MODIFICATIONS.md, "Third-party text scan".
|
| 74 |
+
|
| 75 |
+
Everything else in this repository -- the serving code under src/, the adapter
|
| 76 |
+
and head weights, the calibration artifact, the serving binding and the
|
| 77 |
+
documentation -- is original work of Doccy Pty Ltd, licensed under
|
| 78 |
+
Apache-2.0.
|
mlx/bf16/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Solomon BF16 conversion provenance
|
| 2 |
+
|
| 3 |
+
This directory retains metadata for the unquantized BF16 conversion. **Backbone
|
| 4 |
+
weights are downloaded separately from Qwen; adapter and head weights live at
|
| 5 |
+
`adapter/adapter.safetensors` and `adapter/heads.npz` in the repository root.**
|
| 6 |
+
This directory is no longer a self-contained loadable model.
|
| 7 |
+
|
| 8 |
+
Install the source package in [`../`](../) and follow its README. From that
|
| 9 |
+
package directory:
|
| 10 |
+
|
| 11 |
+
```sh
|
| 12 |
+
uv sync --frozen --extra dev
|
| 13 |
+
SOLOMON_COMMIT=$(uv run python -c 'from huggingface_hub import HfApi; print(HfApi().model_info("DoccyHealth/Solomon").sha)')
|
| 14 |
+
uv run solomon-mlx-hub prepare --revision "$SOLOMON_COMMIT" --output models/quality
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
The loader fetches `adapter/**` plus MLX licensing metadata at the pinned Solomon
|
| 18 |
+
commit. It obtains the original base from `Qwen/Qwen3.8-27B` at
|
| 19 |
+
`1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`, verifies every base file, and invokes
|
| 20 |
+
the included exact converter. Existing original weights can be supplied with
|
| 21 |
+
`--base`. Existing valid converted outputs are verified and reused.
|
| 22 |
+
|
| 23 |
+
The original converter source is `../src/solomon_mlx/prepare.py`. The runtime
|
| 24 |
+
source hash recorded in `conversion.json` for this historical conversion is
|
| 25 |
+
`648e440cface0838f2dcc8d89b3ab172d97f4ffc1f88fe0b7cbbe3ca73b8a575`. The
|
| 26 |
+
current runtime source hash is
|
| 27 |
+
`bbcae17fc1c35db80a79d5865133a42ef9a1b0cf342fff71949972e69cce43ec`;
|
| 28 |
+
the two differ only by the release documentation edits described in `../README.md`,
|
| 29 |
+
which changed no converter behaviour. The new Hub loader is packaged separately so the original
|
| 30 |
+
converter remains reproducible. Dependency versions are locked in `../uv.lock`.
|
| 31 |
+
Large matrices stay BF16; normalization parameters, `A_log`, and `dt_bias` stay
|
| 32 |
+
FP32, with normalization offsets applied after promotion. LoRA is never merged.
|
| 33 |
+
|
| 34 |
+
`conversion.json` and `binding.json` retain the historical output checksums and
|
| 35 |
+
paths, including removed backbone and duplicate adapter paths. The root adapter
|
| 36 |
+
and heads are byte-identical to those historical records. The old binding SHA-256
|
| 37 |
+
is `6d45715aa040fad98b061ff2cbafb35b047143ef2475646cee3df7a334f4d530`.
|
| 38 |
+
New local conversions receive a fresh binding with actual output checksums;
|
| 39 |
+
safetensors serialization may differ across CPU and Metal. The historical source
|
| 40 |
+
revision `2ec506902269e4636285c8811f6c0f52c9300c0c` is provenance, not a required
|
| 41 |
+
future download URL. After a history rewrite, pin the new repository commit.
|
| 42 |
+
|
| 43 |
+
**Experimental: complete CUDA parity remains pending.** Focused text/image
|
| 44 |
+
fixtures and a partial text panel match CUDA decisions. See the dated results in
|
| 45 |
+
`../docs/VALIDATION-20260921.md`. No new calibration or temperature fitting is
|
| 46 |
+
required or performed. Existing CUDA temperatures are applied identically to both
|
| 47 |
+
backends for comparison; CUDA qualification is not inherited.
|
| 48 |
+
|
| 49 |
+
The historical conversion produced 55,610,774,146 bytes. Focused inference used
|
| 50 |
+
about 59.9 GB peak Metal allocation on an M5 Max / 128 GB Mac; larger inputs need
|
| 51 |
+
more memory. This is full BF16, without quantization, and does not fit 24–32 GB Macs.
|
mlx/bf16/base-manifest.json
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"revision": "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0",
|
| 3 |
+
"files": [
|
| 4 |
+
{
|
| 5 |
+
"name": ".gitattributes",
|
| 6 |
+
"size": 1570,
|
| 7 |
+
"blob_id": "52373fe24473b1aa44333d318f578ae6bf04b49b",
|
| 8 |
+
"sha256": null
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"name": "LICENSE",
|
| 12 |
+
"size": 11544,
|
| 13 |
+
"blob_id": "f938136e3adacfd92be087f6e113b5d6d97f678f",
|
| 14 |
+
"sha256": null
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"name": "README.md",
|
| 18 |
+
"size": 65012,
|
| 19 |
+
"blob_id": "bc8aa0e396cd029c21cd773cca21830d0ded28ec",
|
| 20 |
+
"sha256": null
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"name": "chat_template.jinja",
|
| 24 |
+
"size": 8952,
|
| 25 |
+
"blob_id": "c0c686f9c38d70d179fb7b5f5aa7530bc913dda3",
|
| 26 |
+
"sha256": null
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"name": "config.json",
|
| 30 |
+
"size": 4312,
|
| 31 |
+
"blob_id": "706cebd746c4b6f2b1d1f892630867acfdfd3df8",
|
| 32 |
+
"sha256": null
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"name": "crc32.txt",
|
| 36 |
+
"size": 238,
|
| 37 |
+
"blob_id": "6de5ee6a0c6596744baee911af0a5cdcb8d99a1e",
|
| 38 |
+
"sha256": null
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"name": "generation_config.json",
|
| 42 |
+
"size": 202,
|
| 43 |
+
"blob_id": "023756cfadf88e5bf69eefeee3e172f38c448d64",
|
| 44 |
+
"sha256": null
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"name": "merges.txt",
|
| 48 |
+
"size": 3353259,
|
| 49 |
+
"blob_id": "a494e019ca1502219fd0128658b979e5f05ae8e8",
|
| 50 |
+
"sha256": null
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"name": "model-00001-of-00018.safetensors",
|
| 54 |
+
"size": 3966730552,
|
| 55 |
+
"blob_id": "79b73cdd69afeca931d181f5d1e21ad2d73bb7b7",
|
| 56 |
+
"sha256": "ba0ce20aae489ad196733da5064bcdf159a1fe84f53336648196e1ebb7751b1c"
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"name": "model-00002-of-00018.safetensors",
|
| 60 |
+
"size": 3043080328,
|
| 61 |
+
"blob_id": "81cf43545884a227a01351942dfbc72577812316",
|
| 62 |
+
"sha256": "06a148c01bfbe3faa14a5f184a7ff29a706f7ae1c8b2705d2058e26d17a001fb"
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"name": "model-00003-of-00018.safetensors",
|
| 66 |
+
"size": 2542796952,
|
| 67 |
+
"blob_id": "a2da5e6cd6307a6cae13d04820ab0d31b47b48bd",
|
| 68 |
+
"sha256": "2e1bf62cbcd406eaa64b60d10353e1f0ef4039d0976e56f05cabe953454f9968"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"name": "model-00004-of-00018.safetensors",
|
| 72 |
+
"size": 3988973152,
|
| 73 |
+
"blob_id": "175ddab3f2488ad181f73d789d2d778cf6d4fca6",
|
| 74 |
+
"sha256": "511e34063187882659753c4d93f3859f93c019fd438d8813071921c81d9a3f1a"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"name": "model-00005-of-00018.safetensors",
|
| 78 |
+
"size": 2099339864,
|
| 79 |
+
"blob_id": "64890208fdd563c3aac0c2f55f69948bcaa1a492",
|
| 80 |
+
"sha256": "635cb53446dc74f219740fc59e18b774f877b803b9722e289ca62575a6efa701"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"name": "model-00006-of-00018.safetensors",
|
| 84 |
+
"size": 3979553696,
|
| 85 |
+
"blob_id": "3ae29b86e4c773babfe17124dbd10d54d37819ec",
|
| 86 |
+
"sha256": "0bc5214fac607f0e6cc92eec3789d4b8559410ef9fce66621ba8158e8410dae0"
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"name": "model-00007-of-00018.safetensors",
|
| 90 |
+
"size": 2108759344,
|
| 91 |
+
"blob_id": "b7e9c0f038884839f3dad38fef7e75ee3362c24f",
|
| 92 |
+
"sha256": "80b0c49033e9a0d5762562aa12f4acdb7f54da586f3d0110f28c48d91cf07892"
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"name": "model-00008-of-00018.safetensors",
|
| 96 |
+
"size": 3979553696,
|
| 97 |
+
"blob_id": "0b58cbc52714e1c683711be87e7c2e33fb10e7a0",
|
| 98 |
+
"sha256": "7192c5b66185d3592927daabee1cc19e6f6e0ce75988ee20e824b624765fda79"
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"name": "model-00009-of-00018.safetensors",
|
| 102 |
+
"size": 2108759344,
|
| 103 |
+
"blob_id": "4fc0c6b28004d809225d0e115f30e9e11c2345dc",
|
| 104 |
+
"sha256": "af3c48cc37af44f3db6ae0579baf019180d48d9c527caa0a1f03ff85813a56d8"
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"name": "model-00010-of-00018.safetensors",
|
| 108 |
+
"size": 3979553696,
|
| 109 |
+
"blob_id": "9ec693a17c788084116c51b4f34632670df77612",
|
| 110 |
+
"sha256": "163490a76f3bea3a40855b7efc04ce6d27afaf1a34f0bbde495b9491f76457c9"
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"name": "model-00011-of-00018.safetensors",
|
| 114 |
+
"size": 2108759344,
|
| 115 |
+
"blob_id": "3c63baaed16d833432a919647af53ac76bb6b007",
|
| 116 |
+
"sha256": "5f3ae1b948aeee39da77aec558e8236cd65fe4d7cb7686a76bb007acc563c6d8"
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"name": "model-00012-of-00018.safetensors",
|
| 120 |
+
"size": 3979553696,
|
| 121 |
+
"blob_id": "8568b440a4666ed1b4cda0b5d21496378304f326",
|
| 122 |
+
"sha256": "a3de1c7114677a8f5ac5c4892c90e8238ea5c1e2038c80e757dfc87c3902ca55"
|
| 123 |
+
},
|
| 124 |
+
{
|
| 125 |
+
"name": "model-00013-of-00018.safetensors",
|
| 126 |
+
"size": 2108759344,
|
| 127 |
+
"blob_id": "724083995a2257194321a3d00b36fd7d4bb7348d",
|
| 128 |
+
"sha256": "06ab79a41f74c9c5cb734816feb0c7fc364104b227165ee7391231e1155aa02a"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"name": "model-00014-of-00018.safetensors",
|
| 132 |
+
"size": 3979553696,
|
| 133 |
+
"blob_id": "a60b80b6510d7938d951fbddc76aaadd121c6268",
|
| 134 |
+
"sha256": "4138ed94603065ba884bbcadedb04d7718bb40117e85e6f5c6fc5b9c05b7a85b"
|
| 135 |
+
},
|
| 136 |
+
{
|
| 137 |
+
"name": "model-00015-of-00018.safetensors",
|
| 138 |
+
"size": 2108759344,
|
| 139 |
+
"blob_id": "7d4c34f3d716e1a47acff2f576b65b41a3ec4f3f",
|
| 140 |
+
"sha256": "69224e27b9de4e7dbf6fc936c6eaae08447bda3b80a6c31a871ab451173afd22"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"name": "model-00016-of-00018.safetensors",
|
| 144 |
+
"size": 3979564040,
|
| 145 |
+
"blob_id": "c67e3e42c9715298fa7f68c6b378bfb1d74290d0",
|
| 146 |
+
"sha256": "73cb9a1089fb6155cb648609478d6633be8a5c7d9ca5a05bc8925ce8a553cefe"
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"name": "model-00017-of-00018.safetensors",
|
| 150 |
+
"size": 2108759344,
|
| 151 |
+
"blob_id": "23dd899179729a4370c655e2c2241cfdbe4ef4ba",
|
| 152 |
+
"sha256": "beb51f01056142ac4984bd800507b0dd0fd18de57f8e9ef6ea41d1a3598983a8"
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"name": "model-00018-of-00018.safetensors",
|
| 156 |
+
"size": 3392197344,
|
| 157 |
+
"blob_id": "a92b4073fc6a58ffc9334ac63360fc8d9cc50d33",
|
| 158 |
+
"sha256": "1d3479509e21494658f9b64d317f5ea8e55c4025d28c702d6c4d0b356ce8ea06"
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"name": "model.safetensors.index.json",
|
| 162 |
+
"size": 112216,
|
| 163 |
+
"blob_id": "da35e3c564457dface7d138f0b6cac284ff8958c",
|
| 164 |
+
"sha256": null
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"name": "preprocessor_config.json",
|
| 168 |
+
"size": 390,
|
| 169 |
+
"blob_id": "2ea84a437d448ff71b08df68fdd949d5cc4ebb64",
|
| 170 |
+
"sha256": null
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"name": "tokenizer.json",
|
| 174 |
+
"size": 12809320,
|
| 175 |
+
"blob_id": "9328ce9c41e80f6dd7bc2c66d8ae1fc93bf87440",
|
| 176 |
+
"sha256": "0997f410c57a1f4e53b09e4be8f4a172d90edd9564368fb0847030937229b9f3"
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"name": "tokenizer_config.json",
|
| 180 |
+
"size": 17928,
|
| 181 |
+
"blob_id": "5de744b3fca2129d7186979ae47c06be33903243",
|
| 182 |
+
"sha256": null
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"name": "video_preprocessor_config.json",
|
| 186 |
+
"size": 385,
|
| 187 |
+
"blob_id": "3ba673a5ad7d4d13f54155ecd38b2a94a6dac8fe",
|
| 188 |
+
"sha256": null
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"name": "vocab.json",
|
| 192 |
+
"size": 6722759,
|
| 193 |
+
"blob_id": "0aa0ce0658d60ac4a5d609f4eadb0e8e43514176",
|
| 194 |
+
"sha256": null
|
| 195 |
+
}
|
| 196 |
+
]
|
| 197 |
+
}
|
mlx/bf16/binding.json
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"adapter_dtype": "float32",
|
| 3 |
+
"adapter_placement": "question",
|
| 4 |
+
"adapter_scale": 2.0,
|
| 5 |
+
"base_hashes": {
|
| 6 |
+
".gitattributes": "34448b82c17d60fec9b65b1f093c115ddbaadc04beb1b0140b6bfed2e012a930",
|
| 7 |
+
"LICENSE": "bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a",
|
| 8 |
+
"README.md": "57e4bdb258ee1a7d2635c5174ebd4e56abe392505cdb5f8bbb356b0dc4293641",
|
| 9 |
+
"chat_template.jinja": "c3cf9e34abf4f9e36c2d72165aa9c132d3e2a725b6c2586aaa3a8af9d7a81041",
|
| 10 |
+
"config.json": "191e0af232104ed8b65258cf3fb2b842e288008baca7633c11b82a1ac7203aab",
|
| 11 |
+
"crc32.txt": "b42dd291f5f98b05807e458f5b47849969a9b3326acbf0c97d28b05826740b83",
|
| 12 |
+
"generation_config.json": "e70c136c1b78ddc1fb0905bac8e733a4dc448d4f852a5dd75143fffc70be550e",
|
| 13 |
+
"merges.txt": "a9d356d7bdf1ef4949e3e748e95b8e10ad9d4e2e838eddc38a0a7b6b94d1db8d",
|
| 14 |
+
"model-00001-of-00018.safetensors": "ba0ce20aae489ad196733da5064bcdf159a1fe84f53336648196e1ebb7751b1c",
|
| 15 |
+
"model-00002-of-00018.safetensors": "06a148c01bfbe3faa14a5f184a7ff29a706f7ae1c8b2705d2058e26d17a001fb",
|
| 16 |
+
"model-00003-of-00018.safetensors": "2e1bf62cbcd406eaa64b60d10353e1f0ef4039d0976e56f05cabe953454f9968",
|
| 17 |
+
"model-00004-of-00018.safetensors": "511e34063187882659753c4d93f3859f93c019fd438d8813071921c81d9a3f1a",
|
| 18 |
+
"model-00005-of-00018.safetensors": "635cb53446dc74f219740fc59e18b774f877b803b9722e289ca62575a6efa701",
|
| 19 |
+
"model-00006-of-00018.safetensors": "0bc5214fac607f0e6cc92eec3789d4b8559410ef9fce66621ba8158e8410dae0",
|
| 20 |
+
"model-00007-of-00018.safetensors": "80b0c49033e9a0d5762562aa12f4acdb7f54da586f3d0110f28c48d91cf07892",
|
| 21 |
+
"model-00008-of-00018.safetensors": "7192c5b66185d3592927daabee1cc19e6f6e0ce75988ee20e824b624765fda79",
|
| 22 |
+
"model-00009-of-00018.safetensors": "af3c48cc37af44f3db6ae0579baf019180d48d9c527caa0a1f03ff85813a56d8",
|
| 23 |
+
"model-00010-of-00018.safetensors": "163490a76f3bea3a40855b7efc04ce6d27afaf1a34f0bbde495b9491f76457c9",
|
| 24 |
+
"model-00011-of-00018.safetensors": "5f3ae1b948aeee39da77aec558e8236cd65fe4d7cb7686a76bb007acc563c6d8",
|
| 25 |
+
"model-00012-of-00018.safetensors": "a3de1c7114677a8f5ac5c4892c90e8238ea5c1e2038c80e757dfc87c3902ca55",
|
| 26 |
+
"model-00013-of-00018.safetensors": "06ab79a41f74c9c5cb734816feb0c7fc364104b227165ee7391231e1155aa02a",
|
| 27 |
+
"model-00014-of-00018.safetensors": "4138ed94603065ba884bbcadedb04d7718bb40117e85e6f5c6fc5b9c05b7a85b",
|
| 28 |
+
"model-00015-of-00018.safetensors": "69224e27b9de4e7dbf6fc936c6eaae08447bda3b80a6c31a871ab451173afd22",
|
| 29 |
+
"model-00016-of-00018.safetensors": "73cb9a1089fb6155cb648609478d6633be8a5c7d9ca5a05bc8925ce8a553cefe",
|
| 30 |
+
"model-00017-of-00018.safetensors": "beb51f01056142ac4984bd800507b0dd0fd18de57f8e9ef6ea41d1a3598983a8",
|
| 31 |
+
"model-00018-of-00018.safetensors": "1d3479509e21494658f9b64d317f5ea8e55c4025d28c702d6c4d0b356ce8ea06",
|
| 32 |
+
"model.safetensors.index.json": "77042094076611b69791a610065f28b7013b8c621795fa86ddccc8bac7d1b9df",
|
| 33 |
+
"preprocessor_config.json": "27225450ac9c6529872ee1924fcb0962ff5634834f817040f444118116f4e516",
|
| 34 |
+
"tokenizer.json": "0997f410c57a1f4e53b09e4be8f4a172d90edd9564368fb0847030937229b9f3",
|
| 35 |
+
"tokenizer_config.json": "b11349aafa7cdc6a320767cf7ceb29ed82f7eda5d65e8e0819e76f0ce947bf27",
|
| 36 |
+
"video_preprocessor_config.json": "7768af27c1fafa9cc9011c1dc20067e03f8915e03b63504550e11d5066986d13",
|
| 37 |
+
"vocab.json": "ce99b4cb2983d118806ce0a8b777a35b093e2000a503ebde25853284c9dfa003"
|
| 38 |
+
},
|
| 39 |
+
"base_revision": "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0",
|
| 40 |
+
"conversion": "upstream Qwen3.5 sanitization, norms promoted before unit offset",
|
| 41 |
+
"dependencies": {
|
| 42 |
+
"mlx": "0.32.2",
|
| 43 |
+
"mlx-vlm": "0.7.1",
|
| 44 |
+
"numpy": "2.5.3",
|
| 45 |
+
"transformers": "5.17.0"
|
| 46 |
+
},
|
| 47 |
+
"dtype": "bfloat16",
|
| 48 |
+
"files": {
|
| 49 |
+
"LICENSE": "a61385b8bc4e786195136404b4975fede3c0bca526877f526482e9af93d47457",
|
| 50 |
+
"MODIFICATIONS.md": "218218b43b27132a6cfa032d2be908decd0966f5b655946a8668506731c77de7",
|
| 51 |
+
"NOTICE": "ccf2b8e98f0606945a5fcf9f6522c1f2c01b279d55dc21ee02c5a4acadf8e8d1",
|
| 52 |
+
"adapter.safetensors": "2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca",
|
| 53 |
+
"backbone/.gitattributes": "34448b82c17d60fec9b65b1f093c115ddbaadc04beb1b0140b6bfed2e012a930",
|
| 54 |
+
"backbone/LICENSE": "bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a",
|
| 55 |
+
"backbone/README.md": "57e4bdb258ee1a7d2635c5174ebd4e56abe392505cdb5f8bbb356b0dc4293641",
|
| 56 |
+
"backbone/chat_template.jinja": "c3cf9e34abf4f9e36c2d72165aa9c132d3e2a725b6c2586aaa3a8af9d7a81041",
|
| 57 |
+
"backbone/config.json": "191e0af232104ed8b65258cf3fb2b842e288008baca7633c11b82a1ac7203aab",
|
| 58 |
+
"backbone/crc32.txt": "b42dd291f5f98b05807e458f5b47849969a9b3326acbf0c97d28b05826740b83",
|
| 59 |
+
"backbone/generation_config.json": "e70c136c1b78ddc1fb0905bac8e733a4dc448d4f852a5dd75143fffc70be550e",
|
| 60 |
+
"backbone/merges.txt": "a9d356d7bdf1ef4949e3e748e95b8e10ad9d4e2e838eddc38a0a7b6b94d1db8d",
|
| 61 |
+
"backbone/model-00001-of-00018.safetensors": "6c54d794f08d8a479e8a123b6ab3473b8a8f304f0da59b043aabe7bdb5f05a7a",
|
| 62 |
+
"backbone/model-00002-of-00018.safetensors": "3de19e7456388362e7dbe1455362f6b2661d8d7084a7a346e7d3f77053ff0f78",
|
| 63 |
+
"backbone/model-00003-of-00018.safetensors": "103e7f75798c312e696d2547889732b110a634725f6233b7b0bc654bf3365528",
|
| 64 |
+
"backbone/model-00004-of-00018.safetensors": "9b6ff88af2b387c943366b263d1ebef06090cf2a94e637895a74eb10300bf5da",
|
| 65 |
+
"backbone/model-00005-of-00018.safetensors": "f2e95aa5371257fadde49c6d735b716aab00868ae689befd54c091df7a6c57b4",
|
| 66 |
+
"backbone/model-00006-of-00018.safetensors": "7c196564fbb98f683573ae02d3a90bd74ccb7289d9103f09c76d9feffcc64b24",
|
| 67 |
+
"backbone/model-00007-of-00018.safetensors": "1a657de97643d5283547047925453e0bbec151b5f293f0a48ee8fbffb82c83cb",
|
| 68 |
+
"backbone/model-00008-of-00018.safetensors": "e26030a4ee68739f4092696d685b9ef5b4a7052f4843e949cf4419ee7d086b81",
|
| 69 |
+
"backbone/model-00009-of-00018.safetensors": "d73885d7e8995d58cd722b6fd4976035f30e3464189a71d88bb8e504a4612c53",
|
| 70 |
+
"backbone/model-00010-of-00018.safetensors": "ee367c91f6faf3a2d5245e28ee20dbe4e51a1ab08f8e27029c67e7c47a77bd89",
|
| 71 |
+
"backbone/model-00011-of-00018.safetensors": "01ea6406c8ee3f3bd0cbe96fb1ff120bdafc20bdeb4eb5dc8fc08894fef9221f",
|
| 72 |
+
"backbone/model-00012-of-00018.safetensors": "59da9b95e4d818c1189f681044df6bb9a5c7375ea0a01b8d6a6a682451fc4a8e",
|
| 73 |
+
"backbone/model-00013-of-00018.safetensors": "c2f63ec1a168d0f328da8ef74caee72d4e67d6dccfd9ccb595abcaedaeae86c4",
|
| 74 |
+
"backbone/model-00014-of-00018.safetensors": "d8a6453ec4fbe9763644dd9127c3a5ad5fec5c8a5cde6f1414f1101ee9a1250c",
|
| 75 |
+
"backbone/model-00015-of-00018.safetensors": "95db368ab83b8f60d1b9205de6ffa97adbe665d7e61e9adcfb237d25dabf9f8a",
|
| 76 |
+
"backbone/model-00016-of-00018.safetensors": "482d3d948c8cb31068323a85b7c2d445271a28a08699bbed48c13e465894715a",
|
| 77 |
+
"backbone/model-00017-of-00018.safetensors": "7615db84bee928608723f0e5e887f98e11091ccd86583453efcf9745050741f2",
|
| 78 |
+
"backbone/model-00018-of-00018.safetensors": "1219c9ea7951f2bb93c0ccafa2e6e65ac9111fda00961e3fbe614e30050c95e9",
|
| 79 |
+
"backbone/model.safetensors.index.json": "5aec933c5ef08d6c1d411b1b1f225b97d7c55f8eeed4b74535849ce9361e595f",
|
| 80 |
+
"backbone/preprocessor_config.json": "27225450ac9c6529872ee1924fcb0962ff5634834f817040f444118116f4e516",
|
| 81 |
+
"backbone/tokenizer.json": "0997f410c57a1f4e53b09e4be8f4a172d90edd9564368fb0847030937229b9f3",
|
| 82 |
+
"backbone/tokenizer_config.json": "b11349aafa7cdc6a320767cf7ceb29ed82f7eda5d65e8e0819e76f0ce947bf27",
|
| 83 |
+
"backbone/video_preprocessor_config.json": "7768af27c1fafa9cc9011c1dc20067e03f8915e03b63504550e11d5066986d13",
|
| 84 |
+
"backbone/vocab.json": "ce99b4cb2983d118806ce0a8b777a35b093e2000a503ebde25853284c9dfa003",
|
| 85 |
+
"heads.npz": "126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f"
|
| 86 |
+
},
|
| 87 |
+
"head_dtype": "float32",
|
| 88 |
+
"profile": "quality",
|
| 89 |
+
"quantization": null,
|
| 90 |
+
"recurrent_state_dtype": "float32",
|
| 91 |
+
"schema": "solomon-mlx-binding-v1",
|
| 92 |
+
"sensitive_parameters": "FP32 normalization weights, A_log and dt_bias",
|
| 93 |
+
"solomon_revision": "2ec506902269e4636285c8811f6c0f52c9300c0c",
|
| 94 |
+
"source_hashes": {
|
| 95 |
+
".gitattributes": "8baff4be52225e26dd13dffb05fed3d0db821911c36d7ffd6f6d00d02ca421c7",
|
| 96 |
+
"LICENSE": "a61385b8bc4e786195136404b4975fede3c0bca526877f526482e9af93d47457",
|
| 97 |
+
"MANIFEST.json": "a473433af0c2de6a97a0d99e9e47216e91ed67c4269e07ca8d678d8c068c317b",
|
| 98 |
+
"MODIFICATIONS.md": "218218b43b27132a6cfa032d2be908decd0966f5b655946a8668506731c77de7",
|
| 99 |
+
"NOTICE": "ccf2b8e98f0606945a5fcf9f6522c1f2c01b279d55dc21ee02c5a4acadf8e8d1",
|
| 100 |
+
"PUSH.md": "cc8e0ea0a0dec3db020f8245eb90b04571b77d8ac9f3efcd64d0ab0bef5bac16",
|
| 101 |
+
"README.md": "51a2389ef504652f0b0a292cfaf28bb5e7635bde1aede0289f42696ad5818afc",
|
| 102 |
+
"adapter/adapter.safetensors": "2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca",
|
| 103 |
+
"adapter/config.json": "cafc99ce8299eeca3fc2b2e1a2b08dcf659b66467d6675b6f8731a616693dbc4",
|
| 104 |
+
"adapter/heads.npz": "126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f",
|
| 105 |
+
"licenses/Qwen-Apache-2.0.txt": "bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a",
|
| 106 |
+
"requirements.lock": "27675e999e5bcfc175ed768711856a975c2286d2ba807471cc7b0213d6d13f89",
|
| 107 |
+
"serving/scope9-readout-temperature-v2.json": "baa7263ca9e865dda230617563e6a615de5050adc620c28924dffef68d527118",
|
| 108 |
+
"serving/selection.json": "14fa9c88a913d61a60d13b65f0974cff3985f40d50f204a1b83a9426db21b362",
|
| 109 |
+
"serving/service-export.json": "ccd7c0ca37cd900912631ab98b72703a4a4aebf2fadd6208675781aabd1e5ac8",
|
| 110 |
+
"serving/serving-binding.json": "1849df4bd4897d048a45a2f4cbc63beac4ded6afc0d43ff41e53a8a6dc8c49e4",
|
| 111 |
+
"src/scope35/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
| 112 |
+
"src/scope35/engine.py": "61f91be0dabc680795e5d4b83f9d80f02cbed2502b06e3809fdc09fbeeb99202",
|
| 113 |
+
"src/scope4/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
| 114 |
+
"src/scope4/cuda_engine.py": "f41dd19a248193bbda6aa81705317c702e0ec07976c7520a513b14260edddbf2",
|
| 115 |
+
"src/scope4/cuda_engine_v2.py": "d536117abd403811bba62129c2ba30d2e890c9058741baff65f3e7414f829bce",
|
| 116 |
+
"src/scope4/cuda_service.py": "c1c2267401b88dc5d4ad3d18b08c547c9b2e5d0a01c922d8ba88a1756075315a",
|
| 117 |
+
"src/scope4/engine.py": "b1ef3525011a8ec66c308f461e525d73a0a2b927bbfa605c76bef960d25fb5ff",
|
| 118 |
+
"src/scope4/readout.py": "cafcadbfc6ab3e77eac7bcd092d2254049c987913e2f744318ae7e2f36c24587",
|
| 119 |
+
"src/scope4/service.py": "2dfbfbadf92bce3f001063f9d94e5bf19a8d0ff9d143dd68b20d5032dd2e5e73",
|
| 120 |
+
"src/scope5/__init__.py": "6c079cc4864d55e798e243a6cbdc6e2b3fd963ff31fd28cf9a8122819a8c65cf",
|
| 121 |
+
"src/scope5/cuda_engine.py": "2d7d64d7e01cccefdb7afd504b80c54443ca271d0bcd3cf352b6bfd99dc491e3",
|
| 122 |
+
"src/scope5/heads_runtime.py": "48c0c29c79a8b781cddf22034b9ffee3df9a8d61b8709b1dd808b8df47024fe7",
|
| 123 |
+
"src/scope5/heads_service.py": "5c775e26bcb2de1c32156ce0cc404d06de8fbedff6c67fcb5606ce3713b88342",
|
| 124 |
+
"src/scope5/routing.py": "0d88a7f0433dd448b81bd04c48044c98e453038d9ffcd903c9479c20ec6651c1",
|
| 125 |
+
"src/scope5/service.py": "d056ae3e4ebda5d89ba4ebe0c93ae225a31e33a8f543632a0976703c25501019",
|
| 126 |
+
"src/scope6/__init__.py": "e72ad8e334509eb002496207c4e43598d222ba2953162344e43ee122e3832df0",
|
| 127 |
+
"src/scope6/evidence.py": "a0ece458b5c0546c1f80b48cea87ebc1c3732e83f2c0f8e58969645bc8bde2f7",
|
| 128 |
+
"src/scope6/evidence_v3.py": "9b2b9e9c319242ca9c4a96a2567d1c1adb3134332c95dd6dfd60114c54d09426",
|
| 129 |
+
"src/scope6/retrieval.py": "4e5094aacc2ee3bbb0663de402198cd418933c4682f9d5a9006d4058e15f9b4f",
|
| 130 |
+
"src/scope6/runtime.py": "2d154d8ba39e61a10b23bba286e1ce87f57dbdc21d8f6e73430c0929a1990fe7",
|
| 131 |
+
"src/scope6/service.py": "5e7b6f9e163be35ab17ed76355ecee9faa541f27ca76e969ff49f2076dfbd9b8",
|
| 132 |
+
"src/scope6/service_v3.py": "b92cfdee8ca1c039645a97746e47fc99965f9c5f5ecd98e31aedf71bca29b611",
|
| 133 |
+
"src/scope6/serving.py": "aab481eb4b1d34c13caaf8c3628f3702f2956bb413f288c7a30979d5c2281356",
|
| 134 |
+
"src/scope9/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
| 135 |
+
"src/scope9/api.py": "db677e569a3f7d15e6398d4bfb9ac0b00f286502fe4d97e9811388ccfb95dcae",
|
| 136 |
+
"src/scope9/live.py": "62f40568c8c0bc7ea4d436325eb54d49fe06ea8f51c304b384dcffb605bf3e3f",
|
| 137 |
+
"src/scope9/prompts.py": "53e22b99c19f5af588fea2167594c6331877a8ce71d0a0424bce10000bc22b53",
|
| 138 |
+
"src/scope9/semantics.py": "9fd9041c50f8925608bf6a2f351abab745648137400475bdf46f66885bef67dc",
|
| 139 |
+
"src/scope9/service.py": "9deed4e6acae4b26619a95f6f2ef19ced6bb42d6d6a4e1710c26accff4bc198b"
|
| 140 |
+
}
|
| 141 |
+
}
|
mlx/bf16/conversion.json
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run_id": "bf16-cpu-79517a5cd7aa",
|
| 3 |
+
"base_revision": "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0",
|
| 4 |
+
"solomon_revision": "2ec506902269e4636285c8811f6c0f52c9300c0c",
|
| 5 |
+
"backend": "mlx-linux-cpu",
|
| 6 |
+
"binding_sha256": "6d45715aa040fad98b061ff2cbafb35b047143ef2475646cee3df7a334f4d530",
|
| 7 |
+
"converter_code_sha256": "648e440cface0838f2dcc8d89b3ab172d97f4ffc1f88fe0b7cbbe3ca73b8a575",
|
| 8 |
+
"total_output_bytes": 55610774146,
|
| 9 |
+
"seconds": 220.91851106299998,
|
| 10 |
+
"apple_silicon_validation": "pending; conversion is not inference qualification",
|
| 11 |
+
"files": [
|
| 12 |
+
{
|
| 13 |
+
"name": "LICENSE",
|
| 14 |
+
"size": 11344,
|
| 15 |
+
"sha256": "a61385b8bc4e786195136404b4975fede3c0bca526877f526482e9af93d47457"
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"name": "MODIFICATIONS.md",
|
| 19 |
+
"size": 4197,
|
| 20 |
+
"sha256": "218218b43b27132a6cfa032d2be908decd0966f5b655946a8668506731c77de7"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"name": "NOTICE",
|
| 24 |
+
"size": 3891,
|
| 25 |
+
"sha256": "ccf2b8e98f0606945a5fcf9f6522c1f2c01b279d55dc21ee02c5a4acadf8e8d1"
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"name": "adapter.safetensors",
|
| 29 |
+
"size": 870363376,
|
| 30 |
+
"sha256": "2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca"
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"name": "backbone/.gitattributes",
|
| 34 |
+
"size": 1570,
|
| 35 |
+
"sha256": "34448b82c17d60fec9b65b1f093c115ddbaadc04beb1b0140b6bfed2e012a930"
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"name": "backbone/LICENSE",
|
| 39 |
+
"size": 11544,
|
| 40 |
+
"sha256": "bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"name": "backbone/README.md",
|
| 44 |
+
"size": 65012,
|
| 45 |
+
"sha256": "57e4bdb258ee1a7d2635c5174ebd4e56abe392505cdb5f8bbb356b0dc4293641"
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"name": "backbone/chat_template.jinja",
|
| 49 |
+
"size": 8952,
|
| 50 |
+
"sha256": "c3cf9e34abf4f9e36c2d72165aa9c132d3e2a725b6c2586aaa3a8af9d7a81041"
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"name": "backbone/config.json",
|
| 54 |
+
"size": 4312,
|
| 55 |
+
"sha256": "191e0af232104ed8b65258cf3fb2b842e288008baca7633c11b82a1ac7203aab"
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"name": "backbone/crc32.txt",
|
| 59 |
+
"size": 238,
|
| 60 |
+
"sha256": "b42dd291f5f98b05807e458f5b47849969a9b3326acbf0c97d28b05826740b83"
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"name": "backbone/generation_config.json",
|
| 64 |
+
"size": 202,
|
| 65 |
+
"sha256": "e70c136c1b78ddc1fb0905bac8e733a4dc448d4f852a5dd75143fffc70be550e"
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"name": "backbone/merges.txt",
|
| 69 |
+
"size": 3353259,
|
| 70 |
+
"sha256": "a9d356d7bdf1ef4949e3e748e95b8e10ad9d4e2e838eddc38a0a7b6b94d1db8d"
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"name": "backbone/model-00001-of-00018.safetensors",
|
| 74 |
+
"size": 3967078356,
|
| 75 |
+
"sha256": "6c54d794f08d8a479e8a123b6ab3473b8a8f304f0da59b043aabe7bdb5f05a7a"
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"name": "backbone/model-00002-of-00018.safetensors",
|
| 79 |
+
"size": 3043154160,
|
| 80 |
+
"sha256": "3de19e7456388362e7dbe1455362f6b2661d8d7084a7a346e7d3f77053ff0f78"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"name": "backbone/model-00003-of-00018.safetensors",
|
| 84 |
+
"size": 2542796953,
|
| 85 |
+
"sha256": "103e7f75798c312e696d2547889732b110a634725f6233b7b0bc654bf3365528"
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"name": "backbone/model-00004-of-00018.safetensors",
|
| 89 |
+
"size": 3989088609,
|
| 90 |
+
"sha256": "9b6ff88af2b387c943366b263d1ebef06090cf2a94e637895a74eb10300bf5da"
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"name": "backbone/model-00005-of-00018.safetensors",
|
| 94 |
+
"size": 2099392965,
|
| 95 |
+
"sha256": "f2e95aa5371257fadde49c6d735b716aab00868ae689befd54c091df7a6c57b4"
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"name": "backbone/model-00006-of-00018.safetensors",
|
| 99 |
+
"size": 3979669611,
|
| 100 |
+
"sha256": "7c196564fbb98f683573ae02d3a90bd74ccb7289d9103f09c76d9feffcc64b24"
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"name": "backbone/model-00007-of-00018.safetensors",
|
| 104 |
+
"size": 2108811989,
|
| 105 |
+
"sha256": "1a657de97643d5283547047925453e0bbec151b5f293f0a48ee8fbffb82c83cb"
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"name": "backbone/model-00008-of-00018.safetensors",
|
| 109 |
+
"size": 3979669575,
|
| 110 |
+
"sha256": "e26030a4ee68739f4092696d685b9ef5b4a7052f4843e949cf4419ee7d086b81"
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"name": "backbone/model-00009-of-00018.safetensors",
|
| 114 |
+
"size": 2108812007,
|
| 115 |
+
"sha256": "d73885d7e8995d58cd722b6fd4976035f30e3464189a71d88bb8e504a4612c53"
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"name": "backbone/model-00010-of-00018.safetensors",
|
| 119 |
+
"size": 3979669601,
|
| 120 |
+
"sha256": "ee367c91f6faf3a2d5245e28ee20dbe4e51a1ab08f8e27029c67e7c47a77bd89"
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"name": "backbone/model-00011-of-00018.safetensors",
|
| 124 |
+
"size": 2108812003,
|
| 125 |
+
"sha256": "01ea6406c8ee3f3bd0cbe96fb1ff120bdafc20bdeb4eb5dc8fc08894fef9221f"
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"name": "backbone/model-00012-of-00018.safetensors",
|
| 129 |
+
"size": 3979669597,
|
| 130 |
+
"sha256": "59da9b95e4d818c1189f681044df6bb9a5c7375ea0a01b8d6a6a682451fc4a8e"
|
| 131 |
+
},
|
| 132 |
+
{
|
| 133 |
+
"name": "backbone/model-00013-of-00018.safetensors",
|
| 134 |
+
"size": 2108811987,
|
| 135 |
+
"sha256": "c2f63ec1a168d0f328da8ef74caee72d4e67d6dccfd9ccb595abcaedaeae86c4"
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"name": "backbone/model-00014-of-00018.safetensors",
|
| 139 |
+
"size": 3979669605,
|
| 140 |
+
"sha256": "d8a6453ec4fbe9763644dd9127c3a5ad5fec5c8a5cde6f1414f1101ee9a1250c"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"name": "backbone/model-00015-of-00018.safetensors",
|
| 144 |
+
"size": 2108812005,
|
| 145 |
+
"sha256": "95db368ab83b8f60d1b9205de6ffa97adbe665d7e61e9adcfb237d25dabf9f8a"
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"name": "backbone/model-00016-of-00018.safetensors",
|
| 149 |
+
"size": 3979690166,
|
| 150 |
+
"sha256": "482d3d948c8cb31068323a85b7c2d445271a28a08699bbed48c13e465894715a"
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"name": "backbone/model-00017-of-00018.safetensors",
|
| 154 |
+
"size": 2108812005,
|
| 155 |
+
"sha256": "7615db84bee928608723f0e5e887f98e11091ccd86583453efcf9745050741f2"
|
| 156 |
+
},
|
| 157 |
+
{
|
| 158 |
+
"name": "backbone/model-00018-of-00018.safetensors",
|
| 159 |
+
"size": 2542796942,
|
| 160 |
+
"sha256": "1219c9ea7951f2bb93c0ccafa2e6e65ac9111fda00961e3fbe614e30050c95e9"
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"name": "backbone/model.safetensors.index.json",
|
| 164 |
+
"size": 111087,
|
| 165 |
+
"sha256": "5aec933c5ef08d6c1d411b1b1f225b97d7c55f8eeed4b74535849ce9361e595f"
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
"name": "backbone/preprocessor_config.json",
|
| 169 |
+
"size": 390,
|
| 170 |
+
"sha256": "27225450ac9c6529872ee1924fcb0962ff5634834f817040f444118116f4e516"
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"name": "backbone/tokenizer.json",
|
| 174 |
+
"size": 12809320,
|
| 175 |
+
"sha256": "0997f410c57a1f4e53b09e4be8f4a172d90edd9564368fb0847030937229b9f3"
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"name": "backbone/tokenizer_config.json",
|
| 179 |
+
"size": 17928,
|
| 180 |
+
"sha256": "b11349aafa7cdc6a320767cf7ceb29ed82f7eda5d65e8e0819e76f0ce947bf27"
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"name": "backbone/video_preprocessor_config.json",
|
| 184 |
+
"size": 385,
|
| 185 |
+
"sha256": "7768af27c1fafa9cc9011c1dc20067e03f8915e03b63504550e11d5066986d13"
|
| 186 |
+
},
|
| 187 |
+
{
|
| 188 |
+
"name": "backbone/vocab.json",
|
| 189 |
+
"size": 6722759,
|
| 190 |
+
"sha256": "ce99b4cb2983d118806ce0a8b777a35b093e2000a503ebde25853284c9dfa003"
|
| 191 |
+
},
|
| 192 |
+
{
|
| 193 |
+
"name": "heads.npz",
|
| 194 |
+
"size": 2053938,
|
| 195 |
+
"sha256": "126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f"
|
| 196 |
+
},
|
| 197 |
+
{
|
| 198 |
+
"name": "binding.json",
|
| 199 |
+
"size": 12306,
|
| 200 |
+
"sha256": "6d45715aa040fad98b061ff2cbafb35b047143ef2475646cee3df7a334f4d530"
|
| 201 |
+
}
|
| 202 |
+
]
|
| 203 |
+
}
|
mlx/docs/UPSTREAM-MODIFICATIONS.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Statement of changes
|
| 2 |
+
|
| 3 |
+
Apache License 2.0, section 4(b): prominent notice that files carry modifications.
|
| 4 |
+
|
| 5 |
+
## What is modified
|
| 6 |
+
|
| 7 |
+
**No upstream source file is modified.** No file from `Qwen/Qwen3.8-27B` is edited,
|
| 8 |
+
renamed, patched or redistributed in this repository, with one exception: the
|
| 9 |
+
upstream licence text is reproduced byte-for-byte at `licenses/Qwen-Apache-2.0.txt`
|
| 10 |
+
(sha256 `bbedc3fda3305820b977265f01b8619d87570a6739de3a5582c3464840f1e57a`) because section 4(a) requires it. That file is
|
| 11 |
+
unmodified and carries the upstream copyright.
|
| 12 |
+
|
| 13 |
+
The modification this work carries is not an edit to a source file. It is a set
|
| 14 |
+
of **trained parameters applied to the base model at inference time**, plus an
|
| 15 |
+
original serving layer that reads the model's logits. Concretely:
|
| 16 |
+
|
| 17 |
+
| Change | Artifact | sha256 |
|
| 18 |
+
|---|---|---|
|
| 19 |
+
| LoRA adapter, rank 64, question-side placement, float32 | `adapter/adapter.safetensors` | `2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca` |
|
| 20 |
+
| Trained linear answer heads | `adapter/heads.npz` | `126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f` |
|
| 21 |
+
| Readout calibration, one positive scalar per task | `serving/scope9-readout-temperature-v2.json` | file `baa7263ca9e865dda230617563e6a615de5050adc620c28924dffef68d527118` / payload `682d611ec53c3322905c7e265bf9b9b35a1cd581f6d8b7ea924df864a3d74278` |
|
| 22 |
+
| Runtime identity binding | `serving/serving-binding.json` | payload `95683c1f87ec3f71b7657669dc311918ff53b7d41a981eaa8d827047e72cb505` |
|
| 23 |
+
| Serving layer (original work, not derived from upstream code) | `src/` | see `MANIFEST.json` |
|
| 24 |
+
|
| 25 |
+
Base model, unmodified and not redistributed: `Qwen/Qwen3.8-27B` at revision
|
| 26 |
+
`1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0`, Copyright 2026 Alibaba Cloud, Apache-2.0.
|
| 27 |
+
|
| 28 |
+
Training took place between 16 and 20 September 2026. The shipped artifacts are
|
| 29 |
+
identified by the checksums in the table above and in `MANIFEST.json`.
|
| 30 |
+
|
| 31 |
+
## Which files carry a change notice
|
| 32 |
+
|
| 33 |
+
| File | Why |
|
| 34 |
+
|---|---|
|
| 35 |
+
| `NOTICE` | Section 4(b) and 4(c) statement, carried with every copy |
|
| 36 |
+
| `MODIFICATIONS.md` | this file |
|
| 37 |
+
| `README.md` | names the base model, the pinned revision and the derivative relationship in the front matter and in the body |
|
| 38 |
+
| `adapter/config.json` | machine-readable record of the base repo, the pinned revision and both weight checksums |
|
| 39 |
+
| `serving/serving-binding.json` | pins the exact runtime the weights were measured on and refuses to load against a different one |
|
| 40 |
+
|
| 41 |
+
No file under `src/` carries an upstream change notice, because no file under
|
| 42 |
+
`src/` contains upstream code. Every file there is original work, written for
|
| 43 |
+
this project, and is covered by the repository's own Apache-2.0 `LICENSE` and by
|
| 44 |
+
the copyright line in `NOTICE`.
|
| 45 |
+
|
| 46 |
+
All of the changes described above — the adapter, the heads, the calibration, the
|
| 47 |
+
serving binding and the serving layer — are Copyright 2026
|
| 48 |
+
Doccy Pty Ltd and licensed under Apache-2.0.
|
| 49 |
+
|
| 50 |
+
## Third-party text scan
|
| 51 |
+
|
| 52 |
+
Before release, **every file staged into this repository was scanned for text
|
| 53 |
+
originating in third-party source documents.** The scan compared normalised
|
| 54 |
+
6-gram and 8-gram shingles of every staged text file against:
|
| 55 |
+
|
| 56 |
+
1. the 42 third-party source records the training and evaluation panels were
|
| 57 |
+
built from (Apache-2.0, MIT, BSD-3-Clause, CC BY 4.0, CC BY-SA 4.0, CC0,
|
| 58 |
+
OGL v3.0 and US-government public-domain assertions); and
|
| 59 |
+
2. every generated panel and document corpus on disk.
|
| 60 |
+
|
| 61 |
+
**Result: no third-party document text is present in any shipped file.** The
|
| 62 |
+
only matches were:
|
| 63 |
+
|
| 64 |
+
* the reproduced Apache-2.0 licence text at `licenses/Qwen-Apache-2.0.txt`, which
|
| 65 |
+
matches an Apache-2.0 licence document held in the evaluation corpus and is
|
| 66 |
+
required to be here verbatim; and
|
| 67 |
+
* the phrase *"A missing fact is not a negative fact"*, which is **our own
|
| 68 |
+
prompt-template wording** appearing in our own evaluation panels, not
|
| 69 |
+
third-party text entering our prompts.
|
| 70 |
+
|
| 71 |
+
Acceptance fixtures are excluded from this repository entirely. The fixture
|
| 72 |
+
documents used in live acceptance are original synthetic text authored for this
|
| 73 |
+
project and held in tooling that is not distributed.
|
| 74 |
+
|
| 75 |
+
Re-run the scan with `ops/solomon_package.py --scan` in the source project.
|
mlx/docs/VALIDATION-20260921.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Solomon BF16 CUDA parity validation — 21 September 2026
|
| 2 |
+
|
| 3 |
+
Full BF16 inference was exercised on the Apple M5 Max / 128 GB Mac. No weights or temperatures were changed. New temperature fitting is out of scope.
|
| 4 |
+
|
| 5 |
+
## Confirmed results
|
| 6 |
+
|
| 7 |
+
| Check | Result |
|
| 8 |
+
|---|---|
|
| 9 |
+
| Fresh text fixtures, all five answer types | 22/22 decisions match CUDA |
|
| 10 |
+
| Fresh page-image fixtures | 4/4 decisions match CUDA |
|
| 11 |
+
| Saved text subset | 645/645 branch decisions and 327/327 whole-question decisions match CUDA |
|
| 12 |
+
| Prefix tokens and captured full token sequences | Exact match with CUDA |
|
| 13 |
+
| Replay and fresh process versus previous run | Zero logit drift on this Mac |
|
| 14 |
+
| Public API cache isolation, evidence and invalid-input checks | Passed |
|
| 15 |
+
| Existing package tests | 21 passed |
|
| 16 |
+
| Parity workflow and reserved-answer regression tests | 2 passed |
|
| 17 |
+
| Lint | Passed |
|
| 18 |
+
|
| 19 |
+
The saved subset covers 196 documents and all five tasks. It comes from previously scored calibration-fit inputs and is a diagnostic subset, not a complete held-out qualification. It was used only for comparison; nothing was fitted.
|
| 20 |
+
|
| 21 |
+
## Numerical differences
|
| 22 |
+
|
| 23 |
+
With the same frozen CUDA serving temperatures applied once on both backends, maximum probability drift on the saved subset is 2.5871 percentage points; mean drift is 0.0126 points. At identical T=1, maximum drift is 4.1508 points and mean drift is 0.0078 points. All compared decisions still agree.
|
| 24 |
+
|
| 25 |
+
CUDA and MLX logits are not bitwise equal. The report preserves the largest probability differences for inspection. No claim is made that the CUDA confidence calibration has been independently validated for MLX.
|
| 26 |
+
|
| 27 |
+
The focused runs used 59.90 GB peak Metal allocation. This is not a measurement of the maximum supported context or many-page memory use.
|
| 28 |
+
|
| 29 |
+
## Remaining work
|
| 30 |
+
|
| 31 |
+
The untouched certification panel is now scored directly: 1,200 documents / 21,718 branches. It skips fit/development scoring and temperature fitting. The complete agreement gate is at least 99.9% for both branches and whole questions, at T=1 and at the frozen CUDA temperatures. Probability drift and task accuracy are reported separately.
|
| 32 |
+
|
| 33 |
+
Image fixtures and API evidence checks are limited tests; broad image accuracy and CUDA evidence-selection equivalence are not established by them.
|
| 34 |
+
|
| 35 |
+
Runtime fingerprint: `33c9b63f036c5c039a2db4ba944f5b0042ae8b8e485e68c2aeddb57c407f8908`.
|
| 36 |
+
|
| 37 |
+
Detailed evaluation inputs and outputs remain private; the source release includes aggregate results only.
|
| 38 |
+
|
| 39 |
+
## Adapter-only packaging checks
|
| 40 |
+
|
| 41 |
+
The 21 September source update passed 24 portable package tests, including seven
|
| 42 |
+
Hub-loader tests. The local development suite passed 30 tests. The new verifier
|
| 43 |
+
also checked all 37 files of the existing full BF16 conversion. The built wheel
|
| 44 |
+
contains the original converter with its exact recorded source hash and both
|
| 45 |
+
pinned-input manifests. These checks cover packaging and integrity, not additional
|
| 46 |
+
trained-model parity.
|
mlx/examples/decide.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from solomon_mlx import Solomon
|
| 2 |
+
|
| 3 |
+
model = Solomon.load("models/quality")
|
| 4 |
+
questions = {
|
| 5 |
+
"certified": {"type": "noul", "instructions": "Is Rookwood Ltd certified?"},
|
| 6 |
+
"auditor": {
|
| 7 |
+
"type": "choice",
|
| 8 |
+
"instructions": "Who performs the audit?",
|
| 9 |
+
"options": ["The Buyer", "The grower", "An independent auditor"],
|
| 10 |
+
},
|
| 11 |
+
"severity": {
|
| 12 |
+
"type": "score",
|
| 13 |
+
"instructions": "What is the breach severity?",
|
| 14 |
+
"levels": ["none recorded", "minor", "material"],
|
| 15 |
+
},
|
| 16 |
+
}
|
| 17 |
+
with model.prefill(
|
| 18 |
+
"Rookwood Ltd is certified. An independent auditor performs the audit. One minor breach is recorded."
|
| 19 |
+
) as state:
|
| 20 |
+
print(model.decide(state=state, questions=questions, evidence="support"))
|
| 21 |
+
state.save("document-replay.json")
|
mlx/pyproject.toml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["hatchling==1.32.3"]
|
| 3 |
+
build-backend = "hatchling.build"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "solomon-mlx"
|
| 7 |
+
version = "0.1.0"
|
| 8 |
+
description = "Solomon v1.1 BF16 inference on Apple Silicon"
|
| 9 |
+
license = "Apache-2.0"
|
| 10 |
+
license-files = ["LICENSE", "NOTICE", "MODIFICATIONS.md", "docs/UPSTREAM-MODIFICATIONS.md"]
|
| 11 |
+
requires-python = ">=3.12,<3.14"
|
| 12 |
+
dependencies = ["mlx==0.32.2", "mlx-vlm==0.7.1", "transformers==5.17.0", "numpy==2.5.3", "pillow==12.3.0", "safetensors==0.8.0", "huggingface-hub==1.32.0", "scipy==1.18.1"]
|
| 13 |
+
|
| 14 |
+
[project.optional-dependencies]
|
| 15 |
+
dev = ["pytest==9.1.1", "ruff==0.16.8", "modal==1.5.5"]
|
| 16 |
+
cloud = [
|
| 17 |
+
"boto3==1.43.98",
|
| 18 |
+
"mlx[cpu]==0.32.2; sys_platform == 'linux'",
|
| 19 |
+
"modal==1.5.5",
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
[project.scripts]
|
| 23 |
+
solomon-mlx = "solomon_mlx.cli:main"
|
| 24 |
+
solomon-mlx-hub = "solomon_mlx_hub.__main__:main"
|
| 25 |
+
|
| 26 |
+
[tool.pytest.ini_options]
|
| 27 |
+
testpaths = ["tests"]
|
| 28 |
+
markers = ["model: requires the full pinned model"]
|
| 29 |
+
|
| 30 |
+
[tool.ruff]
|
| 31 |
+
line-length = 110
|
| 32 |
+
extend-exclude = ["src/solomon_mlx/_vendor", "snapshots", "models", "evaluations"]
|
| 33 |
+
|
| 34 |
+
[tool.hatch.build.targets.wheel]
|
| 35 |
+
packages = ["src/solomon_mlx", "src/solomon_mlx_hub"]
|
mlx/requirements.cloud.lock
ADDED
|
@@ -0,0 +1,1072 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file was autogenerated by uv via the following command:
|
| 2 |
+
# uv export --frozen --no-dev --extra cloud --no-emit-project --format requirements-txt --output-file requirements.cloud.lock
|
| 3 |
+
aiohappyeyeballs==2.7.1 \
|
| 4 |
+
--hash=sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d \
|
| 5 |
+
--hash=sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472
|
| 6 |
+
# via aiohttp
|
| 7 |
+
aiohttp==3.14.3 \
|
| 8 |
+
--hash=sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043 \
|
| 9 |
+
--hash=sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b \
|
| 10 |
+
--hash=sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf \
|
| 11 |
+
--hash=sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559 \
|
| 12 |
+
--hash=sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86 \
|
| 13 |
+
--hash=sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a \
|
| 14 |
+
--hash=sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c \
|
| 15 |
+
--hash=sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5 \
|
| 16 |
+
--hash=sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d \
|
| 17 |
+
--hash=sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71 \
|
| 18 |
+
--hash=sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1 \
|
| 19 |
+
--hash=sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427 \
|
| 20 |
+
--hash=sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42 \
|
| 21 |
+
--hash=sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd \
|
| 22 |
+
--hash=sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8 \
|
| 23 |
+
--hash=sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228 \
|
| 24 |
+
--hash=sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0 \
|
| 25 |
+
--hash=sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee \
|
| 26 |
+
--hash=sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f \
|
| 27 |
+
--hash=sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c \
|
| 28 |
+
--hash=sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371 \
|
| 29 |
+
--hash=sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0 \
|
| 30 |
+
--hash=sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529 \
|
| 31 |
+
--hash=sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc \
|
| 32 |
+
--hash=sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b \
|
| 33 |
+
--hash=sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80 \
|
| 34 |
+
--hash=sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e \
|
| 35 |
+
--hash=sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807 \
|
| 36 |
+
--hash=sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d \
|
| 37 |
+
--hash=sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82 \
|
| 38 |
+
--hash=sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19 \
|
| 39 |
+
--hash=sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0 \
|
| 40 |
+
--hash=sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5 \
|
| 41 |
+
--hash=sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4 \
|
| 42 |
+
--hash=sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2 \
|
| 43 |
+
--hash=sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9 \
|
| 44 |
+
--hash=sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883 \
|
| 45 |
+
--hash=sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde \
|
| 46 |
+
--hash=sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787 \
|
| 47 |
+
--hash=sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627 \
|
| 48 |
+
--hash=sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a \
|
| 49 |
+
--hash=sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24
|
| 50 |
+
# via modal
|
| 51 |
+
aiosignal==1.4.0 \
|
| 52 |
+
--hash=sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e \
|
| 53 |
+
--hash=sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7
|
| 54 |
+
# via aiohttp
|
| 55 |
+
annotated-doc==0.0.5 \
|
| 56 |
+
--hash=sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101 \
|
| 57 |
+
--hash=sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb
|
| 58 |
+
# via
|
| 59 |
+
# fastapi
|
| 60 |
+
# typer
|
| 61 |
+
annotated-types==0.8.0 \
|
| 62 |
+
--hash=sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7 \
|
| 63 |
+
--hash=sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0
|
| 64 |
+
# via pydantic
|
| 65 |
+
anyio==4.15.1 \
|
| 66 |
+
--hash=sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101 \
|
| 67 |
+
--hash=sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94
|
| 68 |
+
# via
|
| 69 |
+
# httpx
|
| 70 |
+
# starlette
|
| 71 |
+
# watchfiles
|
| 72 |
+
attrs==26.1.0 \
|
| 73 |
+
--hash=sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 \
|
| 74 |
+
--hash=sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32
|
| 75 |
+
# via aiohttp
|
| 76 |
+
boto3==1.43.98 \
|
| 77 |
+
--hash=sha256:1ec732e023fb29c12dc8520f925b5bbbed29eeb36b5764b5a5c26052d7c721f7 \
|
| 78 |
+
--hash=sha256:7454f666a9e852a56db0a7fa23be33a899f64e27828930eac43c3edba7b34e17
|
| 79 |
+
# via solomon-mlx
|
| 80 |
+
botocore==1.43.98 \
|
| 81 |
+
--hash=sha256:6135dd639ea6d1b3b49381bc253c8a139d61f7d44cb5f7dae8e7cd1791758572 \
|
| 82 |
+
--hash=sha256:84b35b10402c2fc0c265f634fbf86336eecc6489ee23f55074b329924b2cfd6f
|
| 83 |
+
# via
|
| 84 |
+
# boto3
|
| 85 |
+
# s3transfer
|
| 86 |
+
cbor2==6.1.4 \
|
| 87 |
+
--hash=sha256:01ecc79a28f33d17331943ce508fc1e21f4b06553c73f874f4c77120d72b2ef9 \
|
| 88 |
+
--hash=sha256:1fc15061553e4494dc10883237501e3402c645fe509248dd698e1faf2460d68b \
|
| 89 |
+
--hash=sha256:2310f07db3f9ba26f2a623774ff9f3dc7185af54f732ea119785a6b1bf7e1e7e \
|
| 90 |
+
--hash=sha256:310f3dfb296ba48fe9b63c5cf26e691e3548a1eae6901d2f0c18e941d151f220 \
|
| 91 |
+
--hash=sha256:32a4663425fbca4a4a7aa918eb5789d844c406439e58424cf34511f79f559242 \
|
| 92 |
+
--hash=sha256:36ae16d64b1f7b620c1af748e7b6947e20069ef80eee56871c5fbb84cc635905 \
|
| 93 |
+
--hash=sha256:4bd29f21529e279d50fc14f1a811f7b05b4d8e66a7969163cce98983b6817245 \
|
| 94 |
+
--hash=sha256:553a46bda7d09552631a714e22b91e6ff2c867ecd91511596ce290d8879b8d5b \
|
| 95 |
+
--hash=sha256:598710183daae69cbdeb177a870ec64aa601de8138a61491fd256826d15a860f \
|
| 96 |
+
--hash=sha256:5e6c76004d674ad1c620660cb0bc5a8a0b72a5d8c7b70926d8e09e6d7e87332f \
|
| 97 |
+
--hash=sha256:69978901302ecbc8cda57b520487c5c5240ed217de783eb7728fceb258311d76 \
|
| 98 |
+
--hash=sha256:ad4efa23fee6447e56a269191044e06eb39e809458bcd674e164fe9445feafd0 \
|
| 99 |
+
--hash=sha256:c08b9c7d2ea013e24a0cb819b872b0119dde404f64a1182c0b24095b7bba781f \
|
| 100 |
+
--hash=sha256:c48a7c938fc5fa5300ff82b5df09068dcb4838685ae8556b5ee8279d74f97ab4 \
|
| 101 |
+
--hash=sha256:cc8cd300e236e9797b2e1ce306109dc481fcccf78bfa2682bf36d99e6eab1ec6 \
|
| 102 |
+
--hash=sha256:d2560c2ba6a95904ba2a0ca257af878c4344409d9b46d8e646d8ebb617b1e0dd \
|
| 103 |
+
--hash=sha256:d9ada5a6ccfbb8ea7a3aa2aeb028421b52d8e0cd9323f0a2aeaa9c09d25fbce2
|
| 104 |
+
# via modal
|
| 105 |
+
certifi==2026.7.22 \
|
| 106 |
+
--hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \
|
| 107 |
+
--hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55
|
| 108 |
+
# via
|
| 109 |
+
# httpcore
|
| 110 |
+
# httpx
|
| 111 |
+
# modal
|
| 112 |
+
# requests
|
| 113 |
+
cffi==2.1.1 \
|
| 114 |
+
--hash=sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e \
|
| 115 |
+
--hash=sha256:19ee6127ee34de7d83ce3d371ebc5ed91addbdcc39f9ab15ce4eb35a4e534971 \
|
| 116 |
+
--hash=sha256:1aa5645c30469b09530c4ebca77ebf8f17618293c58f8549cb1a543a50236e7d \
|
| 117 |
+
--hash=sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517 \
|
| 118 |
+
--hash=sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735 \
|
| 119 |
+
--hash=sha256:31348097ff5bbe827ccc41795d4dd099d9f0625e7def00ee653c137a490c2a6c \
|
| 120 |
+
--hash=sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e \
|
| 121 |
+
--hash=sha256:334644fbac4eff73d985a17a91226df55d0f394160c4cfb880e084c8f7161cac \
|
| 122 |
+
--hash=sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50 \
|
| 123 |
+
--hash=sha256:63bbfd5ded17c4840ac07cd8f1c21ba9d9708141f840b324f422f41b207e3973 \
|
| 124 |
+
--hash=sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890 \
|
| 125 |
+
--hash=sha256:6a8dddef476fab96d066d578fc88526767b836ab5ab21754e1d5bf3879c31c7c \
|
| 126 |
+
--hash=sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80 \
|
| 127 |
+
--hash=sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a \
|
| 128 |
+
--hash=sha256:9d2055050ea716bd38b7f7f1579c275386646b4894c155a3e2f3cd62ed41b7c6 \
|
| 129 |
+
--hash=sha256:a2d7755bef5a12ed488f4ef1f1b69ee9191d7396083b755a5d2295f6edb4768b \
|
| 130 |
+
--hash=sha256:a931079504ecc49efed7744c476a5c343a92fabf66dec2db95edb1b2fdc770e2 \
|
| 131 |
+
--hash=sha256:aa9511c62d14da7aacc9b4bf51f3f697a621e83b2d6919008243c3aad168eea3 \
|
| 132 |
+
--hash=sha256:b5bdfd1c873d4e093aabc0ca84c4ca6dbc4f752afb5c86f146d9742580c9da2e \
|
| 133 |
+
--hash=sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf \
|
| 134 |
+
--hash=sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0 \
|
| 135 |
+
--hash=sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be \
|
| 136 |
+
--hash=sha256:e0bcb7e0f677f543555d2adff3bf19c05f66cdb4796e5ff602442ab2fe3c4ef7 \
|
| 137 |
+
--hash=sha256:f16c709686a78c727bbbf059f92b0bf41c6fc60deec706d2dc19f529175a6125 \
|
| 138 |
+
--hash=sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a \
|
| 139 |
+
--hash=sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf \
|
| 140 |
+
--hash=sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264
|
| 141 |
+
# via
|
| 142 |
+
# miniaudio
|
| 143 |
+
# sounddevice
|
| 144 |
+
charset-normalizer==3.5.1 \
|
| 145 |
+
--hash=sha256:0d929fc574b4d6fd9e7c0f5c2ede8716a41911923aa7fa5fce38e0818aa4a1ac \
|
| 146 |
+
--hash=sha256:1d1c7a53a6c2103925cdd6d7229f8c567379f211c869793df679f2e9f738c369 \
|
| 147 |
+
--hash=sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031 \
|
| 148 |
+
--hash=sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235 \
|
| 149 |
+
--hash=sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072 \
|
| 150 |
+
--hash=sha256:35fe081843b35aad20ffeccec3eeffbe637b15d14f3fb22cc1b59cd8ec17e93c \
|
| 151 |
+
--hash=sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950 \
|
| 152 |
+
--hash=sha256:3617ac3cfd8b9888f145ad89dd6e692285834b0201c6074a5eeaad3fd4d668c2 \
|
| 153 |
+
--hash=sha256:394fea06235c8543390050ed5f529187074b029fb027213f6c46ac11ab5d950e \
|
| 154 |
+
--hash=sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2 \
|
| 155 |
+
--hash=sha256:4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa \
|
| 156 |
+
--hash=sha256:485a0d363cafefcd2538a73c7c838daa2035f09b2c9f9b5e3133f80c6aeb84c2 \
|
| 157 |
+
--hash=sha256:4abdc5f9ad448c1ecbfae2974b820535d6bc6e7eef63babbab3d81cf46968c71 \
|
| 158 |
+
--hash=sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96 \
|
| 159 |
+
--hash=sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8 \
|
| 160 |
+
--hash=sha256:4f298bdadb8f0b9e5672877f647d1be9373ef5320c9e2f049795e26cad28b6a9 \
|
| 161 |
+
--hash=sha256:5b6d1386bf0096d26d3a863dc0a487a5b4eb9aa93cf5ba69683d29dde6b9d60f \
|
| 162 |
+
--hash=sha256:5c0ea61a470e070686aa30892fed79e297d2c8d0ab46b8bcdf027d38c51da591 \
|
| 163 |
+
--hash=sha256:5d8531a6569d025f68e2321e7638fb7978f23db58e5f69f56913837aae03816e \
|
| 164 |
+
--hash=sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3 \
|
| 165 |
+
--hash=sha256:62b55f6722735a6c472f88361cde6640608773d9443cebdbb51abf436a1fcdd3 \
|
| 166 |
+
--hash=sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6 \
|
| 167 |
+
--hash=sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959 \
|
| 168 |
+
--hash=sha256:7235dc28fc6dd9d832ac7c7bce95367dedb85929f17368a0c2bee1e080b9acbf \
|
| 169 |
+
--hash=sha256:7c0c10730342b0c9b35dd1d619beb8214e520bd96a1f870f452680b238aab3e0 \
|
| 170 |
+
--hash=sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e \
|
| 171 |
+
--hash=sha256:88ca277405c2d3b71c4e1c2ee0e7966e807bcba86a69d11e19ba199d18ae4491 \
|
| 172 |
+
--hash=sha256:88e85ab89cb822c1e635f51d6d32e488f94e002e70e2f492bdb8b945543f345a \
|
| 173 |
+
--hash=sha256:90b7481fb62fbe172c558bc6fd1c4c98d82004a54a7551f20e11ac9bf0b8708c \
|
| 174 |
+
--hash=sha256:9362dd90aa7dab48c0054a21187791ccf05473f7dba5d92b8033ae62164675e7 \
|
| 175 |
+
--hash=sha256:94d78ecec2605a8d0398b0f365d5f12a63248438516f5dac536a5eff7337df4a \
|
| 176 |
+
--hash=sha256:96fef3e886d6a9874b14f27fc193fbdc69d5d8035783d86aa4e1cea594e695f9 \
|
| 177 |
+
--hash=sha256:977cdbd483a9cff38179bea4fd754289a6f2195c7abd414aba85410b3e66cc5e \
|
| 178 |
+
--hash=sha256:9d9a0dc7cbe9bec24c3f767c9122c41fe5a1bc43f47cd099d00d393e09769de4 \
|
| 179 |
+
--hash=sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3 \
|
| 180 |
+
--hash=sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99 \
|
| 181 |
+
--hash=sha256:aae2ee51122d3ae968a3837d97dc24a0aeebb0dea23694422cd172bd30017cd6 \
|
| 182 |
+
--hash=sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598 \
|
| 183 |
+
--hash=sha256:aea996a6aba25260827c9ea511d1addfde2da9eb686ac961838509086188b7e6 \
|
| 184 |
+
--hash=sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962 \
|
| 185 |
+
--hash=sha256:b9af956078716df40d985fb0dfeb2c2120c5ca92ba4ff4b388acfd01cdc14d08 \
|
| 186 |
+
--hash=sha256:ba501e667c17d8411f98e67a022d9604ef179aff0e459b7e292c796837c13573 \
|
| 187 |
+
--hash=sha256:c71fb0d56c920c269cd3e2e3fe7c610e3f1fdb21a6ce60efa6430ff63676cea6 \
|
| 188 |
+
--hash=sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2 \
|
| 189 |
+
--hash=sha256:cfa1c0cc3a8f9f53f1243a5a99ac36fd003880199383b37672e86ddda9cb07e2 \
|
| 190 |
+
--hash=sha256:d59b75732e9b6f27388e10c14b0259cc5f2e48c78627d185e6a177b58ad3cffe \
|
| 191 |
+
--hash=sha256:d63600d620ad0064c3a748b950ac5ea38a80190e5498532efefa4b7b3f1da1f3 \
|
| 192 |
+
--hash=sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc \
|
| 193 |
+
--hash=sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d \
|
| 194 |
+
--hash=sha256:e6621fb2a4988d6e53eedc455e5903e2679f3967b8acb3d639f1b63c14a2e893 \
|
| 195 |
+
--hash=sha256:e90251c0c7bdd54a100a0dce3c07b7e637278c93af29dbf78ebb89a58c4bac7d \
|
| 196 |
+
--hash=sha256:f9f8405c2c758532c74fed975dbee57be1f31a6e865c031870c79a6ed3212ada \
|
| 197 |
+
--hash=sha256:fa48b1b63d639f9483e0633e092f5851e2348c352f1f9bb6c8182f87884ef876 \
|
| 198 |
+
--hash=sha256:fd0350afdc3aabd5576f60ea109228bd5538139713c7b094c5cd27c73a98bc6f \
|
| 199 |
+
--hash=sha256:fd0a274c0e5f9a21565cd9d3dd749b61f96b7aa1e20a93aa1ba4029518f2e5c0
|
| 200 |
+
# via requests
|
| 201 |
+
click==8.5.0 \
|
| 202 |
+
--hash=sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360 \
|
| 203 |
+
--hash=sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34
|
| 204 |
+
# via
|
| 205 |
+
# huggingface-hub
|
| 206 |
+
# modal
|
| 207 |
+
# uvicorn
|
| 208 |
+
colorama==0.4.6 ; sys_platform == 'win32' \
|
| 209 |
+
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
| 210 |
+
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
| 211 |
+
# via
|
| 212 |
+
# tqdm
|
| 213 |
+
# typer
|
| 214 |
+
fastapi==0.141.1 \
|
| 215 |
+
--hash=sha256:bfb91aa2d334c61cb35ba9a116fc123b3d3df31640b801cf57a7a78ec3f603b3 \
|
| 216 |
+
--hash=sha256:e8822fc40db1e1858054d7a949a888695bc9bdce70139178e33bd2871a453ca1
|
| 217 |
+
# via mlx-vlm
|
| 218 |
+
filelock==4.0.1 \
|
| 219 |
+
--hash=sha256:481a321a27bef441e23c53371c6abc8d7d16e26b97090074ba44f7538a3fd55a \
|
| 220 |
+
--hash=sha256:fdefc3f3e87716d855ae2b732c1cfd521dd99799ef2b4d00e8c0d4dcdc7cc94b
|
| 221 |
+
# via huggingface-hub
|
| 222 |
+
frozenlist==1.8.0 \
|
| 223 |
+
--hash=sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0 \
|
| 224 |
+
--hash=sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121 \
|
| 225 |
+
--hash=sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c \
|
| 226 |
+
--hash=sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d \
|
| 227 |
+
--hash=sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b \
|
| 228 |
+
--hash=sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed \
|
| 229 |
+
--hash=sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b \
|
| 230 |
+
--hash=sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143 \
|
| 231 |
+
--hash=sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e \
|
| 232 |
+
--hash=sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746 \
|
| 233 |
+
--hash=sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8 \
|
| 234 |
+
--hash=sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad \
|
| 235 |
+
--hash=sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82 \
|
| 236 |
+
--hash=sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29 \
|
| 237 |
+
--hash=sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf \
|
| 238 |
+
--hash=sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62 \
|
| 239 |
+
--hash=sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383 \
|
| 240 |
+
--hash=sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52 \
|
| 241 |
+
--hash=sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d \
|
| 242 |
+
--hash=sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1 \
|
| 243 |
+
--hash=sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714 \
|
| 244 |
+
--hash=sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65 \
|
| 245 |
+
--hash=sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506 \
|
| 246 |
+
--hash=sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888 \
|
| 247 |
+
--hash=sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41 \
|
| 248 |
+
--hash=sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608 \
|
| 249 |
+
--hash=sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa \
|
| 250 |
+
--hash=sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1 \
|
| 251 |
+
--hash=sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231 \
|
| 252 |
+
--hash=sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496 \
|
| 253 |
+
--hash=sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a \
|
| 254 |
+
--hash=sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3 \
|
| 255 |
+
--hash=sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7 \
|
| 256 |
+
--hash=sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4 \
|
| 257 |
+
--hash=sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51 \
|
| 258 |
+
--hash=sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8 \
|
| 259 |
+
--hash=sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042 \
|
| 260 |
+
--hash=sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b \
|
| 261 |
+
--hash=sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e \
|
| 262 |
+
--hash=sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52 \
|
| 263 |
+
--hash=sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1 \
|
| 264 |
+
--hash=sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94 \
|
| 265 |
+
--hash=sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822 \
|
| 266 |
+
--hash=sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11 \
|
| 267 |
+
--hash=sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51 \
|
| 268 |
+
--hash=sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40 \
|
| 269 |
+
--hash=sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5 \
|
| 270 |
+
--hash=sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4 \
|
| 271 |
+
--hash=sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027 \
|
| 272 |
+
--hash=sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd
|
| 273 |
+
# via
|
| 274 |
+
# aiohttp
|
| 275 |
+
# aiosignal
|
| 276 |
+
fsspec==2026.9.0 \
|
| 277 |
+
--hash=sha256:0f08147951c8cb31d844c3547d631053b127863b60be04cf06e121333ee0e2fe \
|
| 278 |
+
--hash=sha256:8dd6e646e99ea382bd85f97a45e6b526a442d79423a7dc673f1e2756d05fcb5f
|
| 279 |
+
# via huggingface-hub
|
| 280 |
+
grpclib==0.4.9 \
|
| 281 |
+
--hash=sha256:7762ec1c8ed94dfad597475152dd35cbd11aecaaca2f243e29702435ca24cf0e \
|
| 282 |
+
--hash=sha256:cc589c330fa81004c6400a52a566407574498cb5b055fa927013361e21466c46
|
| 283 |
+
# via modal
|
| 284 |
+
h11==0.16.0 \
|
| 285 |
+
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
|
| 286 |
+
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
|
| 287 |
+
# via
|
| 288 |
+
# httpcore
|
| 289 |
+
# uvicorn
|
| 290 |
+
h2==4.4.1 \
|
| 291 |
+
--hash=sha256:0e25f1462b23c9cb82d9eb02e28bc706dac2a68cb457c6a0d74d63c8a2a5d0e6 \
|
| 292 |
+
--hash=sha256:4e866ffb1a869ae14dd9b5e6beb5c24a13da0495ad72b65925ded182521c1516
|
| 293 |
+
# via grpclib
|
| 294 |
+
hf-xet==1.6.0 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' \
|
| 295 |
+
--hash=sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7 \
|
| 296 |
+
--hash=sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef \
|
| 297 |
+
--hash=sha256:3dc3e35441ba395006af5aaacc40ef2e603c51ef46c3530b9156185f00935ea3 \
|
| 298 |
+
--hash=sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb \
|
| 299 |
+
--hash=sha256:633dc0cd71d32da58ab8c03ad38e2fac452c15c2b0a2866ebf6ededfe0a5061d \
|
| 300 |
+
--hash=sha256:8fb4f71cba6129110c3374a33f919001ff130488fc23553698e34cc1c2a1198c \
|
| 301 |
+
--hash=sha256:d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f \
|
| 302 |
+
--hash=sha256:f0906082d9932ae0c0057fa194041c22b4e2cdb46b2592ef3b91f020d62a081a \
|
| 303 |
+
--hash=sha256:fb4fadde1b2b70bf4c0c14a6dccbe7194b1c28947fefd5bbe3fed9d940676c3b
|
| 304 |
+
# via huggingface-hub
|
| 305 |
+
hpack==4.2.0 \
|
| 306 |
+
--hash=sha256:0895cfa3b5531fc65fe439c05eb65144f123bf7a394fcaa56aa423548d8e45c0 \
|
| 307 |
+
--hash=sha256:858ac0b02280fa582b5080d68db0899c62a80375e0e5413a74970c5e518b6986
|
| 308 |
+
# via h2
|
| 309 |
+
httpcore==1.0.9 \
|
| 310 |
+
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
|
| 311 |
+
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
|
| 312 |
+
# via httpx
|
| 313 |
+
httpx==0.28.1 \
|
| 314 |
+
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
|
| 315 |
+
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
|
| 316 |
+
# via huggingface-hub
|
| 317 |
+
huggingface-hub==1.32.0 \
|
| 318 |
+
--hash=sha256:b0c7c80561969d9cdacdd55fce67ba9584cca0b9d4ea80957a3a5c1445fac5c8 \
|
| 319 |
+
--hash=sha256:ed70a45498abe86039df7c2f4e5f7575de524be908d3840e8f828d5525eafd6a
|
| 320 |
+
# via
|
| 321 |
+
# mlx-audio
|
| 322 |
+
# solomon-mlx
|
| 323 |
+
# tokenizers
|
| 324 |
+
# transformers
|
| 325 |
+
hyperframe==6.1.0 \
|
| 326 |
+
--hash=sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5 \
|
| 327 |
+
--hash=sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08
|
| 328 |
+
# via h2
|
| 329 |
+
idna==3.20 \
|
| 330 |
+
--hash=sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44 \
|
| 331 |
+
--hash=sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c
|
| 332 |
+
# via
|
| 333 |
+
# anyio
|
| 334 |
+
# httpx
|
| 335 |
+
# requests
|
| 336 |
+
# yarl
|
| 337 |
+
jinja2==3.1.6 \
|
| 338 |
+
--hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \
|
| 339 |
+
--hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
|
| 340 |
+
# via mlx-vlm
|
| 341 |
+
jmespath==1.1.0 \
|
| 342 |
+
--hash=sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d \
|
| 343 |
+
--hash=sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64
|
| 344 |
+
# via
|
| 345 |
+
# boto3
|
| 346 |
+
# botocore
|
| 347 |
+
llguidance==1.8.0 \
|
| 348 |
+
--hash=sha256:020b4ec2254a20555e69095c7d488907f17d7e65ab5a840b267530f2cb369f70 \
|
| 349 |
+
--hash=sha256:0eb7be70bf822e54cd4021bb200cfe2b86e4f3379d251067dc9f7da327f3ceab \
|
| 350 |
+
--hash=sha256:18d1579eabb040e65c870d50c6df19a7bef140c5260d12ad35b7f0dc446312e0 \
|
| 351 |
+
--hash=sha256:39668c11396896e5f05f59b70c81e4afd060b3408f02c8518b7a6943bfbb8a5d \
|
| 352 |
+
--hash=sha256:6ae4343bd40b88d1dd824a17edcee11b5e5a000b16b6fedb9fcf7f58d019177c \
|
| 353 |
+
--hash=sha256:6bf3953d06e7f5e24bd02fa6a89a5b2b88f7e811c0fa0228487d8267ef7cec54 \
|
| 354 |
+
--hash=sha256:79b0576991b8fc7534456b65c41d43c3183c8ca974a17799359af969c1489c07 \
|
| 355 |
+
--hash=sha256:a8837ac2b3bf4c46e1b6363012a22de043b7f8ef013b04d8689d471eb573b766 \
|
| 356 |
+
--hash=sha256:b5e866d8a896e255f30ec952f5280c61a3d6f391a9dce575ce976dd58f0b7000 \
|
| 357 |
+
--hash=sha256:bb9a89e8cdd7c8b5cf4f84e45b04177e79acdcc4d5116fbc775e511f7314df44
|
| 358 |
+
# via mlx-vlm
|
| 359 |
+
markdown-it-py==4.2.0 \
|
| 360 |
+
--hash=sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49 \
|
| 361 |
+
--hash=sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a
|
| 362 |
+
# via rich
|
| 363 |
+
markupsafe==3.0.3 \
|
| 364 |
+
--hash=sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219 \
|
| 365 |
+
--hash=sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb \
|
| 366 |
+
--hash=sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6 \
|
| 367 |
+
--hash=sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce \
|
| 368 |
+
--hash=sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218 \
|
| 369 |
+
--hash=sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73 \
|
| 370 |
+
--hash=sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c \
|
| 371 |
+
--hash=sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37 \
|
| 372 |
+
--hash=sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f \
|
| 373 |
+
--hash=sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d \
|
| 374 |
+
--hash=sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19 \
|
| 375 |
+
--hash=sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9 \
|
| 376 |
+
--hash=sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354 \
|
| 377 |
+
--hash=sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698 \
|
| 378 |
+
--hash=sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b \
|
| 379 |
+
--hash=sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc \
|
| 380 |
+
--hash=sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485 \
|
| 381 |
+
--hash=sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f \
|
| 382 |
+
--hash=sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12 \
|
| 383 |
+
--hash=sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025 \
|
| 384 |
+
--hash=sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009 \
|
| 385 |
+
--hash=sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a \
|
| 386 |
+
--hash=sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5 \
|
| 387 |
+
--hash=sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f \
|
| 388 |
+
--hash=sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1 \
|
| 389 |
+
--hash=sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287 \
|
| 390 |
+
--hash=sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6 \
|
| 391 |
+
--hash=sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed \
|
| 392 |
+
--hash=sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b \
|
| 393 |
+
--hash=sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676 \
|
| 394 |
+
--hash=sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e \
|
| 395 |
+
--hash=sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d \
|
| 396 |
+
--hash=sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d \
|
| 397 |
+
--hash=sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795
|
| 398 |
+
# via jinja2
|
| 399 |
+
mdurl==0.1.2 \
|
| 400 |
+
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
| 401 |
+
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
| 402 |
+
# via markdown-it-py
|
| 403 |
+
miniaudio==1.71 \
|
| 404 |
+
--hash=sha256:12bc33e7e61072b4b541c14e10ef76119d5643e6bbb98e2dec0c0738889438fb \
|
| 405 |
+
--hash=sha256:19be6f0a1e601c2237433e579734cfaf6469191b224c20c9e5f73c32ef9ee2b9 \
|
| 406 |
+
--hash=sha256:1bf93aeede652926f27f430f0fd69ef0cf8a949c07b537d6a2f295602c747037 \
|
| 407 |
+
--hash=sha256:4c849ccb1349f7b3553a77a66fe7e972315185f5c4c44a0bbda7ebcdd224db37 \
|
| 408 |
+
--hash=sha256:61b86f26d653040db32d9d15b05446321dd10e45beba25b44f841e26935213d5 \
|
| 409 |
+
--hash=sha256:62db602651bc20a2698f36a0d356d7217ed6f4f917550c7ffb3705c8e8be90cf \
|
| 410 |
+
--hash=sha256:70fa2ea5353e6919aca59b8c5768144af009d18c3bca251749d66fb497424563 \
|
| 411 |
+
--hash=sha256:8fc1a4f084cc1b4b25c567d22f54d1e46bfa505c17ed777c8b198e5c53d0f785 \
|
| 412 |
+
--hash=sha256:ab100e5240b104b5326e4ec1be07b6ae461f7d3d4d7a694857fd2f0493d210f9 \
|
| 413 |
+
--hash=sha256:d9dc15eff711bcfc62a9d05e0c78e4bc34821a455595e049629f2fea7491a523 \
|
| 414 |
+
--hash=sha256:e6287f15caa808a88aad0700a182bec1ff6d98769717425adf9ebf41259d1936 \
|
| 415 |
+
--hash=sha256:f4a44b70b66628b0c307e40ae0ae857695978cae18462179b806d8edc807d416 \
|
| 416 |
+
--hash=sha256:ff51e2887bb673e2e757752b586b3dc924d59aa5fbcae9bbc45f4a111bd3262b
|
| 417 |
+
# via
|
| 418 |
+
# mlx-audio
|
| 419 |
+
# mlx-vlm
|
| 420 |
+
mlx==0.32.2 \
|
| 421 |
+
--hash=sha256:45857fadb381fea3db57d9681b04c987813fa883f3182ec9fb05bc56f468978a \
|
| 422 |
+
--hash=sha256:48e8738b078eeb7bfde74931fc02d8aa9c32f05d3c0dbf97b5c3cbe0470fbddf \
|
| 423 |
+
--hash=sha256:50ced716f4ab860cbda9d65adf74877923fe26036c4e28d8f572ecec57621cfc \
|
| 424 |
+
--hash=sha256:583111ec13fedf63ddbfefda77dabd57168978f06474f5e5d2637180d154fcc4 \
|
| 425 |
+
--hash=sha256:65beb9ce75153072808ef18913ecca3d929b87be5d7c1f57d9df391c04b6f957 \
|
| 426 |
+
--hash=sha256:65d3d29b66045ed8dd2d8e437c8770de325843c364f7b7c38cd8ae90a7eec854 \
|
| 427 |
+
--hash=sha256:68560fd648c5bb900aa6f6765cd74c5a8abaf092d97d73584a57b7545966c227 \
|
| 428 |
+
--hash=sha256:6c615ad1c6877d7d38affe8526446955cd48d6796e871150f59145cf0d1a265d \
|
| 429 |
+
--hash=sha256:77217798a2b036bae9f213b851d4cde4581893787c9964458b7d471f86036bd6 \
|
| 430 |
+
--hash=sha256:8d270ade1e48e006383a6b5f33a3a4ec5c265389299a60a60bf55165af1770d9 \
|
| 431 |
+
--hash=sha256:9d21abe340403b6bf445e8494590a7341b655739088c92f178d7bd4241ba0110 \
|
| 432 |
+
--hash=sha256:bc69bd1062b97028ae6b79522ed0bd635a2b133fe3c398c03b66b060c20d9240 \
|
| 433 |
+
--hash=sha256:c7670ffb854c11e6776349a3797fa076d1a2a00290ebe2e9cfed8b60ca4a5db0 \
|
| 434 |
+
--hash=sha256:c95a384de1a0c0ba18425344cad8ac87180e3c5c1921a42e2621475be5966bcf \
|
| 435 |
+
--hash=sha256:cf63fd5c32258ab07523b06401c20ee2280bf56e26e991d05bf6fd8a4d42d1f6 \
|
| 436 |
+
--hash=sha256:daebf84dfb857d70e87b1b98189a057e691e99a4a2b9f6f64cadebad917f8964 \
|
| 437 |
+
--hash=sha256:dc5eb3cc30d4285f2734c368442f717599e97294663441cb42959e3b856d6898 \
|
| 438 |
+
--hash=sha256:df8c75e509de868fca148dfeb38d92ce956eed386569c87caeb72bd16d2d6962 \
|
| 439 |
+
--hash=sha256:f6071e4973927966c12b3894deb75f4fcfc33300e0705312a80fdbbaa92a9c4f \
|
| 440 |
+
--hash=sha256:f77e47e6c1e176a61ec1bb1f9e74d874482eea6eb86ffb162a1f3e789c806453 \
|
| 441 |
+
--hash=sha256:fe813a4dee2daa6d5ac496ef25117034728c77fe26f713983a3b406eb6f4e8f0
|
| 442 |
+
# via
|
| 443 |
+
# mlx-audio
|
| 444 |
+
# mlx-vlm
|
| 445 |
+
# solomon-mlx
|
| 446 |
+
mlx-audio==0.5.4 \
|
| 447 |
+
--hash=sha256:3e1895860d9a636360a9377b5651239f5197e649d56fe25f1382cac6f2ed1e55 \
|
| 448 |
+
--hash=sha256:d350ecc43a65b94b1578381370be64229948f79aef9ff599d20adb65e38351b3
|
| 449 |
+
# via mlx-vlm
|
| 450 |
+
mlx-cpu==0.32.2 ; sys_platform == 'linux' \
|
| 451 |
+
--hash=sha256:d0f94625588b51a878786dd51cec5617894ce586cf3c94645ce1b64e24c27c0b \
|
| 452 |
+
--hash=sha256:fc5d31b90fc4f457b2f9614ed45651a567d22a6a11a03d114a90a4e10bdd8878
|
| 453 |
+
# via mlx
|
| 454 |
+
mlx-metal==0.32.2 ; sys_platform == 'darwin' \
|
| 455 |
+
--hash=sha256:3825fff379dbc107dd3413e564a06caeaa24819910ec49c0439e454c06a1b9b8 \
|
| 456 |
+
--hash=sha256:55a369250d220b2cf10213a87a2ac1b1a420608c5b35b1df4e7147ac8e32f121 \
|
| 457 |
+
--hash=sha256:e6abeac9ac5265830c9c1541b6f96e9be37a85c2446763a46ad466c63a3837ab
|
| 458 |
+
# via mlx
|
| 459 |
+
mlx-vlm==0.7.1 \
|
| 460 |
+
--hash=sha256:b8abd3cc7e3513d9915bf9f6903833c697dc4c3084c2acdc880029c33e331a03 \
|
| 461 |
+
--hash=sha256:d9696bc3a2e961f43b5948a101dc0c966b5989d382e6910c37e2f3d555bc3408
|
| 462 |
+
# via solomon-mlx
|
| 463 |
+
modal==1.5.5 \
|
| 464 |
+
--hash=sha256:30df363ed1898cc3d91a09ff3f95c38ab043f6b6294011b01085312c6a0ac777 \
|
| 465 |
+
--hash=sha256:8d10d3ee09818aaba1973b73ce2521ab8961b63a29b5b52e3ff0d25e7a74808e
|
| 466 |
+
# via solomon-mlx
|
| 467 |
+
multidict==6.9.0 \
|
| 468 |
+
--hash=sha256:0db5bf96ec2ce45a8bc7fbbe8a486089969bb2791a66b6789ee3aed0d5dd562e \
|
| 469 |
+
--hash=sha256:1126782e3c3b1a7ccd990be3d3221709348e4b07d6ecf8b50965a93ae2624145 \
|
| 470 |
+
--hash=sha256:11e32ccf23cdbfcf8299a6a825930a858ec9a6aa05d6752d0f90f2bdf19489e1 \
|
| 471 |
+
--hash=sha256:1eb7939025bd9289d9dfe3a399102b1642f4fbb105a6af82f284052ee89e97a9 \
|
| 472 |
+
--hash=sha256:22067e88ff266e6a5dc59114529332692a01cc04b10dbdc2c14ab91217dee819 \
|
| 473 |
+
--hash=sha256:254e53be2ec70518bb82dfa9b0c7166baaf2bd0e918bd17b65caaf489d5a5522 \
|
| 474 |
+
--hash=sha256:2ea72901860ccbe94517421681c60b13533ce03ba2f7bd96293c3a4d16ac4ccb \
|
| 475 |
+
--hash=sha256:3e78870909e9f9e3d672ba99f1eb75130d7e01c42e642e6a70f434df32ca0ee1 \
|
| 476 |
+
--hash=sha256:3ec1e387b1f8a85ae5b94aa8c4e0576912ffa4d31bd0578f24c950d4f05ee476 \
|
| 477 |
+
--hash=sha256:408fac672931f2458be3bc8c89d9facd16dac2aad17c7cee2ca1693eee99f07e \
|
| 478 |
+
--hash=sha256:4bb769ccc72e15d7d441e1a08f169d418376be77cdc387e813129c26b357fe50 \
|
| 479 |
+
--hash=sha256:4be612f23990a261060ccd8f15e89dad1f9b7bb0c1021c5c3987f5fc57959391 \
|
| 480 |
+
--hash=sha256:4bef8cb5edea9c9daeb8396a75eeb97f912c3fb3fa408fe659edfecf91e47424 \
|
| 481 |
+
--hash=sha256:516fa4817cd070088f616a901380db56189f86daee9da79aada3c9b653f49ed7 \
|
| 482 |
+
--hash=sha256:51a08dceed4b42ef25755ee2cbf50df325e90e6b415d00955ffdea2c394ad6c0 \
|
| 483 |
+
--hash=sha256:57c2445049f7d8e66306f712868219da7ff7168ef42263dc032401211bf1205c \
|
| 484 |
+
--hash=sha256:640113258c5925a9eed2c12523410b25565ac5df2fa6735fbae88fb09bcdd212 \
|
| 485 |
+
--hash=sha256:662315f8621b3559268813b11134c1f9633edd4ab5f7b713688a243c13f4026d \
|
| 486 |
+
--hash=sha256:67bcff396d2ad62197c95488a716a88462792b384b5ea6e44bf7c1070eddb8fc \
|
| 487 |
+
--hash=sha256:67bed23e9803945b0760650ec3e903af772c49abe869f3bc03c66b2e7649d5ef \
|
| 488 |
+
--hash=sha256:6a5111a2bd824c821a3dd09da29680391b0caaa18fea7761358f4001e6898d1c \
|
| 489 |
+
--hash=sha256:75f7fc21ffce9a792cb919f0e0b0b52117bd672f2a55d1929d573b6fc437f374 \
|
| 490 |
+
--hash=sha256:7aaa14f0b9ffa2780c5d3b21da0e9b58778ed47af3369df72e5fd6dc10ff8041 \
|
| 491 |
+
--hash=sha256:85ed0f3c3b01174aea5a8a8fcd456f64c2e9719c0f42c612c2694ecd35974a65 \
|
| 492 |
+
--hash=sha256:8bb6be697065cbf31051465f9939d65624573d2219c3da8316db9e7cf5e0f5a7 \
|
| 493 |
+
--hash=sha256:8e991677c4bdc5d9f2e71c74717a4e32cfe98930ca05becdf722b5eae1329d6a \
|
| 494 |
+
--hash=sha256:8f06c4da5315a6f709b13408c3e13f3b475f8c559ec7608c3c67062512871235 \
|
| 495 |
+
--hash=sha256:91092d597fcf0940cd6a59e64ba7156ee22d6899993fd7c5b1897fda71482f8f \
|
| 496 |
+
--hash=sha256:95d339c3b75b4a50c665bdcf8417428cd71c3e5cd48e194cb1d336fcb856beac \
|
| 497 |
+
--hash=sha256:97555ad30ad20a8eb90fa86522088eebbbd68aba03e56d53f4850b3535c65e61 \
|
| 498 |
+
--hash=sha256:9869105ab61db13004f9ed610cd29ce4237b2c609f5f7b8bb8f2339fb9dad17d \
|
| 499 |
+
--hash=sha256:b33e499a7b1f722547d57b4865ed68c03161643b9afe49fe097a0832078d183d \
|
| 500 |
+
--hash=sha256:bb69b724c345420ba49187a17a894f146099f5b2e501df42ddb4452ac8be37fa \
|
| 501 |
+
--hash=sha256:beda95a6bd0a2e2265b941b90ff72543afbeaebb6a450e3a6a010d10d4a2ffca \
|
| 502 |
+
--hash=sha256:c51fd8d59e72e45c64907bf7f81fbd94f4c8dcd1c8b2f23f4c2d7ede788fcfc3 \
|
| 503 |
+
--hash=sha256:c7ab60b91e11b25e7682c5cd8763fdd17929ea83f234ba441091f1492e631ea3 \
|
| 504 |
+
--hash=sha256:cb847cb4002e725f88ffe29883da8290fd0754fa0461ed8988735e20964a9f65 \
|
| 505 |
+
--hash=sha256:cff3cff5a725bdb8359962de8d7429aea592d7693dbd197eeabbdfab9b6300e9 \
|
| 506 |
+
--hash=sha256:d7d32c0543494efbc9394e2b571725071d08e295993486bc9a43f6f89375ee01 \
|
| 507 |
+
--hash=sha256:e231de8ce43d4fd10bec4f67f71238ed88a974de30a9f20be7a4ab16c970a988 \
|
| 508 |
+
--hash=sha256:e4826f6b56456fb1e98111d7bc20cbdc7fa0a41b1f9ad80ff2dd3f2f5b226fe1 \
|
| 509 |
+
--hash=sha256:e71a072c52c78b7f97cd4611df6cef10977e4f2367cd0654a7626192f931adde \
|
| 510 |
+
--hash=sha256:f93c9058a0eceac0df2ce9d4c8823b84786ee598194753c2ca0c100224405e47 \
|
| 511 |
+
--hash=sha256:fca5b74b5909c29041f857c40d51d9273636fb4221cf020e4c452deb1c448a40 \
|
| 512 |
+
--hash=sha256:fdd484b84d3394e805689c56be3ab1f877ae7ff0eb9ff90a3ee7a755cbebab4f
|
| 513 |
+
# via
|
| 514 |
+
# aiohttp
|
| 515 |
+
# grpclib
|
| 516 |
+
# yarl
|
| 517 |
+
numpy==2.5.3 \
|
| 518 |
+
--hash=sha256:0a59a421a32580a009e8a1751345bf829631b990dc1794b80514ab722b435def \
|
| 519 |
+
--hash=sha256:1302b90c0e52281681b2975adfe8a860cb7b12216a27b4b0b4207c44bf7bccf0 \
|
| 520 |
+
--hash=sha256:1c80eabb4035ecf4ca9cd49cde8a9fdd69a729e63e6474887d1523ade7aa277f \
|
| 521 |
+
--hash=sha256:4f8929ee6c96bfbd7b4ed2032e0c03af86fe1826740ab61ddabf9072d06e57ff \
|
| 522 |
+
--hash=sha256:66a78fe4556c60aceda5916f9eacd638b18e9e681016ec302dcb4682d6d4d034 \
|
| 523 |
+
--hash=sha256:71cad2b2a7451ab79d8f5e71b453485b6775963d5cf794179144a7463fe6e8ec \
|
| 524 |
+
--hash=sha256:76c2c1e6bfa5c84adc6434dfbf013aa92096a7985221762c8f11fedfd20fff58 \
|
| 525 |
+
--hash=sha256:8e4dd766076855b5ff7ea52fa5f07ce26286726e0f8bff446b7739d02e6ea204 \
|
| 526 |
+
--hash=sha256:92f30e89b8ee0ecf363033576c422b2f58fed6a80bed0aa48dff6d14c654663e \
|
| 527 |
+
--hash=sha256:a5fa86b80fd24bcd1aff83ad23be44ea323de3f787be8f8b15d4a65621e25321 \
|
| 528 |
+
--hash=sha256:a72f874bc9e10e4b8f80426fb49716d5141f64442a0c8418065093ec8017fbb0 \
|
| 529 |
+
--hash=sha256:b5d93cf48f687479941d12b69c873ad2cc76bbd487f0091c2200636497f34034 \
|
| 530 |
+
--hash=sha256:b7e18c623bb5c95acb3b3328861272816ba199fb531921c5d6d0b675f1fde9e3 \
|
| 531 |
+
--hash=sha256:bd4cb9ad3c7889b9b3fe0a9a9fb5d2ed26f9879bff2608d9f01aed147a20d231 \
|
| 532 |
+
--hash=sha256:bf63afbe037eb5d2fe87fbcc7778e61da53ebaf21d938a4515aa73b62532a5d4 \
|
| 533 |
+
--hash=sha256:c76d5dde9f445058f83d0c02af00557a4db91de9a9a57c0df87d1535001d654b \
|
| 534 |
+
--hash=sha256:cb189f09db39283b26bfd061ec16189e14f71c6755207f72a0f7540867afe5b9 \
|
| 535 |
+
--hash=sha256:ccb32e0525d29e8b0572eb84c9a57af0e7a4e615726927506f55063c62414034 \
|
| 536 |
+
--hash=sha256:ccbc4665079665c3cf3bab4db9f6b095370cd6437d66be549b6c2a1fd19e1958 \
|
| 537 |
+
--hash=sha256:df2d5874ff183595a4ba404edd04f6bd9b5505c1d7708573f6a6c17489a67563 \
|
| 538 |
+
--hash=sha256:f59a878c33d6b88122d80d239bb3b845d58708750b0cb06a09aebb9b18ec696c \
|
| 539 |
+
--hash=sha256:f9a2353b37a1a9e78fd82b27ad7e2a32a2d036604d18f02b05e3136c62ca3b09 \
|
| 540 |
+
--hash=sha256:fc36dc566135b5eceec4cf89758fcb719266a019ef07dae1754ae7c9f617ef3e
|
| 541 |
+
# via
|
| 542 |
+
# mlx-audio
|
| 543 |
+
# mlx-vlm
|
| 544 |
+
# opencv-python
|
| 545 |
+
# scipy
|
| 546 |
+
# solomon-mlx
|
| 547 |
+
# transformers
|
| 548 |
+
opencv-python==5.0.0.93 \
|
| 549 |
+
--hash=sha256:08d5d91d967b58d6db86073b2ad3eaef88ca4ebdfd45c9059bf59f5ded0c7ad2 \
|
| 550 |
+
--hash=sha256:198a75138241810206a17c829dbcc40a7cb1841cda538ca86cbbfc6c7d95f898 \
|
| 551 |
+
--hash=sha256:4b4b1a34c79bf8d3738e3cfe9a9e67b51a79663f6b692cbdad8c31f570da4157 \
|
| 552 |
+
--hash=sha256:66aac3e5b5faa48d4025816592f3af19e4bfc2c68dec067bae2dbb4ca10aa9e2 \
|
| 553 |
+
--hash=sha256:6bbc32f59e1b1a7db7b39c81f63d00625f041d333037fd8702f6da52cc39108b \
|
| 554 |
+
--hash=sha256:c8de2dec111122a02e8beb28e16c31904992dfd6186560b142a92c71403c1039 \
|
| 555 |
+
--hash=sha256:e2b4272e736836f66c2d176e43ab8101f3a00d45654916399f52e150c58981ac \
|
| 556 |
+
--hash=sha256:f8b6d0a212253dd26ad338c812f1f23ca118fdf05a9c8c6b9444f161aa8c5881 \
|
| 557 |
+
--hash=sha256:f90ba04b8f73bc5c3814037699739f0156f597338a98f05956c684e7c3ca10d2
|
| 558 |
+
# via mlx-vlm
|
| 559 |
+
packaging==26.3 \
|
| 560 |
+
--hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \
|
| 561 |
+
--hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c
|
| 562 |
+
# via
|
| 563 |
+
# huggingface-hub
|
| 564 |
+
# transformers
|
| 565 |
+
pillow==12.3.0 \
|
| 566 |
+
--hash=sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3 \
|
| 567 |
+
--hash=sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df \
|
| 568 |
+
--hash=sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8 \
|
| 569 |
+
--hash=sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89 \
|
| 570 |
+
--hash=sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510 \
|
| 571 |
+
--hash=sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce \
|
| 572 |
+
--hash=sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace \
|
| 573 |
+
--hash=sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a \
|
| 574 |
+
--hash=sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e \
|
| 575 |
+
--hash=sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91 \
|
| 576 |
+
--hash=sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66 \
|
| 577 |
+
--hash=sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09 \
|
| 578 |
+
--hash=sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f \
|
| 579 |
+
--hash=sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec \
|
| 580 |
+
--hash=sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b \
|
| 581 |
+
--hash=sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965 \
|
| 582 |
+
--hash=sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35 \
|
| 583 |
+
--hash=sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9 \
|
| 584 |
+
--hash=sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f \
|
| 585 |
+
--hash=sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c \
|
| 586 |
+
--hash=sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65 \
|
| 587 |
+
--hash=sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7
|
| 588 |
+
# via
|
| 589 |
+
# mlx-vlm
|
| 590 |
+
# solomon-mlx
|
| 591 |
+
propcache==0.5.4 \
|
| 592 |
+
--hash=sha256:0c889f6fa84957bc7e8b4eab71fd16a0455068d5045e3aa40c733071d2b2fd77 \
|
| 593 |
+
--hash=sha256:2814ecd8e818f487bee4b0f921bc4d1c176cc5fc71ac0f072d0fa67eda4ac14b \
|
| 594 |
+
--hash=sha256:36c0d9db44b523ef93d03341b1c42d69ff01d673c053d1b1c6c3a363bcaa39ba \
|
| 595 |
+
--hash=sha256:3e413d7a4a9b4866b7a761d6060d434b64d23cd35122eda3b026a0bbe8196b25 \
|
| 596 |
+
--hash=sha256:425f8cc86ab5018b4b8d4a23bc8e74d964bd3d757c3702e301aa79be76c53f6c \
|
| 597 |
+
--hash=sha256:44149f46500a0a41b95b4d99c2e586a77319539730607b9892974a092788b111 \
|
| 598 |
+
--hash=sha256:4fbc1a15dc8cd1689508758d626b372b1f09d28d9577667feaf9e6bfcd8efcbc \
|
| 599 |
+
--hash=sha256:60a64cbccaa11b7760ce705a14ada17ba459e7ca9f23ba587eb013821032d7ef \
|
| 600 |
+
--hash=sha256:62c60aec739ed00124573cce1178138fd690c7676352d67a37328c1cf51d7468 \
|
| 601 |
+
--hash=sha256:69fc35c0779522da366c563e5faf203ffc1f8ff0021d5b1337fa4efa5be73177 \
|
| 602 |
+
--hash=sha256:6af4693716bfb03f1752ef1b30faa593db2c01d5272e9b8564a1549452a979ab \
|
| 603 |
+
--hash=sha256:7cc528e760a8af06f2b13e9b9f362cd90c7c718ea61228a96dbd31ba16ed7f47 \
|
| 604 |
+
--hash=sha256:7ffafcbfc7b549ab940047e505c831eabac5e67de53e1bc174adbc5285c55944 \
|
| 605 |
+
--hash=sha256:87a3caecf8095e48dc72f84bfa42e23a848cf410cc9cc13031fba4869b706a21 \
|
| 606 |
+
--hash=sha256:8876b39961e33d912afe3c1bee18ee564fdad0206f873cc15d522756b7f50737 \
|
| 607 |
+
--hash=sha256:8a235f73d6e020855dc29dff012d920c02ee0feab8d73a24185a7569f4be1161 \
|
| 608 |
+
--hash=sha256:96f7c5c15656040ddcbc51e56dc59b58aa25999d743c126abd425b9766ab43e9 \
|
| 609 |
+
--hash=sha256:98914de2c4d7f0f9f4a8c6ea4bf05841f4175796941e3ef7d47eb718f22311fb \
|
| 610 |
+
--hash=sha256:9a2a8a50a93dee0268a860a07fa3b4bd968f8ce4dbd794957da772f395368526 \
|
| 611 |
+
--hash=sha256:a4d7a54719b67338a305dca2ce6aafe366817df94ddfd4b5514374356f5ca546 \
|
| 612 |
+
--hash=sha256:a5793c7698a53f56f4a1889a4737c7eeb1b7ad0842fa6b1abca22913ff79c8c1 \
|
| 613 |
+
--hash=sha256:a74bfa37147cc08fb29df10bd9c16f40fa7f860cd3a6d2fff853323a94f6e17f \
|
| 614 |
+
--hash=sha256:ae58f361bd5dae942717c65d3413b478c70aea9c462599e7b9adad3731db3894 \
|
| 615 |
+
--hash=sha256:b28f41fa3b8c6900457f858ec5b03998f3a6d535fbc1bb2edec5961ea05ec429 \
|
| 616 |
+
--hash=sha256:b3083bfe87f95c756e610bd8025f26cbd1cd4aaa03a422f2d65efb7a97cd53d8 \
|
| 617 |
+
--hash=sha256:c02c0e570c5c7e077b0181a9f3cdb7d4c3617d1cda6b5c95bd5d34022923d82c \
|
| 618 |
+
--hash=sha256:c2ba30a89035b57b73e00475de948521602f543d79ce01db10b04b36c4c76fc8 \
|
| 619 |
+
--hash=sha256:c3e98c55bde2bcf7db3c70d1aed7ae9aa8aebbf19a250c66645cde44cdb8b867 \
|
| 620 |
+
--hash=sha256:cdee8205a44d0be91bbac4c41b95d86641b72dfc7aef1279400e4fda3f26a937 \
|
| 621 |
+
--hash=sha256:d1f5a500bfcbb2c0ab85e98a0dcd70f5899d34efe365a0187700369a79603031 \
|
| 622 |
+
--hash=sha256:db3ae52ccc150dbc84704e9d642743897f3e1c54742ff34cacb661e52e3818a9 \
|
| 623 |
+
--hash=sha256:dbab5f5ff6897c81f355d079010cdae85b02e5a0b518b5251523b8ad8ae9ac3c \
|
| 624 |
+
--hash=sha256:dcbf346a318a5e30063f547630b02bb787ce2f45b6368d5da143660b6a3835d8 \
|
| 625 |
+
--hash=sha256:e1d52a05dc417279f7e5c7618c5dfbbc29923aaf9bc0a5c1802ddcebf54c61a0 \
|
| 626 |
+
--hash=sha256:f85915e00dcb1cd9f2f890ead064ed40a27df06f0db65be427b29482ae357572 \
|
| 627 |
+
--hash=sha256:ff6b113f50bc066a698db5d944d2c6dc7507168dd3341e255a8892fd0715a558
|
| 628 |
+
# via
|
| 629 |
+
# aiohttp
|
| 630 |
+
# yarl
|
| 631 |
+
protobuf==6.33.6 \
|
| 632 |
+
--hash=sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326 \
|
| 633 |
+
--hash=sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901 \
|
| 634 |
+
--hash=sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3 \
|
| 635 |
+
--hash=sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a \
|
| 636 |
+
--hash=sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135 \
|
| 637 |
+
--hash=sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3 \
|
| 638 |
+
--hash=sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2 \
|
| 639 |
+
--hash=sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593
|
| 640 |
+
# via modal
|
| 641 |
+
pycparser==3.0 ; implementation_name != 'PyPy' \
|
| 642 |
+
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \
|
| 643 |
+
--hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992
|
| 644 |
+
# via cffi
|
| 645 |
+
pydantic==2.13.5 \
|
| 646 |
+
--hash=sha256:346a034f080da3755d8e9cb5e00e8b07de1d39e4f6e2c87d8ab7cafa0b269a73 \
|
| 647 |
+
--hash=sha256:51a9c5f7b2f8e636f04c6cada605d9b6a3bf1348fdf945a3d8869b19bba0ee08
|
| 648 |
+
# via fastapi
|
| 649 |
+
pydantic-core==2.46.5 \
|
| 650 |
+
--hash=sha256:013d6f3483d81e02e7c328831808f336c8596ee33b4bd4026b9ffb1e960b8942 \
|
| 651 |
+
--hash=sha256:0fc5be0abd4a407e200d844b404e33639a554e7bd0d448e7b9ae181be4789ac2 \
|
| 652 |
+
--hash=sha256:10416c15b8839ecc4ef4d0885da76da6fd0f67333a0eb8aff6d93c4b8f2910fc \
|
| 653 |
+
--hash=sha256:15f4a94963c95accac15b7b657bb177d3ad82bb90b0d0526d9a9b85079925db5 \
|
| 654 |
+
--hash=sha256:18a09e1e1011b462f2e32774f25859ef1223d5c2b0546a633cf56654710721e0 \
|
| 655 |
+
--hash=sha256:193375f3548919d3f0b60936ca113ada3e38f264f91b9b8e0508efaad57be931 \
|
| 656 |
+
--hash=sha256:24922243639cbdac66c75fcb6fd6495a9cb52b213d62f9a0d16f0310b1ff8038 \
|
| 657 |
+
--hash=sha256:2bc9419666990c06d7397831f2126a1ecc3594aaa3ff7de5bf2d066802f4e07b \
|
| 658 |
+
--hash=sha256:347ec774390c87326a2e4929d58d3f7e8763a104d5d35f4cd595a4c952366433 \
|
| 659 |
+
--hash=sha256:4fdc8b93a41521988916eeaa271173fcca7fa0803d62f87675aac8dcec1c8e29 \
|
| 660 |
+
--hash=sha256:5cb482e9e84c851f4e623fe4acc1ced89168cf1fe18f7089db4548c8f5bbb65b \
|
| 661 |
+
--hash=sha256:5e81740c09e310f5aa5cbd3e434a01c154d4bef93241c7877b39f211d2b78ba8 \
|
| 662 |
+
--hash=sha256:5ee239d575f80b08eca11f6e20f90c4c695de7825c67eefe6091fbf20dda648e \
|
| 663 |
+
--hash=sha256:6f7b393a8b3da82f5c1fc0751e6d01ac6c55b93c18226a60bdfba4a724efafd1 \
|
| 664 |
+
--hash=sha256:79bdfa52f843137045b2d081cc05c120ba6665d29b7559c2c47690906f39279f \
|
| 665 |
+
--hash=sha256:7ac031912d54f3d83ef3b3eb98dfabc1608802e2202263d25957eeed40b94761 \
|
| 666 |
+
--hash=sha256:816ff0a6550ffc06c098ccd2e0698600f9aa7da192a79eaa6f9af504a35db869 \
|
| 667 |
+
--hash=sha256:837b396ca3d7b74091ca623f6cbd8351bd42d670a79c2683e79fb089f06a2de5 \
|
| 668 |
+
--hash=sha256:8e24d8f05fa2d28513d94e877e9c75ad66175376209b3977f916e240e623193c \
|
| 669 |
+
--hash=sha256:97bf8de4d541598c94a59344eeb988a94c08ff76b5723c41f6567ec18c7892ea \
|
| 670 |
+
--hash=sha256:9c4b71f10dd532fb7a5cbc8f58707779e64f03a258c2bf8bfbaecfcd9970b519 \
|
| 671 |
+
--hash=sha256:a39ac25a9a2fa4072efdb429833c4a4c8009a51ff9eea3eeae131713cd27991e \
|
| 672 |
+
--hash=sha256:b7ca9034437b6022f941f4857459562ee00a560b97e7cce8a0ec5a74fc6766e0 \
|
| 673 |
+
--hash=sha256:b98134087d9de723658d17a42c7d0da8d6e2ef08015dee7dc93889047315f5e4 \
|
| 674 |
+
--hash=sha256:b9fe6fb92520e3fd61f2e49000b6911b188824f089b75973ea06d6267f0b476d \
|
| 675 |
+
--hash=sha256:c76fe65e607be28c7fd4d56fc3c42b1583aa058ce3408b7ad0fd540171d31f9f \
|
| 676 |
+
--hash=sha256:c7ea57fc63aa7da93a1bd2d644e6577befae10c52c4e36377635eea1056a74f5 \
|
| 677 |
+
--hash=sha256:d22a945598fb91236b4dd793a6e42e4f3dd7740bb5aace5ebd7d4c08d13bb575 \
|
| 678 |
+
--hash=sha256:d925f3d9afd05a8c0fb3a1031463a8d59ebe5e2afad297e29c78be19e13b4e62 \
|
| 679 |
+
--hash=sha256:e652ab17569c94bff5475520f907b7148b8c24036a8ebbe5cf7cf7493d28579a \
|
| 680 |
+
--hash=sha256:e80675d75ae2cd14372cb65cad5400d9347a3d3f6c13000183f22dfd027283ed \
|
| 681 |
+
--hash=sha256:e9c134bb666dd54b778b9fc0d2b50cbb7f979b9e3716f26a88c9ab3b6fc1dd0f \
|
| 682 |
+
--hash=sha256:efd62a42486f1bda5d24cb4f63d15a3c7768375fe83d36f9417b4ad7a2fb20b3 \
|
| 683 |
+
--hash=sha256:f332f0e72a5a0400141f830744e141bf9f97917878dbe968669e8a7fefea78ff \
|
| 684 |
+
--hash=sha256:f7b0ec93a2893de856652154d73b7ba622f26fa97726487dcac373de5f4c6084
|
| 685 |
+
# via pydantic
|
| 686 |
+
pygments==2.21.0 \
|
| 687 |
+
--hash=sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9 \
|
| 688 |
+
--hash=sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c
|
| 689 |
+
# via rich
|
| 690 |
+
python-dateutil==2.9.0.post0 \
|
| 691 |
+
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
|
| 692 |
+
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
|
| 693 |
+
# via botocore
|
| 694 |
+
python-multipart==0.0.32 \
|
| 695 |
+
--hash=sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e \
|
| 696 |
+
--hash=sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23
|
| 697 |
+
# via mlx-vlm
|
| 698 |
+
pyyaml==6.0.3 \
|
| 699 |
+
--hash=sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6 \
|
| 700 |
+
--hash=sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1 \
|
| 701 |
+
--hash=sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea \
|
| 702 |
+
--hash=sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb \
|
| 703 |
+
--hash=sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b \
|
| 704 |
+
--hash=sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c \
|
| 705 |
+
--hash=sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd \
|
| 706 |
+
--hash=sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c \
|
| 707 |
+
--hash=sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196 \
|
| 708 |
+
--hash=sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8 \
|
| 709 |
+
--hash=sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e \
|
| 710 |
+
--hash=sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28 \
|
| 711 |
+
--hash=sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5 \
|
| 712 |
+
--hash=sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5 \
|
| 713 |
+
--hash=sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc \
|
| 714 |
+
--hash=sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26 \
|
| 715 |
+
--hash=sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f \
|
| 716 |
+
--hash=sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be \
|
| 717 |
+
--hash=sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c \
|
| 718 |
+
--hash=sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6 \
|
| 719 |
+
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
|
| 720 |
+
# via
|
| 721 |
+
# huggingface-hub
|
| 722 |
+
# transformers
|
| 723 |
+
regex==2026.9.10 \
|
| 724 |
+
--hash=sha256:032da15431c890d376f53547f0a6219f4f4cd19f3e4f11bdc321453b5bd207e4 \
|
| 725 |
+
--hash=sha256:048a89ee797db10160bd2bd519286577a6b43a100279bd4b7d8456a3d69c80a0 \
|
| 726 |
+
--hash=sha256:0c32480f3371b75068decaf9e5da72c224e953830dd71e36e06cf80e30ea39d8 \
|
| 727 |
+
--hash=sha256:1562aabd9d4eb09bd88a62ad97ed06800094b529ac43419e43020b9cefec79b0 \
|
| 728 |
+
--hash=sha256:1e321e2c84f0e52c457f5ea5944f796d6e8e09cb99738ea98dcc1bfe402a128d \
|
| 729 |
+
--hash=sha256:20e8bfb07ad79a282f8b95b56fe67f9750b1b7f775724e4ba1f23cb296115ce4 \
|
| 730 |
+
--hash=sha256:239620b0e0681669367c0e218c8eb2551d9f8fe3b9fccfc8d0003377804e8348 \
|
| 731 |
+
--hash=sha256:23ac9a28180f274d7dd7651fa131ad5b02d343b75df4b040737f0356223895dd \
|
| 732 |
+
--hash=sha256:2479171edccced52ef02b899558f88ab2c235fe05b93180fdcae1670aacd89e1 \
|
| 733 |
+
--hash=sha256:2e67f8843f0e4b931f1fa860bf3bbe4134b714c0155cc5c7c0d7ea450230aae0 \
|
| 734 |
+
--hash=sha256:3bdeed3318a8eb2bbadc9c56347e0ff651639e934a47e168d05a3b12929fd0e7 \
|
| 735 |
+
--hash=sha256:4c66d54042a14a503907d81861b8a5235e6d1f03d4fbc1d8767f652eaf957ac1 \
|
| 736 |
+
--hash=sha256:4db7d00c4afbfbb55b8e17b1e371da11418ea9389b030acec63c1fa4c7ad4b86 \
|
| 737 |
+
--hash=sha256:5847e22bbf959764d776937d791d034cc2d19b787e361c88d97e859e8dc68502 \
|
| 738 |
+
--hash=sha256:6aebdd9a946de328b3f6f61dbf48dd064a36eb6dddf96e34ae6651d37f6e9383 \
|
| 739 |
+
--hash=sha256:6b34a778c695d24e77c140e3b4c95da69282e34f2f6b02b55656aa4a0379f643 \
|
| 740 |
+
--hash=sha256:79e9432995e14c749d34209413de5e621ec8e67789bf4f46dbfabea9d06a2406 \
|
| 741 |
+
--hash=sha256:7abb38b8c40f3a235235a44da452c64b7b5c1d650ec6351027db0e090804f2e5 \
|
| 742 |
+
--hash=sha256:866de9f98df0611d7b62b3a8729d3284a64c0cc6edd90bb95a533e443a4939cb \
|
| 743 |
+
--hash=sha256:880ac684c27176464c00c3fdc456116364f5ebc70da07aad0c2d4a7ba45e98db \
|
| 744 |
+
--hash=sha256:b9d36b03dc362aa40ffaaec9d9bd75e87763529563ec008c43b0e07782f5be7a \
|
| 745 |
+
--hash=sha256:bafa41b0dd63669e5c0f8adf3d24819efeb73c847f492eb011212eb352e69041 \
|
| 746 |
+
--hash=sha256:bb7774924f8cd69f49cba0b3c2d679a6326f777e0e67d130ad5203e4df53f0d3 \
|
| 747 |
+
--hash=sha256:c014641157e9049b0603b8daa5343bd408d9b757b709aaa0f373cd3fab2d7944 \
|
| 748 |
+
--hash=sha256:c103b3b14e011774af4fb7e4617ad4d72b9171905cd3b231a70a4efd76e477d7 \
|
| 749 |
+
--hash=sha256:c25a754bb81a2edcfc3b65eda50f017d736f818112ed43e8aafd595cb00678ae \
|
| 750 |
+
--hash=sha256:d2d377fd1cad611b806cdd732d86b65f536c768209890cb442556548daa65a23 \
|
| 751 |
+
--hash=sha256:d8c668af8f7bdb1d18739c27d30cd9f4b371495a883f75a002fb7a39d740fecd \
|
| 752 |
+
--hash=sha256:dce932f8e3ba936475ea3d0d8b59f7b050a9e206e994f53f8fd80299871e87da \
|
| 753 |
+
--hash=sha256:e0dc78251154b66dc60211563fc115345da332eaa881e4e2523fb1edae3772f4 \
|
| 754 |
+
--hash=sha256:ebb2ba68e4641a994061f70bf44ed448fba0b9b1d18c94ffb9efc1cca805b39b \
|
| 755 |
+
--hash=sha256:ef5a059ea1c6ee5d1c7e99a2484e628608d010921efe876c6f0e2029d2f35eca \
|
| 756 |
+
--hash=sha256:f2374c27deb189b282ec7e16106752c22ad39b056bbd8018960b1e4cc95d67a1
|
| 757 |
+
# via transformers
|
| 758 |
+
requests==2.34.2 \
|
| 759 |
+
--hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \
|
| 760 |
+
--hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed
|
| 761 |
+
# via mlx-vlm
|
| 762 |
+
rich==15.0.0 \
|
| 763 |
+
--hash=sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb \
|
| 764 |
+
--hash=sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36
|
| 765 |
+
# via
|
| 766 |
+
# modal
|
| 767 |
+
# typer
|
| 768 |
+
s3transfer==0.19.2 \
|
| 769 |
+
--hash=sha256:ba0309fd86be3c27dbf78cdd813c13c5e1df16e5874b99d2535ebbdfb9892993 \
|
| 770 |
+
--hash=sha256:d8168eccca828cbb2cd573675333f3bddd254313a9c42494b84c76b539e8ba25
|
| 771 |
+
# via boto3
|
| 772 |
+
safetensors==0.8.0 \
|
| 773 |
+
--hash=sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358 \
|
| 774 |
+
--hash=sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f \
|
| 775 |
+
--hash=sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d \
|
| 776 |
+
--hash=sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d \
|
| 777 |
+
--hash=sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0 \
|
| 778 |
+
--hash=sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc \
|
| 779 |
+
--hash=sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235 \
|
| 780 |
+
--hash=sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98 \
|
| 781 |
+
--hash=sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4 \
|
| 782 |
+
--hash=sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846 \
|
| 783 |
+
--hash=sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca \
|
| 784 |
+
--hash=sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0 \
|
| 785 |
+
--hash=sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25 \
|
| 786 |
+
--hash=sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452 \
|
| 787 |
+
--hash=sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d \
|
| 788 |
+
--hash=sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78 \
|
| 789 |
+
--hash=sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774
|
| 790 |
+
# via
|
| 791 |
+
# solomon-mlx
|
| 792 |
+
# transformers
|
| 793 |
+
scipy==1.18.1 \
|
| 794 |
+
--hash=sha256:3ab3523da44749156e1f68b464dc56af11ae4cbc5c739a49d05f32b982eca9f3 \
|
| 795 |
+
--hash=sha256:3c085faa2cfa879c5141df483f836f4d691045a078224a670fa570fa01612d89 \
|
| 796 |
+
--hash=sha256:457fd7a2a8edeb044ab6ffbc0aa03ff6cd18491356e5e0c834d76ce621b916d1 \
|
| 797 |
+
--hash=sha256:52c4b7422442aba924d03ad4019852b08a92e64ea187b933135687bfe2747307 \
|
| 798 |
+
--hash=sha256:559ed65f60c1af5a03f3912605a1b5114f522c7c32fb23c3376ae8f03219fe28 \
|
| 799 |
+
--hash=sha256:5e4d44984abc0020154ea81b247adeddcc3ac5527b975ff798bd1ba0adc513c2 \
|
| 800 |
+
--hash=sha256:75b00eb8fb802090aa903f4ea1c7f5a584779f967361e68b7e98e531cc2d7174 \
|
| 801 |
+
--hash=sha256:78c0665edead396b1abb4897c41a5c1d9bf090c8a637a4c20a61678e0a264e66 \
|
| 802 |
+
--hash=sha256:7bbf207c4453ce1ad2e00b17313852b33310b83090c2311bdaf97f93c0380d12 \
|
| 803 |
+
--hash=sha256:c35d74ce0e193ff740c2f2be2ac913ddc232fe6c1ff40b26cfecb9c670c63314 \
|
| 804 |
+
--hash=sha256:c825cef2f49e46753726a7181a8e199804a912b29519ada542c6ebc654951899 \
|
| 805 |
+
--hash=sha256:cd479fc04dd9401e3b4f49e76518768ef99c4f517a98c284eb091fd725719adf \
|
| 806 |
+
--hash=sha256:d2924a03db38dc2e848bca2fe9f077dafb891480b91a00a0963a8cf86dfc31c1 \
|
| 807 |
+
--hash=sha256:d416b16cccfd70fbf62400e84d0bb2f4e6af519a45557f1692c749b37f14b315 \
|
| 808 |
+
--hash=sha256:d65d448389b8436493abcf629cc94ad0cf32aecaf06e1acca1de53cc795f2f12 \
|
| 809 |
+
--hash=sha256:e3b417bf8c2c7c16e8f58ad91db17783ec911ac16e7b50eb6eab6e809b4f5b07 \
|
| 810 |
+
--hash=sha256:e6fb6a55cc0ba97b59a1f288fb86dc6fce8bdfc0fffcbfd015e3a954bf2a2d93 \
|
| 811 |
+
--hash=sha256:e708533e8b2ae2497d65346538a7dcc92814410b25b81432eac66de0f2af8265 \
|
| 812 |
+
--hash=sha256:ea324d9dd34c38bfb9bec8ca4d1b407db97dbb74029f566b8e322b1b6fe56fe6 \
|
| 813 |
+
--hash=sha256:f55fa87b6c612ecd6b058f167c53231b1d14e412efe361d3d6e38b3631c73218 \
|
| 814 |
+
--hash=sha256:fdaf5ea890a6183d0565f51a61799d67081bd5b1cf03c5f4b3fd3732108625c9
|
| 815 |
+
# via
|
| 816 |
+
# mlx-audio
|
| 817 |
+
# solomon-mlx
|
| 818 |
+
sentencepiece==0.2.2 \
|
| 819 |
+
--hash=sha256:1edb10e520e4bddf74d85b0f5ae74cc2d60c2b448885080bfb618bc2b3a49f6b \
|
| 820 |
+
--hash=sha256:201a8e0f55501a76e08dbf2c54bc45f4642b379271e89c667d517bfbc2191f2a \
|
| 821 |
+
--hash=sha256:38111ed1f79268f399c505028023d5eaaf0ab4e5eafceb709468b0d3323e7838 \
|
| 822 |
+
--hash=sha256:3ab3f1ae98970b5590e2209341522718900ba19bcc2c207ffaa6bd417ad960c5 \
|
| 823 |
+
--hash=sha256:3d2b5e824b5622038dc7b490897efe05ebbbb9e7350fc142f3ecc8789ef9bdf6 \
|
| 824 |
+
--hash=sha256:3ec27c152a1f1b24bc9168b55a5880f3c16e2334e697da6f55a1046a22405a3d \
|
| 825 |
+
--hash=sha256:4f0603267cd15b92b68c2c0e852a441507614b70dc7773659baa6b8c214a91fd \
|
| 826 |
+
--hash=sha256:59d6588712101ccfcae9b03692be3aaae1514c2078666d7b05f15ba3a702e41b \
|
| 827 |
+
--hash=sha256:64b656f025355cf8c51abe9fbe3848540756c6d7ca5e6791b1afa664bc24c7cb \
|
| 828 |
+
--hash=sha256:72b7825b331b1b7e7c45be2e674b3e3c65af608fa376bad2d851b20aaf0cdc78 \
|
| 829 |
+
--hash=sha256:74f0ee601047c0c12a783088b51be4e6214a62ecd9e02278c477433cd16e0ed9 \
|
| 830 |
+
--hash=sha256:76ff5814db72e7462dece042d7593cdf102b8ec82c2b1cc201a2add34ee3050d \
|
| 831 |
+
--hash=sha256:77c3ce990b23441e5ecfa5bce181fd6f408b564aeb6d7e1d1e7de9c5612501c8 \
|
| 832 |
+
--hash=sha256:7c6e7bf684dc12145bfa685d3060beaea55139134ba848289bee514ed42e7383 \
|
| 833 |
+
--hash=sha256:89625fb43765cccaa1443b9adb61f283e5fe4cb1536728205d06bada730caa53 \
|
| 834 |
+
--hash=sha256:8eed98514bffe5ecac37f493f91869c351fbb05629328bfdbc08502c6c094dc0 \
|
| 835 |
+
--hash=sha256:b23fe17779834d3c27aaf2edac9486d04cca1a7deb8f5facda35150ac6263a91 \
|
| 836 |
+
--hash=sha256:c8a168b040bc61681293f79a949b5d911c8e25086f4260285b8d97ab5f1195da \
|
| 837 |
+
--hash=sha256:cbce24284f51f71d10a42b7b9c964dcb9048b28f1c8e5db40bcbcb6f428cba6a \
|
| 838 |
+
--hash=sha256:d795c4ac689a57f9d4ba2288126ec7901d389ad5827d2f8b8533c883974fe563 \
|
| 839 |
+
--hash=sha256:f7c06c751c19d923435a54bff4f7e66e728fad160e8da28254f133abc9725820 \
|
| 840 |
+
--hash=sha256:fd523c4992041faa5c2b3cde62253d11a96c30d73a34afe48a486e8e2254cd1c
|
| 841 |
+
# via mlx-vlm
|
| 842 |
+
shellingham==1.5.4 \
|
| 843 |
+
--hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \
|
| 844 |
+
--hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
|
| 845 |
+
# via typer
|
| 846 |
+
six==1.17.0 \
|
| 847 |
+
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
|
| 848 |
+
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
|
| 849 |
+
# via python-dateutil
|
| 850 |
+
sounddevice==0.5.6 \
|
| 851 |
+
--hash=sha256:7f4162f514f007b0bf25a3ccfed3f1705bc2ec311888a90232729eec4f57a4f4 \
|
| 852 |
+
--hash=sha256:8ec9fbfde2e32f020b167e348f3ab3bac6625a5f15af524d790108ac7147a410 \
|
| 853 |
+
--hash=sha256:b36b807eb02abd257198bf84b2af05e4fea199a9d2f0019014169c7136d45e9c \
|
| 854 |
+
--hash=sha256:c8ae19173e5f27f8c12d4b5eee2dbfe542cee125d591e663e0fb4dfb75246d45 \
|
| 855 |
+
--hash=sha256:de099612311ad81e55d31ccbd83f43ea6bf4d87b48f9b6ea55a1fbcde0eee4e0 \
|
| 856 |
+
--hash=sha256:e3aef00ad8b1d1740eb66d9a7671eab88a4d2b8fa4ab33498d742e63b65c309c
|
| 857 |
+
# via mlx-audio
|
| 858 |
+
starlette==1.6.0 \
|
| 859 |
+
--hash=sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c \
|
| 860 |
+
--hash=sha256:d4e3ac5e546444960c710297a3c9fc3f7ebae1b7e963f3d36173b49da535be9b
|
| 861 |
+
# via
|
| 862 |
+
# fastapi
|
| 863 |
+
# mlx-vlm
|
| 864 |
+
synchronicity==0.12.5 \
|
| 865 |
+
--hash=sha256:94d96b1d85698e3056b96a793b8c0949af6584e4a7d877fabdeb5385efe230aa \
|
| 866 |
+
--hash=sha256:fdbbb10d437bc08a6b0f814fc66fddd1b58ffed314533d42f1ab555801e781af
|
| 867 |
+
# via modal
|
| 868 |
+
tokenizers==0.23.2 \
|
| 869 |
+
--hash=sha256:12f0835dc2ee694746a76adf7b1567d4346a4a502ebe93fb1f5f80ea49799b78 \
|
| 870 |
+
--hash=sha256:2e96f5699d5249c9c64aa8412e044f727aae3a4098cf830f9901ec1afc361cde \
|
| 871 |
+
--hash=sha256:325fee2e0418a9dc6c9ecf736a5f5f0db7875183ace9549ae339da76f7a1fbb7 \
|
| 872 |
+
--hash=sha256:41c2f84d172449b4dadb9cdc508e3e364076613c35b16e76ecfe47a60d1e3305 \
|
| 873 |
+
--hash=sha256:43e4f2071e3cc8d5d86421c874aebc82659bb51a68bcdef5a0da75ee89511ccb \
|
| 874 |
+
--hash=sha256:5c56bda1511921587789163e524d196ed8284174ac23abd7685d5ea8da6c4718 \
|
| 875 |
+
--hash=sha256:7b7e37ba198f24150f523e1242e83c4970de4a525480586be5dcc24d9add32c5 \
|
| 876 |
+
--hash=sha256:7f0f085686b9de0d0079e6f874ae053600db64c5d13049e0bbc0119926d25aac \
|
| 877 |
+
--hash=sha256:85a9a357a3764aecc904ee76bdaf8cf1ad8e5a67a1b929a487c4a39b49ed0e90 \
|
| 878 |
+
--hash=sha256:950d7c9426fa72406a0ffeacdbc0bb9985f5db20eb8b263f29c79aaf83105703 \
|
| 879 |
+
--hash=sha256:986670e43691469dcee610ea0f846f91a8f84e91fc6f7a48d4c064414c0ec2bf \
|
| 880 |
+
--hash=sha256:a37039b5dfc4af84eb3ef0a92f4307e28936c8f9adccba2629d36f652e9bf7a2 \
|
| 881 |
+
--hash=sha256:bef235815a067b2648caf6dcc7a71091b0b0fff9ee8057f6451eb9335fae52ef \
|
| 882 |
+
--hash=sha256:debf978920d93ba9c219bd67cc4bbfaf912c9039e41e7a28b91ec15e3728c95a \
|
| 883 |
+
--hash=sha256:e49c394456dd9985787fec76132438ba3fb8911f857b1bf3d40119f9292d41aa \
|
| 884 |
+
--hash=sha256:eb2f9c8a24da020ea8c11a01a19c1c2547912d92121ae4a01cfbca46125dee40 \
|
| 885 |
+
--hash=sha256:f486f402f6f9abee5bb032553736813af0c710a86b2e0ca592634c55cea1f835
|
| 886 |
+
# via transformers
|
| 887 |
+
toml==0.10.2 \
|
| 888 |
+
--hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
|
| 889 |
+
--hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
|
| 890 |
+
# via modal
|
| 891 |
+
tqdm==4.70.1 \
|
| 892 |
+
--hash=sha256:c293e525e6fef9c20e8728fd4612df02a0aa31bb5fe91ecd93e123b1b7bffa73 \
|
| 893 |
+
--hash=sha256:cefd0eca11b2a37a3aee776544d4f4ae913f02688135b5556b8788dfa474afc4
|
| 894 |
+
# via
|
| 895 |
+
# huggingface-hub
|
| 896 |
+
# mlx-audio
|
| 897 |
+
# mlx-vlm
|
| 898 |
+
# transformers
|
| 899 |
+
transformers==5.17.0 \
|
| 900 |
+
--hash=sha256:78ec1ce21579b38dfb83950a0658cd119f87212a2fcfdff478096ce9d6c03801 \
|
| 901 |
+
--hash=sha256:a153be279169b55b92d8000bf4af294aed684503d091cca7804da2dd8a9de000
|
| 902 |
+
# via
|
| 903 |
+
# mlx-audio
|
| 904 |
+
# mlx-vlm
|
| 905 |
+
# solomon-mlx
|
| 906 |
+
typer==0.27.2 \
|
| 907 |
+
--hash=sha256:269b7eb9d3c202ca84b4bc9618cb04ebb43d3d4d1e567e4c768607232c05f945 \
|
| 908 |
+
--hash=sha256:b3a5fc4342d5fc8fda8fc3010b1cf117e9249aab7fae800c2eff62fd3842d97d
|
| 909 |
+
# via transformers
|
| 910 |
+
types-certifi==2021.10.8.3 \
|
| 911 |
+
--hash=sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f \
|
| 912 |
+
--hash=sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a
|
| 913 |
+
# via modal
|
| 914 |
+
types-toml==0.10.8.20260518 \
|
| 915 |
+
--hash=sha256:0e564ab05f6fde62a315b3b5a9b6624fda569399795d30a37e64705a70459303 \
|
| 916 |
+
--hash=sha256:80e10facd24fdeda9d5c672187d72be3ac284843788d67f5aae59e3e016db6fe
|
| 917 |
+
# via modal
|
| 918 |
+
typing-extensions==4.16.0 \
|
| 919 |
+
--hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \
|
| 920 |
+
--hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5
|
| 921 |
+
# via
|
| 922 |
+
# aiohttp
|
| 923 |
+
# aiosignal
|
| 924 |
+
# anyio
|
| 925 |
+
# fastapi
|
| 926 |
+
# huggingface-hub
|
| 927 |
+
# modal
|
| 928 |
+
# pydantic
|
| 929 |
+
# pydantic-core
|
| 930 |
+
# starlette
|
| 931 |
+
# synchronicity
|
| 932 |
+
# typing-inspection
|
| 933 |
+
typing-inspection==0.4.4 \
|
| 934 |
+
--hash=sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47 \
|
| 935 |
+
--hash=sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147
|
| 936 |
+
# via
|
| 937 |
+
# fastapi
|
| 938 |
+
# pydantic
|
| 939 |
+
urllib3==2.8.0 \
|
| 940 |
+
--hash=sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3 \
|
| 941 |
+
--hash=sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63
|
| 942 |
+
# via
|
| 943 |
+
# botocore
|
| 944 |
+
# requests
|
| 945 |
+
uvicorn==0.53.0 \
|
| 946 |
+
--hash=sha256:a9356f0cb89b3b8621529c5d5eebd69bfe154f4c3f68b4cf2de47e45fa855c2e \
|
| 947 |
+
--hash=sha256:e8dca71ec86dce5f04e333f0d56cdedf942446e6643b9cea1af0d6d3a02cb03e
|
| 948 |
+
# via mlx-vlm
|
| 949 |
+
watchfiles==1.2.0 \
|
| 950 |
+
--hash=sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9 \
|
| 951 |
+
--hash=sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98 \
|
| 952 |
+
--hash=sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f \
|
| 953 |
+
--hash=sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427 \
|
| 954 |
+
--hash=sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4 \
|
| 955 |
+
--hash=sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa \
|
| 956 |
+
--hash=sha256:2581a94056e55d7d0a31a823ea92bf73749c489ca2285bfdc0fbe6b2bb49d50c \
|
| 957 |
+
--hash=sha256:2995c176de7692b86a2e4c58d9ec718f753150a979cb4a754e2b4ffa38e70906 \
|
| 958 |
+
--hash=sha256:2cb93af48550faf1cea04c303107c8b75833de7013e57ce27d3b8d21d8d0f58c \
|
| 959 |
+
--hash=sha256:2d95ddc1eb6914154253d239089900813f6a767e174b8e6a50e7fdacb7e4236c \
|
| 960 |
+
--hash=sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077 \
|
| 961 |
+
--hash=sha256:41bc1199f7523b3f82843c88cbb979180c949caef0342cf90968f178e5d49b01 \
|
| 962 |
+
--hash=sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9 \
|
| 963 |
+
--hash=sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658 \
|
| 964 |
+
--hash=sha256:56d8641cf834c2836922899105bd3ce3d0dfc69291d52edf0b4d0436829b34c0 \
|
| 965 |
+
--hash=sha256:7571e4464cb6e434958f867f7f730b8ab0b75e3f8e5eac0499168486ab3c33a8 \
|
| 966 |
+
--hash=sha256:7a2cffd17d27d2ecbb310c2b1d8174f222a5495b1a721894afa88ec11e25b898 \
|
| 967 |
+
--hash=sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44 \
|
| 968 |
+
--hash=sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5 \
|
| 969 |
+
--hash=sha256:8f70d8b291ef6e88d19b1f297a6905ddb978888d9272b0d05e6f53309856bcfc \
|
| 970 |
+
--hash=sha256:8fa585ede612ee9f9e91b18bebf9ba11b9ae29a4e3a0d0cf6fca3e382133f0d5 \
|
| 971 |
+
--hash=sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9 \
|
| 972 |
+
--hash=sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0 \
|
| 973 |
+
--hash=sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55 \
|
| 974 |
+
--hash=sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb \
|
| 975 |
+
--hash=sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0 \
|
| 976 |
+
--hash=sha256:bc13eb17538be00c874699dc0abe4ee2bc8d50bb1166a6b9e175ef3fd7eb8f26 \
|
| 977 |
+
--hash=sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3 \
|
| 978 |
+
--hash=sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838 \
|
| 979 |
+
--hash=sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71 \
|
| 980 |
+
--hash=sha256:d20029a60a71a052a24c4db7673bc4de39ab89adbaccbfb5d67987c5d73f424d \
|
| 981 |
+
--hash=sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44 \
|
| 982 |
+
--hash=sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2 \
|
| 983 |
+
--hash=sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5 \
|
| 984 |
+
--hash=sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799 \
|
| 985 |
+
--hash=sha256:f155b3a1b2a5fc89cdc70d47ee5d54e3b75e88efa34982028a35daef9ba00379 \
|
| 986 |
+
--hash=sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925 \
|
| 987 |
+
--hash=sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72 \
|
| 988 |
+
--hash=sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08 \
|
| 989 |
+
--hash=sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4
|
| 990 |
+
# via modal
|
| 991 |
+
websockets==17.1 \
|
| 992 |
+
--hash=sha256:00bf34b64501e3477e81fc281532ff3cbf4da26633c10b63979d5085d46602d3 \
|
| 993 |
+
--hash=sha256:0340bbef6bfbe16da888b3983d666a4db4954ac3253c38f13bc7aba0c7db5a2f \
|
| 994 |
+
--hash=sha256:073c5c3f7e127041fa9d34a9e29ceefee8c3cafbd267ed2927318f425144380d \
|
| 995 |
+
--hash=sha256:0c863507ada5805517ca6dff1c524dcd42942efe6304dacf06700878398d21a6 \
|
| 996 |
+
--hash=sha256:0de501b7f2db11e83739ac20e2d33d46da4604b829f506c24be80e7def069391 \
|
| 997 |
+
--hash=sha256:1fce0f43e0d41422e0b2cad6561e1970df22f212f4c7e884967df7cf591b031c \
|
| 998 |
+
--hash=sha256:29176d8b429cfa0fa443c473878d37a5c06cfd0cb36b71ba4314accc71e05906 \
|
| 999 |
+
--hash=sha256:2a0162a6372110a5601cb5c9fd826635cedf69f3e110c545dd19774e040b970e \
|
| 1000 |
+
--hash=sha256:2afb58c7ba48b329d56769f8dfd89f394efe587b65ef806bae810a484d6d3608 \
|
| 1001 |
+
--hash=sha256:3709a1ab30b4b922027d22f68d2b61a0656a91680ac894a537624e6be7dd7f7c \
|
| 1002 |
+
--hash=sha256:4031152769179ab8dcdeafc7b0e58052a49117560a28671700b47b2c7b717aad \
|
| 1003 |
+
--hash=sha256:43bd0c1ceb924d67f5c1a5254d8361dd9d94246e6331a726064dfa2917880780 \
|
| 1004 |
+
--hash=sha256:581fa678ef46f4277cc8491312468e582f8ad609dbab907ba6096a08c6a0ff98 \
|
| 1005 |
+
--hash=sha256:5aefe78e6a3077fe22b5e64b04666a85a3eb8b934d40e8595a693adcbceb6f11 \
|
| 1006 |
+
--hash=sha256:5f051f8030a51815dc00e24bd2e5f1435af095c1cc111d747ac6e2a3620d7641 \
|
| 1007 |
+
--hash=sha256:617243e19a0992095956f406ee9cd3bc4ba92862d83cb1d83bb59ce574412bec \
|
| 1008 |
+
--hash=sha256:655a8e28010f09fd6fa317e857afab3af7647f33e41dee88fa421e92086d1090 \
|
| 1009 |
+
--hash=sha256:677014a073bcb1fbaa7e21144786864f16c08f856d66834f611eceb9006cbab8 \
|
| 1010 |
+
--hash=sha256:76dd004f59115087c7b700474cb18f01325e37250032e19396c08ae41448e4b3 \
|
| 1011 |
+
--hash=sha256:77b37cceca17291897c3c73bd30a7c7c7909593554b5da574ec852af83c1742a \
|
| 1012 |
+
--hash=sha256:7a72efa3bf4fa3a6669a54420a472ad056da3973d827f10e3a536da463f926c2 \
|
| 1013 |
+
--hash=sha256:7e724f843fa6a0614aece65a7c73e51d0f4412ca41dccac13c3caf98e69536bb \
|
| 1014 |
+
--hash=sha256:829dba1bc049779de9b332088c1a6a9858e96bd67e50b6b644a95e02b67836bc \
|
| 1015 |
+
--hash=sha256:87f0d5e77548b0c40c8464cdb6108792e7e53f487c6400028a4ec28a8afbe5ab \
|
| 1016 |
+
--hash=sha256:882af300d2c6a092b93767d5de03c7bb56dfb06314140c8e872d3f48e09f7b74 \
|
| 1017 |
+
--hash=sha256:9f4a08ff7cb68c27b18e09223cc6304e01d0f82d5a240d251266dfd2e6e44729 \
|
| 1018 |
+
--hash=sha256:9f4c0377a83e163a303514fdfab501dbe379bdc13e5b9312a91d112658b29dce \
|
| 1019 |
+
--hash=sha256:a06f3b5085176763182449559e20391d7ce616a8972a9f7a33deda87ea6d4f3c \
|
| 1020 |
+
--hash=sha256:acfea4c20bf54384883ea33b1240fc1db4f52e190823a4e2b334bc3e8bfca96a \
|
| 1021 |
+
--hash=sha256:c3241d684a76eaaef8b2dc789afde4343cd3aad55ea81e4e8ab3605b529bae51 \
|
| 1022 |
+
--hash=sha256:ccbf3f4a9890d50b3a08ee04029fde30a03bfdeffaa19977628bf17251764e60 \
|
| 1023 |
+
--hash=sha256:ce0305b702b20d1e1d60a9aaace6bc89970e1753565543f310d549eab22c2435 \
|
| 1024 |
+
--hash=sha256:d41ef69d5416fbc1d98cf96c37be6192d10fd101c3e0f8b3ddc36e09432b3c08 \
|
| 1025 |
+
--hash=sha256:d8e83333385cac6030a5167fd18bf96cc6c58b914c308e683f05b0cf94bc8dd0 \
|
| 1026 |
+
--hash=sha256:dc2b79afc074d2f3e64b26539350f697fe1b85ea1c49ea24eb588f247b053ce1 \
|
| 1027 |
+
--hash=sha256:e4bd7eacb87d8cf3ed70d6392c770a0d92441f05d7d2a3efafb5bc171d5e3067 \
|
| 1028 |
+
--hash=sha256:e5f5c7a893507d0e83a80b88aefd6522f7e882cd53f9722c6f23f5a020c9557c \
|
| 1029 |
+
--hash=sha256:eec113a5b41d124ef42ff56b0d74a6da3fd986400038eab9e58ee42a4024e837 \
|
| 1030 |
+
--hash=sha256:f221081107b8c48184d99f7019604486376e7ef826037e70aad6b02540732c23 \
|
| 1031 |
+
--hash=sha256:f62114a54117e4948a1e414e89521f7fe1e3c2f83f2a571a06a4fc6718b0900a \
|
| 1032 |
+
--hash=sha256:f64e001bb7fa89b9f32cfa600bf8e9ac8ca26759d9b92ae01453ee303d9cd7b4 \
|
| 1033 |
+
--hash=sha256:fd8f47dbf2e8adb15c847215f83436de3fdb120b51fdae0fbbdf69fd97a3ad80
|
| 1034 |
+
# via mlx-vlm
|
| 1035 |
+
yarl==1.25.1 \
|
| 1036 |
+
--hash=sha256:03dd38de09bc213e9a8b29761eec33ee1d5318dac0e49d8af36e4d27830e23a7 \
|
| 1037 |
+
--hash=sha256:0a66db89ea473abeac4b70523cafd94db3772380e565f9d28af7a179b7af71fa \
|
| 1038 |
+
--hash=sha256:0f12afda4eea8c8994a76d4df1875c765194f5fbe8a9d197929ea303caee29ec \
|
| 1039 |
+
--hash=sha256:10b2fd95332f0d716d5eee3c9fb2ce8eada19082de7fee83d32e37992fd75c26 \
|
| 1040 |
+
--hash=sha256:126a2533570c554719ca40a1288fdee1700b6bc82e7131aa69fa85252d92e651 \
|
| 1041 |
+
--hash=sha256:14b79a30a93a3ce2e8832603fd0ab780ada281b0ba5110b519a634f2d7d7d1fc \
|
| 1042 |
+
--hash=sha256:1f51020b2eb8a003c84925638ec63c21a750a4bddd3a22ec8eac6a742dadf1b9 \
|
| 1043 |
+
--hash=sha256:25868beca8b6765f8f7d0e11fe6dd7c66dd4b0793b9500286d20cc92352126a5 \
|
| 1044 |
+
--hash=sha256:2b49375d22299b0a834c2bca72f39aaecc270d96fb24c30424899676f487b22a \
|
| 1045 |
+
--hash=sha256:3feb99222553a8cbedfa52c2f59dd84c3f50d5b582c728d522caf8d72769a54b \
|
| 1046 |
+
--hash=sha256:419f392a1da624877975709e3864dfe833af6cc7671b39318086d456e288380c \
|
| 1047 |
+
--hash=sha256:4bd6340d20ae2c7ca719b87b426e808e90743b676d05d4c26c4fb5ca71f41184 \
|
| 1048 |
+
--hash=sha256:4d781294bb815ecb5ea57ff6bbf8038e0a31a95fdf3e1788f66e0dc100d64b58 \
|
| 1049 |
+
--hash=sha256:681c758b0490f9e96b78e5fa8e8dc6e648e9185bb6eaebe73183c33ea0c445f3 \
|
| 1050 |
+
--hash=sha256:68782fdb4027b8d1eee25ec35e9a6db05e863b899eb0310b3a33b6c3fef55707 \
|
| 1051 |
+
--hash=sha256:7d575b54cb3863ef9bc290ea4b009999d55dc237326131e4853cf33e888fee03 \
|
| 1052 |
+
--hash=sha256:7e4de3ac4adbad3d0bc7c6f4360a7dbff5de2f15e3b723be3198074e17fd9c40 \
|
| 1053 |
+
--hash=sha256:80e47012e730da131c9f059c80936783f9659aae22dc31c03c0595590d11ed54 \
|
| 1054 |
+
--hash=sha256:83d4a37e4b95da4d8bda930d6d35b75b4cdadbacbb4980cae290ea3100b5d51d \
|
| 1055 |
+
--hash=sha256:94d7aa6debf92a1dd14cb5280b083a764169a13cfb23a452111160274ed989f4 \
|
| 1056 |
+
--hash=sha256:a2ed0ba415ccdf08f14bf544cb78346d0f76086707ffee24921a2c84dbf1305a \
|
| 1057 |
+
--hash=sha256:a3faadac7d812ddac258feb57b9846b60c1b437c4f4b9ad42595c6f6fe4390df \
|
| 1058 |
+
--hash=sha256:af4ea5b37403ef4e30f3927eaed540db942bde01d8d3ff083527c0704d1c9c68 \
|
| 1059 |
+
--hash=sha256:b10dd0557ba422715b5206b3743192135a6022acca8baec51aa127d0a75db8fe \
|
| 1060 |
+
--hash=sha256:bc3ac7bf569f6b64dad04dd7808c7872dae8a97df657856eac05e9b7e3614a85 \
|
| 1061 |
+
--hash=sha256:be80550d9bfe83d9b62398a37081a90434e6df2d978ec345c3d2820de6beddab \
|
| 1062 |
+
--hash=sha256:c6f117789d22dce188e5754e8bc65b7e6ebf8cb73963b9fa761f672a5883769d \
|
| 1063 |
+
--hash=sha256:cce0727fd5ac04d372fa9bbfde9febc2bcf209aadfcf0468e45dec72719895d1 \
|
| 1064 |
+
--hash=sha256:e029648f9c951db30e98a7d7ec90835db88ec4b32820efe2a9bdc2287e032eb6 \
|
| 1065 |
+
--hash=sha256:e07595c7d6f4db270ceede356a1bd1c07a34f1c26f958d1ed0cd7b48e0d2bba3 \
|
| 1066 |
+
--hash=sha256:e12c538e00e7c1b286a07061046b90e8124e6a9793efae2c70db6a4aad07faad \
|
| 1067 |
+
--hash=sha256:e546fe1d4a93ebc2910f0d768baff19faa09843ab3f2036a67ed6e69fae4419d \
|
| 1068 |
+
--hash=sha256:e80f557716fd765439577131e526b8942ffc2c07bdbc5e39fa62f660ba1e963f \
|
| 1069 |
+
--hash=sha256:eb96ed1ae6c7d072d60840c0434aef07a2df611812810807fbc54263a6053e9a \
|
| 1070 |
+
--hash=sha256:ef74070ac553c59eb4f04258722066d6c6135b7baa03b2e9f2da65c096e96d98 \
|
| 1071 |
+
--hash=sha256:f61964f235a43738bfac50da46fc4254943a7eea3051aeb0b6fc7c992c29fadc
|
| 1072 |
+
# via aiohttp
|
mlx/requirements.lock
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiohappyeyeballs==2.7.1
|
| 2 |
+
aiohttp==3.14.3
|
| 3 |
+
aiosignal==1.4.0
|
| 4 |
+
annotated-doc==0.0.5
|
| 5 |
+
annotated-types==0.8.0
|
| 6 |
+
anyio==4.15.1
|
| 7 |
+
attrs==26.1.0
|
| 8 |
+
cbor2==6.1.4
|
| 9 |
+
certifi==2026.7.22
|
| 10 |
+
cffi==2.1.1
|
| 11 |
+
charset-normalizer==3.5.1
|
| 12 |
+
click==8.5.0
|
| 13 |
+
fastapi==0.141.1
|
| 14 |
+
filelock==4.0.1
|
| 15 |
+
frozenlist==1.8.0
|
| 16 |
+
fsspec==2026.9.0
|
| 17 |
+
grpclib==0.4.9
|
| 18 |
+
h11==0.16.0
|
| 19 |
+
h2==4.4.1
|
| 20 |
+
hf-xet==1.6.0
|
| 21 |
+
hpack==4.2.0
|
| 22 |
+
httpcore==1.0.9
|
| 23 |
+
httpx==0.28.1
|
| 24 |
+
huggingface-hub==1.32.0
|
| 25 |
+
hyperframe==6.1.0
|
| 26 |
+
idna==3.20
|
| 27 |
+
iniconfig==2.3.0
|
| 28 |
+
jinja2==3.1.6
|
| 29 |
+
llguidance==1.8.0
|
| 30 |
+
markdown-it-py==4.2.0
|
| 31 |
+
markupsafe==3.0.3
|
| 32 |
+
mdurl==0.1.2
|
| 33 |
+
miniaudio==1.71
|
| 34 |
+
mlx==0.32.2
|
| 35 |
+
mlx-audio==0.5.4
|
| 36 |
+
mlx-metal==0.32.2
|
| 37 |
+
mlx-vlm==0.7.1
|
| 38 |
+
modal==1.5.5
|
| 39 |
+
multidict==6.9.0
|
| 40 |
+
numpy==2.5.3
|
| 41 |
+
opencv-python==5.0.0.93
|
| 42 |
+
packaging==26.3
|
| 43 |
+
pillow==12.3.0
|
| 44 |
+
pluggy==1.6.0
|
| 45 |
+
propcache==0.5.4
|
| 46 |
+
protobuf==6.33.6
|
| 47 |
+
pycparser==3.0
|
| 48 |
+
pydantic==2.13.5
|
| 49 |
+
pydantic-core==2.46.5
|
| 50 |
+
pygments==2.21.0
|
| 51 |
+
pytest==9.1.1
|
| 52 |
+
python-multipart==0.0.32
|
| 53 |
+
pyyaml==6.0.3
|
| 54 |
+
regex==2026.9.10
|
| 55 |
+
requests==2.34.2
|
| 56 |
+
rich==15.0.0
|
| 57 |
+
ruff==0.16.8
|
| 58 |
+
safetensors==0.8.0
|
| 59 |
+
scipy==1.18.1
|
| 60 |
+
sentencepiece==0.2.2
|
| 61 |
+
shellingham==1.5.4
|
| 62 |
+
-e .
|
| 63 |
+
sounddevice==0.5.6
|
| 64 |
+
starlette==1.6.0
|
| 65 |
+
synchronicity==0.12.5
|
| 66 |
+
tokenizers==0.23.2
|
| 67 |
+
toml==0.10.2
|
| 68 |
+
tqdm==4.70.1
|
| 69 |
+
transformers==5.17.0
|
| 70 |
+
typer==0.27.2
|
| 71 |
+
types-certifi==2021.10.8.3
|
| 72 |
+
types-toml==0.10.8.20260518
|
| 73 |
+
typing-extensions==4.16.0
|
| 74 |
+
typing-inspection==0.4.4
|
| 75 |
+
urllib3==2.8.0
|
| 76 |
+
uvicorn==0.53.0
|
| 77 |
+
watchfiles==1.2.0
|
| 78 |
+
websockets==17.1
|
| 79 |
+
yarl==1.25.1
|
mlx/scripts/benchmark.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Full-model parity and measurements on this Mac; emits no simulated hardware results."""
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import time
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
import mlx.core as mx
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from solomon_mlx import Solomon
|
| 12 |
+
from solomon_mlx._vendor.semantics import listed_probs, p_yes
|
| 13 |
+
from solomon_mlx.artifacts import digest, sha256
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def probabilities(job, row):
|
| 17 |
+
if job["task"] in ("boolean", "multilabel", "entity"):
|
| 18 |
+
p = p_yes(row["letter_logits"])
|
| 19 |
+
return np.array([p, 1 - p])
|
| 20 |
+
n = job["n"] - 2 if job["head_key"].endswith("choiceR") else job["n"]
|
| 21 |
+
return listed_probs(row["letter_logits"], n)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def run(model_dir, jobs_path, reference_path, output):
|
| 25 |
+
output = Path(output)
|
| 26 |
+
if output.exists():
|
| 27 |
+
raise FileExistsError("Benchmark outputs are immutable")
|
| 28 |
+
jobs = json.loads(Path(jobs_path).read_text())
|
| 29 |
+
reference = json.loads(Path(reference_path).read_text())
|
| 30 |
+
ref = {r["id"]: r for r in reference["rows"]}
|
| 31 |
+
if set(ref) != {j["id"] for j in jobs}:
|
| 32 |
+
raise ValueError("Benchmark and reference jobs differ")
|
| 33 |
+
mx.reset_peak_memory()
|
| 34 |
+
started = time.perf_counter()
|
| 35 |
+
model = Solomon.load(model_dir)
|
| 36 |
+
load_seconds = time.perf_counter() - started
|
| 37 |
+
states = {}
|
| 38 |
+
rows = []
|
| 39 |
+
prefills = []
|
| 40 |
+
try:
|
| 41 |
+
for job in jobs:
|
| 42 |
+
key = digest(job["parts"])
|
| 43 |
+
if key not in states:
|
| 44 |
+
state = model.prefill(job["parts"])
|
| 45 |
+
states[key] = state
|
| 46 |
+
prefills.append(
|
| 47 |
+
{
|
| 48 |
+
"document": key,
|
| 49 |
+
"tokens": state.prefix_tokens,
|
| 50 |
+
"seconds": state._data["prefill_seconds"],
|
| 51 |
+
"vision_seconds": state._data["vision_seconds"],
|
| 52 |
+
"cache_bytes": sum(c.nbytes for c in state._data["cache"]),
|
| 53 |
+
}
|
| 54 |
+
)
|
| 55 |
+
state = states[key]
|
| 56 |
+
row = model.engine.ask(
|
| 57 |
+
state._data,
|
| 58 |
+
job["block"],
|
| 59 |
+
job["n"],
|
| 60 |
+
job["head_key"],
|
| 61 |
+
execution=job.get("execution", "cached"),
|
| 62 |
+
taps=job.get("taps", []),
|
| 63 |
+
)
|
| 64 |
+
p, q = probabilities(job, row), probabilities(job, ref[job["id"]])
|
| 65 |
+
row.update(
|
| 66 |
+
id=job["id"],
|
| 67 |
+
decision_agrees=bool(p.argmax() == q.argmax()),
|
| 68 |
+
max_probability_drift=float(np.max(np.abs(p - q))),
|
| 69 |
+
max_logit_drift=float(
|
| 70 |
+
np.max(np.abs(np.array(row["letter_logits"]) - ref[job["id"]]["letter_logits"]))
|
| 71 |
+
),
|
| 72 |
+
prefix_ids_exact=state._data["prefix_ids"] == ref[job["id"]]["prefix_ids"],
|
| 73 |
+
)
|
| 74 |
+
if "token_ids" in row:
|
| 75 |
+
row["token_ids_exact"] = row["token_ids"] == ref[job["id"]]["token_ids"]
|
| 76 |
+
if row.get("taps"):
|
| 77 |
+
row["layer_max_hidden_drift"] = {
|
| 78 |
+
k: float(np.max(np.abs(np.array(v) - ref[job["id"]]["taps"][k])))
|
| 79 |
+
for k, v in row["taps"].items()
|
| 80 |
+
}
|
| 81 |
+
rows.append(row)
|
| 82 |
+
print(job["id"], row["seconds"], row["decision_agrees"], flush=True)
|
| 83 |
+
# Replay checks real prefill and repeated question semantics on the same binding.
|
| 84 |
+
first = states[digest(jobs[0]["parts"])]
|
| 85 |
+
recipe = output.with_suffix(".replay.json")
|
| 86 |
+
first.save(recipe)
|
| 87 |
+
with model.replay(recipe) as restored:
|
| 88 |
+
b, n, h = jobs[0]["block"], jobs[0]["n"], jobs[0]["head_key"]
|
| 89 |
+
replay = model.engine.ask(restored._data, b, n, h)
|
| 90 |
+
replay_drift = float(np.max(np.abs(np.array(replay["letter_logits"]) - rows[0]["letter_logits"])))
|
| 91 |
+
finally:
|
| 92 |
+
for state in states.values():
|
| 93 |
+
state.close()
|
| 94 |
+
warm = [r["seconds"] for r in rows if r["reused_prefix_tokens"]]
|
| 95 |
+
report = {
|
| 96 |
+
"runtime": model.identity,
|
| 97 |
+
"device": mx.device_info(),
|
| 98 |
+
"jobs_sha256": sha256(jobs_path),
|
| 99 |
+
"reference_sha256": sha256(reference_path),
|
| 100 |
+
"load_seconds": load_seconds,
|
| 101 |
+
"prefills": prefills,
|
| 102 |
+
"rows": rows,
|
| 103 |
+
"warm_question_latency_median_seconds": float(np.median(warm)),
|
| 104 |
+
"questions_per_second": len(warm) / sum(warm),
|
| 105 |
+
"peak_metal_bytes": mx.get_peak_memory(),
|
| 106 |
+
"replay_max_logit_drift": replay_drift,
|
| 107 |
+
"decision_agreement": float(np.mean([r["decision_agrees"] for r in rows])),
|
| 108 |
+
"scope": "development parity fixtures; not held-out task accuracy or release qualification",
|
| 109 |
+
"calibration_status": "uncalibrated",
|
| 110 |
+
}
|
| 111 |
+
output.write_text(json.dumps(report, indent=2))
|
| 112 |
+
return report
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
if __name__ == "__main__":
|
| 116 |
+
p = argparse.ArgumentParser()
|
| 117 |
+
p.add_argument("--model", default="models/quality")
|
| 118 |
+
p.add_argument("--jobs", default="evaluations/golden-jobs.json")
|
| 119 |
+
p.add_argument("--reference", default="evaluations/bf16-reference-1789901869/report.json")
|
| 120 |
+
p.add_argument("--output", default="evaluations/bf16-text-benchmark.json")
|
| 121 |
+
a = p.parse_args()
|
| 122 |
+
run(a.model, a.jobs, a.reference, a.output)
|
mlx/scripts/benchmark_chunks.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Measure 512/1024/2048-token prefill on frozen original acceptance documents."""
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import time
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
import mlx.core as mx
|
| 9 |
+
|
| 10 |
+
from solomon_mlx import Solomon
|
| 11 |
+
|
| 12 |
+
p = argparse.ArgumentParser()
|
| 13 |
+
p.add_argument("--model", default="models/quality")
|
| 14 |
+
p.add_argument("--output", default="evaluations/chunk-benchmark.json")
|
| 15 |
+
a = p.parse_args()
|
| 16 |
+
out = Path(a.output)
|
| 17 |
+
if out.exists():
|
| 18 |
+
raise FileExistsError("Use a new immutable benchmark output")
|
| 19 |
+
model = Solomon.load(a.model)
|
| 20 |
+
fixtures = json.loads(Path("evaluations/cuda-acceptance/input/documents.json").read_text())
|
| 21 |
+
results = []
|
| 22 |
+
for document, parts in fixtures["documents"].items():
|
| 23 |
+
for target in (1242, 2048):
|
| 24 |
+
text = "".join(p["text"] for p in parts)
|
| 25 |
+
while True:
|
| 26 |
+
rendered = model.engine.render([{"text": text}], "X")
|
| 27 |
+
end = rendered.rfind("\n\nX")
|
| 28 |
+
length = len(model.engine.t.encode(rendered[:end], add_special_tokens=False)) - 1
|
| 29 |
+
if length >= target:
|
| 30 |
+
break
|
| 31 |
+
text += fixtures["filler"]
|
| 32 |
+
for chunk in (512, 1024, 2048):
|
| 33 |
+
model.engine.chunk_size = chunk
|
| 34 |
+
mx.reset_peak_memory()
|
| 35 |
+
started = time.perf_counter()
|
| 36 |
+
with model.prefill(text) as state:
|
| 37 |
+
results.append(
|
| 38 |
+
{
|
| 39 |
+
"document": document,
|
| 40 |
+
"chunk": chunk,
|
| 41 |
+
"tokens": state.prefix_tokens,
|
| 42 |
+
"seconds": time.perf_counter() - started,
|
| 43 |
+
"peak_metal_bytes": mx.get_peak_memory(),
|
| 44 |
+
"cache_bytes": sum(c.nbytes for c in state._data["cache"]),
|
| 45 |
+
}
|
| 46 |
+
)
|
| 47 |
+
print(results[-1], flush=True)
|
| 48 |
+
out.write_text(
|
| 49 |
+
json.dumps({"runtime": model.identity, "measurements": results, "hardware_simulation": False}, indent=2)
|
| 50 |
+
)
|
mlx/scripts/check_cuda_parity.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Compare saved MLX scores with CUDA using identical, frozen temperatures.
|
| 2 |
+
|
| 3 |
+
No fitting, parameter selection, or changes to inference weights take place.
|
| 4 |
+
Partial panels are diagnostic only and can never qualify a release.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import argparse
|
| 8 |
+
import json
|
| 9 |
+
from collections import defaultdict
|
| 10 |
+
from pathlib import Path
|
| 11 |
+
|
| 12 |
+
import numpy as np
|
| 13 |
+
|
| 14 |
+
from solomon_mlx._vendor.semantics import listed_probs, p_yes
|
| 15 |
+
from solomon_mlx.api import TASKS
|
| 16 |
+
from solomon_mlx.artifacts import digest, runtime_identity, sha256
|
| 17 |
+
from solomon_mlx.evaluation import compare_rows, load_panel, read_cuda_scores
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def decision_probabilities(row, temperature):
|
| 21 |
+
"""Parity includes every branch, even when its gold label is not a listed option."""
|
| 22 |
+
if row["task"] in ("boolean", "entity", "multilabel"):
|
| 23 |
+
p = p_yes(row["letter_logits"], temperature)
|
| 24 |
+
return np.array([1 - p, p])
|
| 25 |
+
width = row["n"] - 2 if row["head_key"].endswith("choiceR") else row["n"]
|
| 26 |
+
return listed_probs(row["letter_logits"], width, temperature)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def compare(panel, scores, cuda_directory, reference, output, *, allow_partial=False):
|
| 30 |
+
panel, scores, output = Path(panel), Path(scores), Path(output)
|
| 31 |
+
if output.exists():
|
| 32 |
+
raise FileExistsError("Parity reports are immutable")
|
| 33 |
+
jobs, manifest = load_panel(panel)
|
| 34 |
+
identity = json.loads((scores / "identity.json").read_text())
|
| 35 |
+
model_binding = json.loads(Path("models/quality/binding.json").read_text())
|
| 36 |
+
if identity["runtime"] != runtime_identity(model_binding):
|
| 37 |
+
raise ValueError("Scores belong to another MLX runtime")
|
| 38 |
+
if identity["panel_sha256"] != manifest["jobs_sha256"]:
|
| 39 |
+
raise ValueError("Scores belong to another panel")
|
| 40 |
+
groups = defaultdict(list)
|
| 41 |
+
for job in jobs:
|
| 42 |
+
groups[job["document_key"]].append(job)
|
| 43 |
+
rows, files = [], {}
|
| 44 |
+
for key, group in groups.items():
|
| 45 |
+
path = scores / (key + ".json")
|
| 46 |
+
if not path.exists() and allow_partial:
|
| 47 |
+
continue
|
| 48 |
+
record = json.loads(path.read_text())
|
| 49 |
+
body = {k: v for k, v in record.items() if k != "sha256"}
|
| 50 |
+
if (
|
| 51 |
+
record["sha256"] != digest(body)
|
| 52 |
+
or record["identity"] != digest(identity)
|
| 53 |
+
or [r["id"] for r in record["rows"]] != [r["id"] for r in group]
|
| 54 |
+
):
|
| 55 |
+
raise ValueError("Corrupt or mismatched score document")
|
| 56 |
+
rows.extend(record["rows"])
|
| 57 |
+
files[path.name] = sha256(path)
|
| 58 |
+
complete = len(files) == len(groups)
|
| 59 |
+
if not allow_partial:
|
| 60 |
+
marker = json.loads((scores / "complete.json").read_text())
|
| 61 |
+
if marker != {
|
| 62 |
+
"identity": digest(identity),
|
| 63 |
+
"documents": len(groups),
|
| 64 |
+
"branches": len(jobs),
|
| 65 |
+
"files": files,
|
| 66 |
+
}:
|
| 67 |
+
raise ValueError("Incomplete or mismatched completion manifest")
|
| 68 |
+
ref = json.loads(Path(reference).read_text())
|
| 69 |
+
cuda = read_cuda_scores(cuda_directory, panel, ref["identity"])
|
| 70 |
+
selected = {r["id"] for r in rows}
|
| 71 |
+
cuda = [r for r in cuda if r["id"] in selected]
|
| 72 |
+
binding_path = Path("evaluations/cuda-acceptance/input/serving-binding.json")
|
| 73 |
+
source_manifest = json.loads((binding_path.parent / "manifest.json").read_text())
|
| 74 |
+
if sha256(binding_path) != source_manifest["files"][binding_path.name]:
|
| 75 |
+
raise ValueError("CUDA acceptance binding checksum mismatch")
|
| 76 |
+
binding = json.loads(binding_path.read_text())
|
| 77 |
+
for key in (
|
| 78 |
+
"adapter_sha256",
|
| 79 |
+
"trained_heads_sha256",
|
| 80 |
+
"model_sha256",
|
| 81 |
+
"numerics",
|
| 82 |
+
"placement",
|
| 83 |
+
"arithmetic",
|
| 84 |
+
):
|
| 85 |
+
if binding["runtime"][key] != ref["identity"][key]:
|
| 86 |
+
raise ValueError("CUDA temperatures belong to another reference")
|
| 87 |
+
temperatures = {task: binding["temperatures"]["models"][task]["temperature"] for task in TASKS}
|
| 88 |
+
comparisons = {}
|
| 89 |
+
cuda_by_id = {r["id"]: r for r in cuda}
|
| 90 |
+
for name, temps in (("temperature_one", dict.fromkeys(TASKS, 1.0)), ("cuda_serving", temperatures)):
|
| 91 |
+
result = compare_rows(rows, cuda, temperatures=temps, reference_temperatures=temps)
|
| 92 |
+
result.pop("quality_gate_passed")
|
| 93 |
+
result["accuracy_units"] = result["units"]
|
| 94 |
+
result["accuracy_questions"] = result["questions"]
|
| 95 |
+
worst, questions = [], defaultdict(list)
|
| 96 |
+
for row in rows:
|
| 97 |
+
other = {**row, "letter_logits": cuda_by_id[row["id"]]["letter_logits"]}
|
| 98 |
+
p = decision_probabilities(row, temps[row["task"]])
|
| 99 |
+
q = decision_probabilities(other, temps[row["task"]])
|
| 100 |
+
if not np.isfinite(p).all() or not np.isfinite(q).all():
|
| 101 |
+
raise ValueError("Nonfinite parity probability")
|
| 102 |
+
agrees = int(np.argmax(p)) == int(np.argmax(q))
|
| 103 |
+
questions[row["question_id"]].append(agrees)
|
| 104 |
+
worst.append(
|
| 105 |
+
{
|
| 106 |
+
"id": row["id"],
|
| 107 |
+
"task": row["task"],
|
| 108 |
+
"max_probability_drift": float(np.max(np.abs(p - q))),
|
| 109 |
+
"decision_agrees": agrees,
|
| 110 |
+
}
|
| 111 |
+
)
|
| 112 |
+
result.update(
|
| 113 |
+
units=len(rows),
|
| 114 |
+
questions=len(questions),
|
| 115 |
+
unit_decision_agreement=float(np.mean([r["decision_agrees"] for r in worst])),
|
| 116 |
+
question_decision_agreement=float(np.mean([all(v) for v in questions.values()])),
|
| 117 |
+
max_probability_drift=max(r["max_probability_drift"] for r in worst),
|
| 118 |
+
mean_probability_drift=float(np.mean([r["max_probability_drift"] for r in worst])),
|
| 119 |
+
)
|
| 120 |
+
result["agreement_gate_passed"] = (
|
| 121 |
+
result["unit_decision_agreement"] >= 0.999 and result["question_decision_agreement"] >= 0.999
|
| 122 |
+
)
|
| 123 |
+
result["largest_probability_differences"] = sorted(
|
| 124 |
+
worst, key=lambda r: r["max_probability_drift"], reverse=True
|
| 125 |
+
)[:10]
|
| 126 |
+
comparisons[name] = result
|
| 127 |
+
report = {
|
| 128 |
+
"scope": "complete text parity panel" if complete else "partial text parity diagnostic",
|
| 129 |
+
"complete": complete,
|
| 130 |
+
"documents": len(files),
|
| 131 |
+
"total_documents": len(groups),
|
| 132 |
+
"branches": len(rows),
|
| 133 |
+
"total_branches": len(jobs),
|
| 134 |
+
"tasks": sorted({r["task"] for r in rows}),
|
| 135 |
+
"runtime": identity["runtime"],
|
| 136 |
+
"cuda_runtime": ref["identity"],
|
| 137 |
+
"panel_sha256": identity["panel_sha256"],
|
| 138 |
+
"score_files_sha256": digest(files),
|
| 139 |
+
"cuda_serving_binding_sha256": sha256(binding_path),
|
| 140 |
+
"temperature_fitting_performed": False,
|
| 141 |
+
"temperature_policy": "identical settings on both backends; not MLX calibration",
|
| 142 |
+
"comparisons": comparisons,
|
| 143 |
+
"parity_gate_passed": complete and all(r["agreement_gate_passed"] for r in comparisons.values()),
|
| 144 |
+
"bitwise_equality_claimed": False,
|
| 145 |
+
"image_qualification": False,
|
| 146 |
+
}
|
| 147 |
+
output.parent.mkdir(parents=True, exist_ok=True)
|
| 148 |
+
output.write_text(json.dumps(report, indent=2))
|
| 149 |
+
print(
|
| 150 |
+
json.dumps(
|
| 151 |
+
{k: report[k] for k in ("scope", "documents", "branches", "tasks", "parity_gate_passed")},
|
| 152 |
+
indent=2,
|
| 153 |
+
)
|
| 154 |
+
)
|
| 155 |
+
return report
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
if __name__ == "__main__":
|
| 159 |
+
parser = argparse.ArgumentParser()
|
| 160 |
+
for field in ("panel", "scores", "cuda-directory", "output"):
|
| 161 |
+
parser.add_argument("--" + field, required=True)
|
| 162 |
+
parser.add_argument("--reference", default="evaluations/bf16-reference-1789901869/report.json")
|
| 163 |
+
parser.add_argument("--allow-partial", action="store_true")
|
| 164 |
+
args = parser.parse_args()
|
| 165 |
+
compare(
|
| 166 |
+
args.panel,
|
| 167 |
+
args.scores,
|
| 168 |
+
args.cuda_directory,
|
| 169 |
+
args.reference,
|
| 170 |
+
args.output,
|
| 171 |
+
allow_partial=args.allow_partial,
|
| 172 |
+
)
|
mlx/scripts/score_parity.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Score a frozen panel for CUDA parity without fitting temperatures."""
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
|
| 5 |
+
from solomon_mlx import Solomon
|
| 6 |
+
from solomon_mlx.evaluation import score_panel
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 11 |
+
parser.add_argument("--model", default="models/quality")
|
| 12 |
+
parser.add_argument("--panel", required=True)
|
| 13 |
+
parser.add_argument("--output", required=True)
|
| 14 |
+
args = parser.parse_args()
|
| 15 |
+
score_panel(Solomon.load(args.model), args.panel, args.output)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
if __name__ == "__main__":
|
| 19 |
+
main()
|
mlx/scripts/validate_api.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Focused public API checks using the real BF16 model, without calibration."""
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
from solomon_mlx import Solomon
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def validate(output):
|
| 13 |
+
output = Path(output)
|
| 14 |
+
if output.exists():
|
| 15 |
+
raise FileExistsError("Validation outputs are immutable")
|
| 16 |
+
model = Solomon.load("models/quality")
|
| 17 |
+
document = "Alice is certified. Bob is not certified. The current priority is high."
|
| 18 |
+
questions = {
|
| 19 |
+
"boolean": "Is Alice certified?",
|
| 20 |
+
"single": {"type": "choice", "instructions": "Who is certified?", "options": ["Alice", "Bob"]},
|
| 21 |
+
"ordered": {"type": "score", "instructions": "What is the priority?", "levels": ["low", "high"]},
|
| 22 |
+
"entity": {"instructions": "Is {candidate} certified?", "candidates": ["Alice", "Bob"]},
|
| 23 |
+
"multilabel": {
|
| 24 |
+
"instructions": "Which facts apply?",
|
| 25 |
+
"candidates": ["Alice is certified", "Bob is certified"],
|
| 26 |
+
},
|
| 27 |
+
}
|
| 28 |
+
checks = {}
|
| 29 |
+
with model.prefill(document) as state:
|
| 30 |
+
first = model.decide(state=state, questions=questions, evidence="none", diagnostics=True)
|
| 31 |
+
assert set(first["answers"]) == set(questions)
|
| 32 |
+
checks["all_five_answer_types"] = True
|
| 33 |
+
repeated = model.decide(
|
| 34 |
+
state=state, questions={"boolean": questions["boolean"]}, evidence="none", diagnostics=True
|
| 35 |
+
)
|
| 36 |
+
a = first["answers"]["boolean"]["branches"][0]["letter_logits"]
|
| 37 |
+
b = repeated["answers"]["boolean"]["branches"][0]["letter_logits"]
|
| 38 |
+
np.testing.assert_array_equal(a, b)
|
| 39 |
+
checks["repeated_question_logits_exact"] = True
|
| 40 |
+
full = model.decide(
|
| 41 |
+
state=state,
|
| 42 |
+
questions={"boolean": questions["boolean"]},
|
| 43 |
+
evidence="none",
|
| 44 |
+
execution="full",
|
| 45 |
+
diagnostics=True,
|
| 46 |
+
)
|
| 47 |
+
c = full["answers"]["boolean"]["branches"][0]["letter_logits"]
|
| 48 |
+
checks["cached_full_max_logit_drift"] = float(np.max(np.abs(np.array(a) - c)))
|
| 49 |
+
assert (first["answers"]["boolean"]["noul"] >= 0.5) == (full["answers"]["boolean"]["noul"] >= 0.5)
|
| 50 |
+
reverse = model.decide(
|
| 51 |
+
state=state,
|
| 52 |
+
questions={"entity": {**questions["entity"], "candidates": ["Bob", "Alice"]}},
|
| 53 |
+
evidence="none",
|
| 54 |
+
)
|
| 55 |
+
assert reverse["answers"]["entity"]["candidates"] == first["answers"]["entity"]["candidates"]
|
| 56 |
+
assert list(reverse["answers"]["entity"]["candidates"]) == ["Bob", "Alice"]
|
| 57 |
+
checks["candidate_order_and_cache_isolation"] = True
|
| 58 |
+
evidence = model.decide(state=state, questions={"boolean": questions["boolean"]}, evidence="removal")
|
| 59 |
+
answer = evidence["answers"]["boolean"]
|
| 60 |
+
assert answer["evidence"]
|
| 61 |
+
for span in answer["evidence"]:
|
| 62 |
+
assert document[span["start"] : span["end"]] == span["text"]
|
| 63 |
+
assert answer["evidence_detail"]["verification"] == "fresh_source_reencoding"
|
| 64 |
+
assert answer["evidence_detail"]["calls"] == 2
|
| 65 |
+
checks["evidence_spans_and_fresh_verification"] = True
|
| 66 |
+
exhausted = model.decide(
|
| 67 |
+
state=state, questions={"boolean": questions["boolean"]}, evidence="removal", evidence_max_calls=0
|
| 68 |
+
)
|
| 69 |
+
assert exhausted["answers"]["boolean"]["evidence_status"] == "budget_exhausted"
|
| 70 |
+
assert exhausted["usage"]["evidence_calls"] == 0
|
| 71 |
+
checks["evidence_budget_enforced"] = True
|
| 72 |
+
replay = output.with_suffix(".replay.json")
|
| 73 |
+
state.save(replay)
|
| 74 |
+
try:
|
| 75 |
+
model.decide(state=state, questions={"q": "Fact?"})
|
| 76 |
+
except ValueError:
|
| 77 |
+
checks["closed_state_rejected"] = True
|
| 78 |
+
else:
|
| 79 |
+
raise AssertionError("Closed state accepted")
|
| 80 |
+
with model.replay(replay) as restored:
|
| 81 |
+
result = model.decide(
|
| 82 |
+
state=restored, questions={"boolean": questions["boolean"]}, evidence="none", diagnostics=True
|
| 83 |
+
)
|
| 84 |
+
np.testing.assert_array_equal(a, result["answers"]["boolean"]["branches"][0]["letter_logits"])
|
| 85 |
+
checks["public_api_replay_exact"] = True
|
| 86 |
+
corrupt = json.loads(replay.read_text())
|
| 87 |
+
corrupt["parts"][0]["text"] += " changed"
|
| 88 |
+
bad_path = output.with_suffix(".corrupt-replay.json")
|
| 89 |
+
bad_path.write_text(json.dumps(corrupt))
|
| 90 |
+
try:
|
| 91 |
+
model.replay(bad_path)
|
| 92 |
+
except ValueError:
|
| 93 |
+
checks["corrupt_replay_rejected"] = True
|
| 94 |
+
else:
|
| 95 |
+
raise AssertionError("Corrupt replay accepted")
|
| 96 |
+
image_parts = json.loads(Path("evaluations/image-jobs.json").read_text())[0]["parts"]
|
| 97 |
+
with model.prefill(image_parts) as images:
|
| 98 |
+
result = model.decide(state=images, questions={"q": "Is Alice certified?"}, evidence="support")
|
| 99 |
+
assert result["answers"]["q"]["evidence_status"] == "unsupported_page_selector"
|
| 100 |
+
checks["missing_page_selector_reported"] = True
|
| 101 |
+
with model.prefill({"subject": "Alice", "certified": True}) as structured:
|
| 102 |
+
assert structured.prefix_tokens > 0
|
| 103 |
+
checks["structured_document_accepted"] = True
|
| 104 |
+
try:
|
| 105 |
+
model.engine.admit(40961)
|
| 106 |
+
except ValueError:
|
| 107 |
+
checks["context_ceiling_enforced"] = True
|
| 108 |
+
else:
|
| 109 |
+
raise AssertionError("Context limit not enforced")
|
| 110 |
+
assert model.engine.context["start"] is None
|
| 111 |
+
assert len(model.engine.heads) == 10
|
| 112 |
+
checks["adapter_state_reset_and_ten_heads_loaded"] = True
|
| 113 |
+
report = {
|
| 114 |
+
"runtime": model.identity,
|
| 115 |
+
"checks": checks,
|
| 116 |
+
"passed": True,
|
| 117 |
+
"scope": "real-weight API behavior; these checks do not establish held-out CUDA parity",
|
| 118 |
+
"answers": first["answers"],
|
| 119 |
+
"evidence": answer,
|
| 120 |
+
}
|
| 121 |
+
output.write_text(json.dumps(report, indent=2))
|
| 122 |
+
print(json.dumps({"passed": True, "checks": checks}, indent=2))
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
if __name__ == "__main__":
|
| 126 |
+
parser = argparse.ArgumentParser()
|
| 127 |
+
parser.add_argument("--output", required=True)
|
| 128 |
+
validate(parser.parse_args().output)
|
mlx/src/solomon_mlx/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Solomon semantic decisions on Apple Silicon."""
|
| 2 |
+
|
| 3 |
+
from .api import DocumentState, Solomon
|
| 4 |
+
|
| 5 |
+
__all__ = ["DocumentState", "Solomon"]
|
mlx/src/solomon_mlx/_vendor/__init__.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
mlx/src/solomon_mlx/_vendor/contract.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
| 3 |
+
import json
|
| 4 |
+
import numpy as np
|
| 5 |
+
MAX_CANDIDATES = 64
|
| 6 |
+
|
| 7 |
+
def _text(value, name):
|
| 8 |
+
if not isinstance(value, str) or not value.strip():
|
| 9 |
+
raise ValueError(name + ' must be a nonempty string')
|
| 10 |
+
return value
|
| 11 |
+
|
| 12 |
+
def parse_questions(questions):
|
| 13 |
+
"""Questions {id: spec} -> ordered list of normalised specs.
|
| 14 |
+
|
| 15 |
+
noul: {"type": "noul", "instructions": str} -> task boolean
|
| 16 |
+
{"type": "noul", "instructions": "Is {candidate} ...?", "candidates": [...]} -> task entity (one Noul per candidate)
|
| 17 |
+
{"type": "noul", "instructions": str, "candidates": [...], "candidate_kind": "label"} -> task multilabel
|
| 18 |
+
(candidate_kind defaults to 'entity' when instructions contain {candidate}, else 'label')
|
| 19 |
+
choice: {"type": "choice", "instructions": str, "options": [str, ...] | {key: text}, "ordered": bool}
|
| 20 |
+
('criteria' is accepted as a compatibility alias of 'options')
|
| 21 |
+
score: {"type": "score", "instructions": str, "levels": [str, ...]} (alias 'criteria'); an ordered choice keyed
|
| 22 |
+
"0".."K-1" with a legend and score = sum_i i * p_i.
|
| 23 |
+
"""
|
| 24 |
+
if not isinstance(questions, dict) or not questions:
|
| 25 |
+
raise ValueError('questions must be a nonempty mapping of id -> question')
|
| 26 |
+
out = []
|
| 27 |
+
for qid, spec in questions.items():
|
| 28 |
+
if not isinstance(qid, str) or not qid:
|
| 29 |
+
raise ValueError('question ids must be nonempty strings')
|
| 30 |
+
if isinstance(spec, str):
|
| 31 |
+
spec = {'type': 'noul', 'instructions': spec}
|
| 32 |
+
if not isinstance(spec, dict):
|
| 33 |
+
raise ValueError(f'question {qid}: spec must be an object')
|
| 34 |
+
kind = str(spec.get('type', 'noul')).lower()
|
| 35 |
+
instructions = _text(spec.get('instructions', spec.get('question')), f'question {qid}: instructions')
|
| 36 |
+
if kind == 'noul':
|
| 37 |
+
if 'candidates' not in spec:
|
| 38 |
+
out.append({'id': qid, 'type': 'noul', 'task': 'boolean', 'request': {'question': instructions}})
|
| 39 |
+
continue
|
| 40 |
+
candidates = spec['candidates']
|
| 41 |
+
if not isinstance(candidates, list) or not 1 <= len(candidates) <= MAX_CANDIDATES or len(set(candidates)) != len(candidates) or any((not isinstance(c, str) or not c.strip() for c in candidates)):
|
| 42 |
+
raise ValueError(f'question {qid}: candidates must be 1 to {MAX_CANDIDATES} distinct nonempty strings')
|
| 43 |
+
ckind = spec.get('candidate_kind', 'entity' if '{candidate}' in instructions else 'label')
|
| 44 |
+
if ckind == 'entity':
|
| 45 |
+
if instructions.count('{candidate}') != 1 or '{entity}' in instructions:
|
| 46 |
+
raise ValueError(f'question {qid}: entity instructions need exactly one {{candidate}} placeholder')
|
| 47 |
+
request = {'template': instructions.replace('{candidate}', '{entity}'), 'entities': list(candidates)}
|
| 48 |
+
task = 'entity'
|
| 49 |
+
elif ckind == 'label':
|
| 50 |
+
if '{candidate}' in instructions:
|
| 51 |
+
raise ValueError(f'question {qid}: label candidates take no {{candidate}} placeholder')
|
| 52 |
+
request = {'question': instructions, 'labels': list(candidates)}
|
| 53 |
+
task = 'multilabel'
|
| 54 |
+
else:
|
| 55 |
+
raise ValueError(f'question {qid}: candidate_kind must be entity or label')
|
| 56 |
+
out.append({'id': qid, 'type': 'noul', 'task': task, 'candidates': list(candidates), 'request': request})
|
| 57 |
+
elif kind in ('choice', 'score'):
|
| 58 |
+
raw = spec.get('levels', spec.get('options', spec.get('criteria'))) if kind == 'score' else spec.get('options', spec.get('criteria'))
|
| 59 |
+
if isinstance(raw, dict):
|
| 60 |
+
keys, texts = ([str(k) for k in raw], [raw[k] if isinstance(raw[k], str) and raw[k].strip() else str(k) for k in raw])
|
| 61 |
+
elif isinstance(raw, list):
|
| 62 |
+
texts = list(raw)
|
| 63 |
+
keys = [str(i) for i in range(len(raw))] if kind == 'score' else list(raw)
|
| 64 |
+
else:
|
| 65 |
+
raise ValueError(f'question {qid}: options must be a list or a mapping')
|
| 66 |
+
if not 2 <= len(texts) <= 8 or any((not isinstance(t, str) or not t.strip() for t in texts)) or len(set(texts)) != len(texts):
|
| 67 |
+
raise ValueError(f'question {qid}: provide 2 to 8 distinct nonempty options')
|
| 68 |
+
ordered = kind == 'score' or bool(spec.get('ordered', False))
|
| 69 |
+
if not isinstance(spec.get('ordered', False), bool):
|
| 70 |
+
raise ValueError(f'question {qid}: ordered must be Boolean')
|
| 71 |
+
out.append({'id': qid, 'type': kind, 'task': 'ordered' if ordered else 'single', 'keys': keys, 'texts': texts, 'request': {'question': instructions, 'options': texts}})
|
| 72 |
+
else:
|
| 73 |
+
raise ValueError(f'question {qid}: type must be noul, choice or score')
|
| 74 |
+
return out
|
| 75 |
+
|
| 76 |
+
def _state_parts(state):
|
| 77 |
+
if isinstance(state, str):
|
| 78 |
+
return [{'text': state}]
|
| 79 |
+
if isinstance(state, list):
|
| 80 |
+
return state
|
| 81 |
+
if isinstance(state, dict):
|
| 82 |
+
return [{'text': json.dumps(state, ensure_ascii=False, indent=2, sort_keys=False)}]
|
| 83 |
+
raise ValueError('state must be text, an object, or a list of document parts')
|
| 84 |
+
def empty(spec):
|
| 85 |
+
if spec['type'] == 'noul':
|
| 86 |
+
return {'candidates': None} if 'candidates' in spec else {'noul': None}
|
| 87 |
+
return {'probabilities': None, 'answer': None}
|
| 88 |
+
|
| 89 |
+
def present(spec, dists):
|
| 90 |
+
if spec['type'] == 'noul':
|
| 91 |
+
if 'candidates' in spec:
|
| 92 |
+
return {'candidate_kind': 'entity' if spec['task'] == 'entity' else 'label', 'candidates': {c: float(d[0]) for c, d in zip(spec['candidates'], dists)}, 'candidate_ordering_scores': {c: float(max(d[0], 1 - d[0])) for c, d in zip(spec['candidates'], dists)}}
|
| 93 |
+
return {'noul': float(dists[0][0])}
|
| 94 |
+
p = dists[0]
|
| 95 |
+
keys = spec['keys']
|
| 96 |
+
out = {'probabilities': {k: float(v) for k, v in zip(keys, p)}, 'answer': keys[int(np.argmax(p))]}
|
| 97 |
+
out['choice'] = out['answer']
|
| 98 |
+
if spec['type'] == 'score':
|
| 99 |
+
out['score'] = float(np.dot(np.arange(len(p)), p))
|
| 100 |
+
out['legend'] = dict(zip(keys, spec['texts']))
|
| 101 |
+
elif spec['task'] == 'ordered':
|
| 102 |
+
out['ordered'] = True
|
| 103 |
+
return out
|
| 104 |
+
|
| 105 |
+
def decision(spec, shown):
|
| 106 |
+
if spec['type'] == 'noul':
|
| 107 |
+
if 'candidates' in spec:
|
| 108 |
+
return {c: p >= 0.5 for c, p in shown['candidates'].items()}
|
| 109 |
+
return shown['noul'] >= 0.5
|
| 110 |
+
return shown['answer']
|
| 111 |
+
|
mlx/src/solomon_mlx/_vendor/evidence.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
| 3 |
+
"""Deterministic source references and explicit evidence interventions.
|
| 4 |
+
|
| 5 |
+
Offsets count Python Unicode code points, never bytes. Candidate ranking is lexical
|
| 6 |
+
and is labelled as such; only an independent model callback supplies support scores.
|
| 7 |
+
Interventions re-encode edited source; an existing KV state cannot prove removal.
|
| 8 |
+
"""
|
| 9 |
+
import hashlib
|
| 10 |
+
import re
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def digest(text):
|
| 15 |
+
return hashlib.sha256(text.encode()).hexdigest()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def passages(text, max_chars=1200):
|
| 19 |
+
if not isinstance(text,str) or max_chars < 1:
|
| 20 |
+
raise ValueError('text and positive passage size required')
|
| 21 |
+
result=[]
|
| 22 |
+
# Cover every character, including whitespace; splitting does not normalize text.
|
| 23 |
+
start=0
|
| 24 |
+
while start < len(text):
|
| 25 |
+
limit=min(len(text),start+max_chars)
|
| 26 |
+
end=limit
|
| 27 |
+
if limit < len(text):
|
| 28 |
+
candidates=[m.end() for m in re.finditer(r'\n\s*\n|(?<=[.!?])\s+',text[start:limit])]
|
| 29 |
+
if candidates and candidates[-1] >= max_chars//2:end=start+candidates[-1]
|
| 30 |
+
result.append({'id':f'text:{start}:{end}','kind':'text','start':start,'end':end,
|
| 31 |
+
'text':text[start:end],'source_sha256':digest(text)})
|
| 32 |
+
start=end
|
| 33 |
+
return result
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def image_pages(paths):
|
| 37 |
+
return [{'id':f'page:{i+1}','kind':'image','page':i+1,'path':str(p),
|
| 38 |
+
'source_sha256':hashlib.sha256(Path(p).read_bytes()).hexdigest()} for i,p in enumerate(paths)]
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def validate_spans(text, spans):
|
| 42 |
+
ordered=sorted(spans,key=lambda s:(s['start'],s['end']))
|
| 43 |
+
last=0
|
| 44 |
+
for span in ordered:
|
| 45 |
+
start,end=span['start'],span['end']
|
| 46 |
+
if type(start) is not int or type(end) is not int or not 0<=start<end<=len(text) or start<last:
|
| 47 |
+
raise ValueError('invalid or overlapping evidence range')
|
| 48 |
+
if span.get('source_sha256',digest(text))!=digest(text) or span.get('text',text[start:end])!=text[start:end]:
|
| 49 |
+
raise ValueError('evidence no longer matches source')
|
| 50 |
+
last=end
|
| 51 |
+
return ordered
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def rank_candidates(question, candidates, limit=8):
|
| 55 |
+
if limit<1:raise ValueError('positive candidate limit required')
|
| 56 |
+
tokens=set(re.findall(r'\w+',question.casefold()))
|
| 57 |
+
ranked=[]
|
| 58 |
+
for c in candidates:
|
| 59 |
+
words=set(re.findall(r'\w+',c.get('text','').casefold()))
|
| 60 |
+
ranked.append({**c,'candidate_score':len(words&tokens)/max(1,len(tokens)),
|
| 61 |
+
'candidate_method':'lexical_overlap' if c['kind']=='text' else 'page_order'})
|
| 62 |
+
# Stable ties retain source order (page 2 must precede page 10).
|
| 63 |
+
return sorted(ranked,key=lambda c:-c['candidate_score'])[:limit]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def select(question, candidates, support_score, limit=8, minimum_support=.5):
|
| 67 |
+
"""Callback receives only question+candidate, never benchmark gold."""
|
| 68 |
+
if not 0<=minimum_support<=1:raise ValueError('invalid support threshold')
|
| 69 |
+
results=[]
|
| 70 |
+
for candidate in rank_candidates(question,candidates,limit):
|
| 71 |
+
score=float(support_score(question,candidate))
|
| 72 |
+
if not 0<=score<=1:raise ValueError('finite support probability required')
|
| 73 |
+
results.append({**candidate,'support_score':score})
|
| 74 |
+
chosen=[r for r in results if r['support_score']>=minimum_support]
|
| 75 |
+
return {'evidence':chosen,'candidates':results,'verification':'model_support_only',
|
| 76 |
+
'faithfulness_established':False,'no_support_found':not chosen}
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def intervene(text, spans, question, decide):
|
| 80 |
+
"""decide(document,question) must prefill each supplied document afresh.
|
| 81 |
+
|
| 82 |
+
All three actual calls are returned; agreement/disagreement is evidence, not a
|
| 83 |
+
guarantee that a passage is the unique cause of an answer.
|
| 84 |
+
"""
|
| 85 |
+
spans=validate_spans(text,spans)
|
| 86 |
+
evidence='\n\n'.join(text[s['start']:s['end']] for s in spans)
|
| 87 |
+
pieces=[];start=0
|
| 88 |
+
for span in spans:
|
| 89 |
+
pieces.append(text[start:span['start']]);start=span['end']
|
| 90 |
+
pieces.append(text[start:]);removed=''.join(pieces)
|
| 91 |
+
full=decide(text,question)
|
| 92 |
+
only=decide(evidence,question)
|
| 93 |
+
removal=decide(removed,question)
|
| 94 |
+
return {'full':full,'evidence_only':only,'evidence_removed':removal,
|
| 95 |
+
'evidence_only_agrees':only==full,'removal_changes_answer':removal!=full,
|
| 96 |
+
'verification':'fresh_source_reencoding','source_sha256':digest(text),
|
| 97 |
+
'evidence_sha256':digest(evidence),'removed_sha256':digest(removed),
|
| 98 |
+
'calls':3,'input_characters':len(text)+len(evidence)+len(removed)}
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def validate_pages(pages, selected):
|
| 102 |
+
"""Validate ordered page manifests and selected immutable references."""
|
| 103 |
+
indexed = {}
|
| 104 |
+
for expected, page in enumerate(pages, 1):
|
| 105 |
+
if page.get('kind') != 'image' or type(page.get('page')) is not int or page['page'] != expected:
|
| 106 |
+
raise ValueError('image manifest must use consecutive source page IDs')
|
| 107 |
+
if page.get('id') != f'page:{expected}':
|
| 108 |
+
raise ValueError('image page ID does not match source position')
|
| 109 |
+
actual = hashlib.sha256(Path(page['path']).read_bytes()).hexdigest()
|
| 110 |
+
if page.get('source_sha256') != actual:
|
| 111 |
+
raise ValueError('image no longer matches source')
|
| 112 |
+
indexed[expected] = page
|
| 113 |
+
ids = []
|
| 114 |
+
for reference in selected:
|
| 115 |
+
number = reference.get('page')
|
| 116 |
+
if type(number) is not int or number not in indexed or number in ids:
|
| 117 |
+
raise ValueError('invalid or duplicate evidence page')
|
| 118 |
+
source = indexed[number]
|
| 119 |
+
if any(reference.get(key) != source[key] for key in ('id', 'kind', 'path', 'source_sha256')):
|
| 120 |
+
raise ValueError('evidence page no longer matches source manifest')
|
| 121 |
+
ids.append(number)
|
| 122 |
+
return [indexed[number] for number in sorted(ids)]
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def intervene_pages(pages, selected, question, decide, text=''):
|
| 126 |
+
"""Re-encode full, evidence-only and page-removed multimodal documents.
|
| 127 |
+
|
| 128 |
+
decide(text, image_paths, question) must create a fresh state each time and
|
| 129 |
+
accept an empty image list. Evidence-only has no accompanying source text;
|
| 130 |
+
removal retains all source text and unselected pages. This isolates page
|
| 131 |
+
evidence and makes text-only sufficiency a visible competing explanation.
|
| 132 |
+
Original page IDs are recorded because subset images are renumbered on input.
|
| 133 |
+
"""
|
| 134 |
+
if not isinstance(text, str):
|
| 135 |
+
raise ValueError('source text must be a string')
|
| 136 |
+
selected = validate_pages(pages, selected)
|
| 137 |
+
selected_ids = {p['page'] for p in selected}
|
| 138 |
+
removed = [p for p in pages if p['page'] not in selected_ids]
|
| 139 |
+
calls = [(text, pages), ('', selected), (text, removed)]
|
| 140 |
+
answers = []
|
| 141 |
+
for source_text, source_pages in calls:
|
| 142 |
+
# Recheck all originals before each call: never silently mix revisions.
|
| 143 |
+
validate_pages(pages, selected)
|
| 144 |
+
answers.append(decide(source_text, [p['path'] for p in source_pages], question))
|
| 145 |
+
validate_pages(pages, selected)
|
| 146 |
+
full, only, removal = answers
|
| 147 |
+
return {'full': full, 'evidence_only': only, 'evidence_removed': removal,
|
| 148 |
+
'evidence_only_agrees': only == full, 'removal_changes_answer': removal != full,
|
| 149 |
+
'verification': 'fresh_source_reencoding', 'faithfulness_established': False,
|
| 150 |
+
'source_text_sha256': digest(text),
|
| 151 |
+
'source_pages': [{k: p[k] for k in ('id', 'page', 'source_sha256')} for p in pages],
|
| 152 |
+
'evidence_page_ids': [p['page'] for p in selected],
|
| 153 |
+
'removed_input_page_ids': [p['page'] for p in removed],
|
| 154 |
+
'calls': 3, 'input_images': sum(len(p) for _, p in calls),
|
| 155 |
+
'input_image_bytes': sum(Path(p['path']).stat().st_size for _, ps in calls for p in ps),
|
| 156 |
+
'input_characters': 2 * len(text)}
|
mlx/src/solomon_mlx/_vendor/evidence_v3.py
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
| 3 |
+
"""Evidence packages (v3): selected spans plus source-derived governing context, per question unit.
|
| 4 |
+
|
| 5 |
+
A package is a genuine subset of one source document: every range is an exact, validated slice
|
| 6 |
+
of the source (Python code-point offsets), rendered in source order with whitespace-only
|
| 7 |
+
separators. Nothing is paraphrased, summarised or generated. Context is attached by
|
| 8 |
+
question-independent document structure plus the unit's own selected spans and question text;
|
| 9 |
+
gold/authoring data is never an input.
|
| 10 |
+
|
| 11 |
+
Roles
|
| 12 |
+
evidence spans chosen by the selector (or, in oracle diagnostics, gold anchors). Span
|
| 13 |
+
precision/recall gates are computed on these only, exactly as before.
|
| 14 |
+
context ranges attached automatically, each with one or more reasons:
|
| 15 |
+
header document title block (identity of the source, author/compiler, date)
|
| 16 |
+
interpretation generic reading rules (scope6.retrieval.governing_context, unchanged regex)
|
| 17 |
+
locator container of an included span: message header line (date, author ->
|
| 18 |
+
recipient), minute number + heading, schedule/section heading, entry number
|
| 19 |
+
correction a withdrawal/rescission/deletion elsewhere that refers to the container of an
|
| 20 |
+
included statement and names the same subject and topic (or the exact entry)
|
| 21 |
+
withdrawn the statement(s) that an included withdrawal refers to, so the chain is
|
| 22 |
+
readable (the withdrawn text is marked by the withdrawal, not by us)
|
| 23 |
+
rule a general rule / band scale whose operative topic matches the unit question
|
| 24 |
+
(attached only when the unit has evidence)
|
| 25 |
+
exception the exception clause governing an included rule, or the rule an included
|
| 26 |
+
exception limits
|
| 27 |
+
definition the sentence defining a capitalised class term used by an included rule,
|
| 28 |
+
when it names the unit's subject
|
| 29 |
+
condition a statement about the unit's subject that bears on an included rule's
|
| 30 |
+
conditions or exception (>=2 shared content words beyond the question topic,
|
| 31 |
+
or one document-rare shared word)
|
| 32 |
+
convention the document's own reading conventions (sentences of the paragraphs that hold
|
| 33 |
+
generic reading rules) that the package needs: silence always; conflict and vocabulary when
|
| 34 |
+
there is evidence; removal when a withdrawal/deletion chain is present;
|
| 35 |
+
condition when a rule is present; exception when an exception is present
|
| 36 |
+
|
| 37 |
+
Size is measured as covered source characters / source characters and reported per package. A
|
| 38 |
+
package above the registered cap (default 0.30) sheds context in TRIM_ORDER (never evidence, rule,
|
| 39 |
+
exception, condition, correction or withdrawn context) and records what was trimmed.
|
| 40 |
+
"""
|
| 41 |
+
import re
|
| 42 |
+
from .evidence import digest, validate_spans
|
| 43 |
+
from .retrieval import candidates, governing_context
|
| 44 |
+
|
| 45 |
+
SCHEMA = 'scope6-evidence-package-v3.1'
|
| 46 |
+
SIZE_CAP = .30
|
| 47 |
+
# Context dropped first when a package exceeds the size cap (evidence is never dropped).
|
| 48 |
+
TRIM_ORDER = ('interpretation', 'convention/silence', 'convention/vocabulary', 'convention/conflict', 'header', 'definition',
|
| 49 |
+
'convention/condition', 'convention/exception', 'convention/removal', 'locator')
|
| 50 |
+
MONTHS = 'January|February|March|April|May|June|July|August|September|October|November|December'
|
| 51 |
+
_WORD = re.compile(r'\w+')
|
| 52 |
+
_CAP = re.compile(r"\b[A-Z][\w&'-]*")
|
| 53 |
+
_WITHDRAWAL = re.compile(r"withdr[ae]w|withdrawn|take back|disregard|rescind|retract|should not be relied|"
|
| 54 |
+
r"substituted|\bis deleted|\bdelete[sd]?\b|struck out|replaced by|no further effect", re.I)
|
| 55 |
+
_REF_DATE = re.compile(r'(?:message|wrote|written|letter|note)\D{0,14}?(\d{1,2} (?:' + MONTHS + r'))')
|
| 56 |
+
_REF_MINUTE = re.compile(r'\bminute (\d+)\b', re.I)
|
| 57 |
+
_REF_ENTRY = re.compile(r'\b[Ee]ntry (\d+) of [Ss]chedule (\d+)')
|
| 58 |
+
_MSG_HEAD = re.compile(r'Message \d+\. (\d{1,2} (?:' + MONTHS + r'))\.')
|
| 59 |
+
_MINUTE_HEAD = re.compile(r'(\d+)\.\s+[^.\n]{1,80}\.')
|
| 60 |
+
_SCHEDULE_HEAD = re.compile(r'SCHEDULE (\d+)\b')
|
| 61 |
+
_ENTRY_PREFIX = re.compile(r'[A-Z]?\d+(?:\.\d+)*\.?\s*')
|
| 62 |
+
_PERMISSION = re.compile(r'\bmay\b|permitted|authorised|entitled|leave to|allowed|cleared|confers?', re.I)
|
| 63 |
+
_RULE = re.compile(r"(?i:\b(?:any|each|every)\s+[a-z]+(?:\s+[a-z]+)?\s+(?:who|that)\b|\ban?\s+[a-z]+\s+who\b|general rule|standing rule|"
|
| 64 |
+
r"office rule|rule governing|\bif that\b|where one and the same|\b[a-z]+s who\b|\bwhere (?:an?|any|one)\b)|\b[A-Z][a-z]+ [A-Z][a-z]+s? (?:that|who)\b")
|
| 65 |
+
_SCALE = re.compile(r'\bbands?\b|\bscale\b|from lowest to highest|order of the levels|worked out from|fixed by that number|\bfewer than \d+', re.I)
|
| 66 |
+
_EXCEPTION = re.compile(r'does not apply|confers nothing on|is outside (?:clause|the rule)|not engaged|does not reach|switched off|'
|
| 67 |
+
r'disapplied|subject to (?:one|the) exception|nothing in the rule|save that|except (?:where|that|for)\b', re.I)
|
| 68 |
+
CONVENTIONS = {
|
| 69 |
+
'removal': re.compile(r"withdr[ae]w|rescind|delet|substitut|struck out|take back|displace|disregard|\bspent\b|express(?:ly)? (?:withdrawal|rescission)", re.I),
|
| 70 |
+
'condition': re.compile(r"\bconditions?\b|\blimbs?\b|requirements?\b|only part|part of the way|whole of it|each of its|all of its", re.I),
|
| 71 |
+
'exception': re.compile(r"\bexcept", re.I),
|
| 72 |
+
'conflict': re.compile(r"both (?:stand|remain|hold|are in force|left standing)|opposite (?:ways|things)|inconsistent|contradict|"
|
| 73 |
+
r"point opposite|not say which|not chosen between|this office does not say", re.I),
|
| 74 |
+
'vocabulary': re.compile(r"interchangeabl|one and the same (?:permission|refusal)|are one (?:grant|refusal)|mean the same|same thing|words to like effect", re.I),
|
| 75 |
+
'silence': re.compile(r"silen|absence of|unminuted|nothing has been decided|has not been said|undecided|left open", re.I)}
|
| 76 |
+
_DEFINES = re.compile(r'\bare\b|\bmeans\b|\bidentified\b|\binclude', re.I)
|
| 77 |
+
_STOP = {'this', 'that', 'these', 'those', 'with', 'under', 'which', 'what', 'does', 'file', 'correspondence', 'record', 'records',
|
| 78 |
+
'recorded', 'minutes', 'agreement', 'bundle', 'messages', 'message', 'stand', 'stands', 'taking', 'reading', 'whole',
|
| 79 |
+
'strength', 'position', 'open', 'given', 'have', 'been', 'applies', 'apply', 'entitled', 'allowed', 'liberty', 'free',
|
| 80 |
+
'from', 'there', 'their', 'they', 'decisions', 'here', 'schedules', 'schedule', 'papers', 'office', 'shown', 'show',
|
| 81 |
+
'shows', 'case', 'matters', 'terms', 'place', 'placed', 'about', 'question', 'whether', 'should', 'relied', 'either',
|
| 82 |
+
'wrote', 'withdraw', 'withdrawn', 'passage', 'treat', 'nothing', 'follows', 'please', 'disregard', 'concerns', 'deals',
|
| 83 |
+
'resolved', 'rescinded', 'much', 'decision', 'minute', 'further', 'effect', 'permission', 'permitted', 'refused',
|
| 84 |
+
'barred', 'prohibited', 'authorised', 'cleared', 'leave', 'allows', 'allow', 'bars', 'refuses', 'grant', 'refusal',
|
| 85 |
+
'entry', 'deleted', 'substituted', 'following', 'replaced', 'struck', 'committee', 'secretary', 'chair', 'principal'}
|
| 86 |
+
ROLES = ('evidence', 'context')
|
| 87 |
+
# Capitalised words that are never subject names (sentence openers, document furniture).
|
| 88 |
+
_NOT_NAMES = {'the', 'this', 'that', 'these', 'those', 'it', 'its', 'i', 'we', 'our', 'my', 'on', 'for', 'so', 'as', 'at', 'in', 'of',
|
| 89 |
+
'please', 'treat', 'where', 'when', 'what', 'which', 'who', 'whether', 'any', 'each', 'every', 'no', 'nothing', 'there',
|
| 90 |
+
'message', 'messages', 'entry', 'schedule', 'clause', 'minute', 'minutes', 'agreement', 'principal', 'resolved', 'note',
|
| 91 |
+
'committee', 'secretary', 'chair', 'treasurer', 'register', 'records', 'record', 'permission', 'an', 'a', 'if', 'all',
|
| 92 |
+
'both', 'neither', 'either', 'one', 'two', 'words', 'dates', 'decisions', 'rules', 'only', 'once', 'part', 'to', 'by',
|
| 93 |
+
'read', 'do', 'what', 'should', 'with', 'from', 'under', 'after', 'before', 'reading', 'taking', 'is', 'has', 'have'}
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def _words(s):
|
| 97 |
+
return set(_WORD.findall(s.casefold()))
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def _topic(s, names=()):
|
| 101 |
+
low = {w for n in names for w in _words(n)}
|
| 102 |
+
return {w for w in _words(s) if len(w) >= 4 and w not in _STOP and w not in low and not w.isdigit()
|
| 103 |
+
and not re.fullmatch(MONTHS.casefold(), w)}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
class Structure:
|
| 107 |
+
"""Question-independent source structure: sentences, paragraphs, lines and containers."""
|
| 108 |
+
|
| 109 |
+
def __init__(self, text):
|
| 110 |
+
self.text = text
|
| 111 |
+
self.sentences = candidates(text)
|
| 112 |
+
self.paragraphs = []
|
| 113 |
+
start = 0
|
| 114 |
+
for m in list(re.finditer(r'\n\s*\n', text)) + [None]:
|
| 115 |
+
end = m.start() if m else len(text)
|
| 116 |
+
if text[start:end].strip():
|
| 117 |
+
self.paragraphs.append((start, end))
|
| 118 |
+
start = m.end() if m else len(text)
|
| 119 |
+
self.lines = [(m.start(), m.end()) for m in re.finditer(r'[^\n]+', text)]
|
| 120 |
+
df = {}
|
| 121 |
+
for s in self.sentences:
|
| 122 |
+
for w in _words(s['text']):
|
| 123 |
+
df[w] = df.get(w, 0) + 1
|
| 124 |
+
self.df = df
|
| 125 |
+
self.interpretation = [(s['start'], s['end']) for s in governing_context(text, self.sentences)]
|
| 126 |
+
# containers: message date -> paragraph; minute number -> paragraph; (schedule, entry) -> line
|
| 127 |
+
self.messages, self.minutes, self.entries = {}, {}, {}
|
| 128 |
+
for a, b in self.paragraphs:
|
| 129 |
+
first = text[a:b].split('\n', 1)[0]
|
| 130 |
+
m = _MSG_HEAD.match(first)
|
| 131 |
+
if m:
|
| 132 |
+
self.messages.setdefault(m.group(1), (a, b))
|
| 133 |
+
m = re.match(r'(\d+)\. ', text[a:b])
|
| 134 |
+
if m and '\n' not in text[a:b].strip():
|
| 135 |
+
self.minutes.setdefault(m.group(1), (a, b))
|
| 136 |
+
m = _SCHEDULE_HEAD.match(first)
|
| 137 |
+
if m:
|
| 138 |
+
for la, lb in self.lines:
|
| 139 |
+
if a <= la and lb <= b:
|
| 140 |
+
e = re.match(r'(\d+)\. ', text[la:lb])
|
| 141 |
+
if e:
|
| 142 |
+
self.entries[(m.group(1), e.group(1))] = (la, lb)
|
| 143 |
+
self.rules = [s for s in self.sentences if (_RULE.search(s['text']) and _PERMISSION.search(s['text'])) or _SCALE.search(s['text'])]
|
| 144 |
+
self.exceptions = [s for s in self.sentences if _EXCEPTION.search(s['text'])]
|
| 145 |
+
self.withdrawals = [s for s in self.sentences if _WITHDRAWAL.search(s['text'])]
|
| 146 |
+
# Reading conventions: sentences of the interpretation paragraphs (those holding a generic reading rule).
|
| 147 |
+
blocks = {self.paragraph_of(a) for a, _ in self.interpretation} - {None}
|
| 148 |
+
general = [s for s in self.sentences if self.paragraph_of(s['start']) in blocks and s not in self.rules]
|
| 149 |
+
self.conventions = {k: [(s['start'], s['end']) for s in general if rx.search(s['text'])] for k, rx in CONVENTIONS.items()}
|
| 150 |
+
|
| 151 |
+
def governed_rule(self, exception):
|
| 152 |
+
"""The rule an exception limits: nearest preceding rule in the same paragraph (or the same sentence)."""
|
| 153 |
+
para = self.paragraph_of(exception['start'])
|
| 154 |
+
prior = [r for r in self.rules if r['start'] <= exception['start'] and para and para[0] <= r['start'] < para[1]
|
| 155 |
+
and not _SCALE.search(r['text'])]
|
| 156 |
+
return prior[-1] if prior else None
|
| 157 |
+
|
| 158 |
+
def names(self, s, limit=16):
|
| 159 |
+
"""Capitalised tokens that are rare in this source (subject names); months/number words excluded."""
|
| 160 |
+
out = set()
|
| 161 |
+
for tok in _CAP.findall(s):
|
| 162 |
+
tok = re.sub(r"'s$", '', tok)
|
| 163 |
+
w = tok.casefold()
|
| 164 |
+
if re.fullmatch(MONTHS, tok) or len(w) < 3 or w in _NOT_NAMES or (tok.isupper() and len(tok) > 1):
|
| 165 |
+
continue
|
| 166 |
+
if self.df.get(w, 0) <= limit:
|
| 167 |
+
out.add(tok)
|
| 168 |
+
return out
|
| 169 |
+
|
| 170 |
+
def paragraph_of(self, pos):
|
| 171 |
+
for a, b in self.paragraphs:
|
| 172 |
+
if a <= pos < b:
|
| 173 |
+
return a, b
|
| 174 |
+
return None
|
| 175 |
+
|
| 176 |
+
def line_of(self, pos):
|
| 177 |
+
for a, b in self.lines:
|
| 178 |
+
if a <= pos < b:
|
| 179 |
+
return a, b
|
| 180 |
+
return None
|
| 181 |
+
|
| 182 |
+
def container(self, span):
|
| 183 |
+
"""(kind, key) of the message/minute/entry holding a span, else None."""
|
| 184 |
+
for key, (a, b) in self.entries.items():
|
| 185 |
+
if a <= span['start'] < b:
|
| 186 |
+
return ('entry', key)
|
| 187 |
+
para = self.paragraph_of(span['start'])
|
| 188 |
+
if para is None:
|
| 189 |
+
return None
|
| 190 |
+
for key, rng in self.messages.items():
|
| 191 |
+
if rng == para:
|
| 192 |
+
return ('message', key)
|
| 193 |
+
for key, rng in self.minutes.items():
|
| 194 |
+
if rng == para:
|
| 195 |
+
return ('minute', key)
|
| 196 |
+
return None
|
| 197 |
+
|
| 198 |
+
def references(self, sentence):
|
| 199 |
+
"""Containers a withdrawal-type sentence refers to."""
|
| 200 |
+
out = []
|
| 201 |
+
for m in _REF_ENTRY.finditer(sentence):
|
| 202 |
+
out.append(('entry', (m.group(2), m.group(1))))
|
| 203 |
+
for m in _REF_DATE.finditer(sentence):
|
| 204 |
+
out.append(('message', m.group(1)))
|
| 205 |
+
for m in _REF_MINUTE.finditer(sentence):
|
| 206 |
+
out.append(('minute', m.group(1)))
|
| 207 |
+
return out
|
| 208 |
+
|
| 209 |
+
def container_range(self, ref):
|
| 210 |
+
kind, key = ref
|
| 211 |
+
return {'entry': self.entries, 'message': self.messages, 'minute': self.minutes}[kind].get(key)
|
| 212 |
+
|
| 213 |
+
def locators(self, span):
|
| 214 |
+
"""Header ranges that place a span in its container (never the span's own text)."""
|
| 215 |
+
text, out = self.text, []
|
| 216 |
+
para = self.paragraph_of(span['start'])
|
| 217 |
+
if para is None:
|
| 218 |
+
return out
|
| 219 |
+
a, b = para
|
| 220 |
+
nl = text.find('\n', a, b)
|
| 221 |
+
if nl >= 0 and span['start'] > nl:
|
| 222 |
+
out.append((a, nl)) # first line of a multi-line block: message/section/schedule heading
|
| 223 |
+
else:
|
| 224 |
+
m = _MINUTE_HEAD.match(text, a)
|
| 225 |
+
if m and m.end() <= span['start']:
|
| 226 |
+
out.append((a, m.end())) # numbered minute and its heading
|
| 227 |
+
line = self.line_of(span['start'])
|
| 228 |
+
if line and line[0] < span['start']:
|
| 229 |
+
prefix = text[line[0]:span['start']]
|
| 230 |
+
if len(prefix) <= 16 and _ENTRY_PREFIX.fullmatch(prefix):
|
| 231 |
+
out.append((line[0], span['start'])) # entry / clause number
|
| 232 |
+
return out
|
| 233 |
+
|
| 234 |
+
def sentence_ranges_in(self, rng):
|
| 235 |
+
a, b = rng
|
| 236 |
+
return [s for s in self.sentences if a <= s['start'] < b]
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
def _strip(text, a, b):
|
| 240 |
+
while a < b and text[a].isspace():
|
| 241 |
+
a += 1
|
| 242 |
+
while b > a and text[b - 1].isspace():
|
| 243 |
+
b -= 1
|
| 244 |
+
return a, b
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
def _merge(text, items):
|
| 248 |
+
"""items: (start, end, role, reason) -> merged validated ranges; evidence role wins on overlap."""
|
| 249 |
+
cleaned = []
|
| 250 |
+
for a, b, role, reason in items:
|
| 251 |
+
a, b = _strip(text, a, b)
|
| 252 |
+
if a < b:
|
| 253 |
+
cleaned.append((a, b, role, reason))
|
| 254 |
+
cleaned.sort()
|
| 255 |
+
merged = []
|
| 256 |
+
for a, b, role, reason in cleaned:
|
| 257 |
+
if merged and a <= merged[-1]['end']:
|
| 258 |
+
m = merged[-1]
|
| 259 |
+
m['end'] = max(m['end'], b)
|
| 260 |
+
m['roles'].add(role)
|
| 261 |
+
m['reasons'].add(reason)
|
| 262 |
+
else:
|
| 263 |
+
merged.append({'start': a, 'end': b, 'roles': {role}, 'reasons': {reason}})
|
| 264 |
+
h = digest(text)
|
| 265 |
+
out = [{'id': f"text:{m['start']}:{m['end']}", 'kind': 'text', 'start': m['start'], 'end': m['end'],
|
| 266 |
+
'text': text[m['start']:m['end']], 'source_sha256': h,
|
| 267 |
+
'role': 'evidence' if 'evidence' in m['roles'] else 'context', 'reasons': sorted(m['reasons'])} for m in merged]
|
| 268 |
+
validate_spans(text, out)
|
| 269 |
+
return out
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
def render(text, spans):
|
| 273 |
+
"""Source-order rendering; separators are whitespace only and mirror the source layout."""
|
| 274 |
+
parts, last = [], None
|
| 275 |
+
for s in sorted(spans, key=lambda s: s['start']):
|
| 276 |
+
if last is not None:
|
| 277 |
+
gap = text[last:s['start']]
|
| 278 |
+
parts.append('\n\n' if '\n\n' in gap or re.search(r'\n\s*\n', gap) else ('\n' if '\n' in gap else ' '))
|
| 279 |
+
parts.append(text[s['start']:s['end']])
|
| 280 |
+
last = s['end']
|
| 281 |
+
return ''.join(parts)
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
def build(text, question, evidence, *, subject=None, structure=None, options=None, cap=SIZE_CAP):
|
| 285 |
+
"""One unit's evidence package.
|
| 286 |
+
|
| 287 |
+
evidence: selected (or gold, for oracle diagnostics) source spans for this unit.
|
| 288 |
+
subject: optional explicit subject string (entity name); otherwise rare capitalised question tokens.
|
| 289 |
+
"""
|
| 290 |
+
opts = {'header': True, 'interpretation': True, 'locator': True, 'correction': True, 'withdrawn': True,
|
| 291 |
+
'rule': True, 'exception': True, 'definition': True, 'condition': True, 'convention': True, **(options or {})}
|
| 292 |
+
st = structure or Structure(text)
|
| 293 |
+
evidence = validate_spans(text, [{k: s[k] for k in ('start', 'end')} for s in evidence]) if evidence else []
|
| 294 |
+
items = [(s['start'], s['end'], 'evidence', 'selected') for s in evidence]
|
| 295 |
+
subj = st.names(subject if subject else question, limit=10 ** 9 if subject else 16)
|
| 296 |
+
if subject:
|
| 297 |
+
subj |= {subject}
|
| 298 |
+
qtopic = _topic(question, subj)
|
| 299 |
+
rare = st.names(question)
|
| 300 |
+
|
| 301 |
+
def mentions(t):
|
| 302 |
+
return (subject in t) if subject else bool(st.names(t) & rare)
|
| 303 |
+
if opts['header'] and st.paragraphs:
|
| 304 |
+
a, b = st.paragraphs[0]
|
| 305 |
+
items.append((a, min(b, a + 400), 'context', 'header'))
|
| 306 |
+
if opts['interpretation']:
|
| 307 |
+
items += [(a, b, 'context', 'interpretation') for a, b in st.interpretation]
|
| 308 |
+
if evidence:
|
| 309 |
+
included = [dict(s) for s in evidence]
|
| 310 |
+
if opts['rule']:
|
| 311 |
+
for r in st.rules:
|
| 312 |
+
if len(_topic(r['text'], subj) & qtopic) >= (3 if 'Attribute:' in question else 2):
|
| 313 |
+
items.append((r['start'], r['end'], 'context', 'rule'))
|
| 314 |
+
included.append(r)
|
| 315 |
+
# Iterate twice: attached statements can themselves need locators/corrections.
|
| 316 |
+
for _ in range(3):
|
| 317 |
+
current = [{'start': a, 'end': b} for a, b, role, reason in items
|
| 318 |
+
if role == 'evidence' or reason in ('rule', 'exception', 'withdrawn', 'correction', 'definition', 'condition')]
|
| 319 |
+
spans = [s for s in st.sentences if any(max(s['start'], c['start']) < min(s['end'], c['end']) for c in current)]
|
| 320 |
+
for s in spans:
|
| 321 |
+
s_text = s['text']
|
| 322 |
+
if opts['exception'] and s in st.rules:
|
| 323 |
+
for e in st.exceptions:
|
| 324 |
+
g = st.governed_rule(e)
|
| 325 |
+
if g is not None and g['start'] == s['start']:
|
| 326 |
+
items.append((e['start'], e['end'], 'context', 'exception'))
|
| 327 |
+
if opts['exception'] and s in st.exceptions:
|
| 328 |
+
g = st.governed_rule(s)
|
| 329 |
+
if g is not None:
|
| 330 |
+
items.append((g['start'], g['end'], 'context', 'exception'))
|
| 331 |
+
if opts['definition'] and s in st.rules:
|
| 332 |
+
for term in set(re.findall(r'(?<=[a-z,;] )([A-Z][a-z]+ [A-Z][a-z]+?)s?\b', s_text)):
|
| 333 |
+
for d in st.sentences:
|
| 334 |
+
if term in d['text'] and _DEFINES.search(d['text']) and d['start'] < s['start'] and mentions(d['text']):
|
| 335 |
+
items.append((d['start'], d['end'], 'context', 'definition'))
|
| 336 |
+
if opts['condition'] and s in st.rules:
|
| 337 |
+
# Facts about this unit's subject that bear on the rule's conditions or its exception.
|
| 338 |
+
governing = [s] + [e for e in st.exceptions if (st.governed_rule(e) or {}).get('start') == s['start']]
|
| 339 |
+
words = set().union(*(_topic(g['text'], subj) for g in governing)) - qtopic
|
| 340 |
+
for t in st.sentences:
|
| 341 |
+
shared = _topic(t['text'], subj) & words
|
| 342 |
+
if t['start'] != s['start'] and mentions(t['text']) and (len(shared) >= 2 or any(st.df.get(w, 0) <= 3 for w in shared)):
|
| 343 |
+
items.append((t['start'], t['end'], 'context', 'condition'))
|
| 344 |
+
if opts['locator']:
|
| 345 |
+
items += [(a, b, 'context', 'locator') for a, b in st.locators(s)]
|
| 346 |
+
is_withdrawal = bool(_WITHDRAWAL.search(s_text))
|
| 347 |
+
if opts['withdrawn'] and is_withdrawal:
|
| 348 |
+
wnames = st.names(s_text)
|
| 349 |
+
for ref in st.references(s_text):
|
| 350 |
+
rng = st.container_range(ref)
|
| 351 |
+
if rng is None:
|
| 352 |
+
continue
|
| 353 |
+
if ref[0] == 'entry':
|
| 354 |
+
items.append((rng[0], rng[1], 'context', 'withdrawn'))
|
| 355 |
+
continue
|
| 356 |
+
for t in st.sentence_ranges_in(rng):
|
| 357 |
+
if t['start'] == s['start']:
|
| 358 |
+
continue
|
| 359 |
+
if st.names(t['text']) & wnames and _topic(t['text'], wnames) & _topic(s_text, wnames):
|
| 360 |
+
items.append((t['start'], t['end'], 'context', 'withdrawn'))
|
| 361 |
+
if opts['correction'] and not is_withdrawal:
|
| 362 |
+
where = st.container(s)
|
| 363 |
+
if where is None:
|
| 364 |
+
continue
|
| 365 |
+
snames = st.names(s_text)
|
| 366 |
+
for w in st.withdrawals:
|
| 367 |
+
if w['start'] == s['start'] or where not in st.references(w['text']):
|
| 368 |
+
continue
|
| 369 |
+
if where[0] == 'entry' or (st.names(w['text']) & snames and _topic(w['text'], snames) & _topic(s_text, snames)):
|
| 370 |
+
items.append((w['start'], w['end'], 'context', 'correction'))
|
| 371 |
+
if opts['convention']:
|
| 372 |
+
reasons = {r for _, _, _, r in items}
|
| 373 |
+
ev_text = ' '.join(text[a:b] for a, b, role, _ in items if role == 'evidence')
|
| 374 |
+
wanted = {'silence'}
|
| 375 |
+
if evidence:
|
| 376 |
+
wanted |= {'conflict', 'vocabulary'}
|
| 377 |
+
if reasons & {'correction', 'withdrawn'} or _WITHDRAWAL.search(ev_text):
|
| 378 |
+
wanted.add('removal')
|
| 379 |
+
if 'rule' in reasons or any(r['start'] < b and a < r['end'] for r in st.rules if not _SCALE.search(r['text'])
|
| 380 |
+
for a, b, role, _ in items if role == 'evidence'):
|
| 381 |
+
wanted.add('condition')
|
| 382 |
+
if 'exception' in reasons:
|
| 383 |
+
wanted.add('exception')
|
| 384 |
+
for kind in sorted(wanted):
|
| 385 |
+
items += [(a, b, 'context', 'convention/'+kind) for a, b in st.conventions[kind]]
|
| 386 |
+
spans = _merge(text, items);trimmed = []
|
| 387 |
+
def size(sp):return sum(x['end'] - x['start'] for x in sp) / len(text) if text else 0.
|
| 388 |
+
for reason in (TRIM_ORDER if cap is not None else ()):
|
| 389 |
+
if size(spans) <= cap:
|
| 390 |
+
break
|
| 391 |
+
keep = [it for it in items if it[3] != reason]
|
| 392 |
+
if len(keep) != len(items):
|
| 393 |
+
items = keep;trimmed.append(reason);spans = _merge(text, items)
|
| 394 |
+
rendered = render(text, spans)
|
| 395 |
+
covered = sum(s['end'] - s['start'] for s in spans)
|
| 396 |
+
return {'schema': SCHEMA, 'question': question, 'source_sha256': digest(text), 'text': rendered, 'spans': spans,
|
| 397 |
+
'size_cap': cap, 'within_size_cap': cap is None or covered <= cap * len(text), 'trimmed_for_cap': trimmed,
|
| 398 |
+
'evidence_ranges': [{'start': s['start'], 'end': s['end']} for s in evidence],
|
| 399 |
+
'no_support_found': not evidence, 'source_characters': len(text), 'covered_characters': covered,
|
| 400 |
+
'rendered_characters': len(rendered), 'source_fraction': covered / len(text) if text else 0.,
|
| 401 |
+
'context_reasons': sorted({r for s in spans for r in s['reasons'] if r != 'selected'}),
|
| 402 |
+
'faithfulness_established': False}
|
| 403 |
+
|
| 404 |
+
|
| 405 |
+
def union(text, packages):
|
| 406 |
+
"""One document-level package: union of unit packages (used for whole-question rendering)."""
|
| 407 |
+
items = [(s['start'], s['end'], s['role'], r) for p in packages for s in p['spans'] for r in s['reasons']]
|
| 408 |
+
if not items:
|
| 409 |
+
return {'schema': SCHEMA, 'text': '', 'spans': [], 'source_fraction': 0., 'covered_characters': 0,
|
| 410 |
+
'source_characters': len(text), 'rendered_characters': 0, 'source_sha256': digest(text)}
|
| 411 |
+
spans = _merge(text, items)
|
| 412 |
+
rendered = render(text, spans)
|
| 413 |
+
covered = sum(s['end'] - s['start'] for s in spans)
|
| 414 |
+
return {'schema': SCHEMA, 'text': rendered, 'spans': spans, 'source_fraction': covered / len(text),
|
| 415 |
+
'covered_characters': covered, 'source_characters': len(text), 'rendered_characters': len(rendered),
|
| 416 |
+
'source_sha256': digest(text)}
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
def with_pages(package, text, page_map):
|
| 420 |
+
"""Attach renderer page IDs to every package span (scope6.sources.evidence_pages)."""
|
| 421 |
+
from scope6.sources import evidence_pages
|
| 422 |
+
out = dict(package)
|
| 423 |
+
out['spans'] = [{**s, 'pages': evidence_pages(text, [s], page_map)} for s in package['spans']]
|
| 424 |
+
out['pages'] = sorted({p for s in out['spans'] for p in s['pages']})
|
| 425 |
+
return out
|
mlx/src/solomon_mlx/_vendor/prompts.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
| 3 |
+
SYSTEM = 'You answer questions about the supplied document. Use only the document. Task instructions follow the document; follow them exactly.'
|
| 4 |
+
|
| 5 |
+
BOOLEAN_TASK = 'Task: classify the evidence for the question using only the document and its explicit rules. A = Yes only. B = No only. C = neither Yes nor No is established. D = both Yes and No are established. A missing fact is not a negative fact. Evidence about another person or subject does not contradict the queried one. Apply explicit time and replacement rules before deciding. Respond with exactly one letter: A, B, C, or D. Do not explain.'
|
| 6 |
+
|
| 7 |
+
CHOICE_TASK = 'Task: choose the single option that the document best supports. Respond with exactly one letter. Do not explain.'
|
| 8 |
+
|
| 9 |
+
def boolean_block(question):
|
| 10 |
+
return BOOLEAN_TASK + '\nQuestion: ' + question + '\nAnswer (one letter):'
|
| 11 |
+
LETTERS = 'ABCDEFGHIJ'
|
| 12 |
+
|
| 13 |
+
PAGE = '<|vision_start|><|image_pad|><|vision_end|>'
|
| 14 |
+
|
| 15 |
+
RESERVED = ['The document does not state this', 'The document gives conflicting answers']
|
| 16 |
+
|
| 17 |
+
SINGLE_R = 'Task: choose the single option that the document establishes as the answer. If the document does not establish any of the other listed answers, choose the option that says it does not state this. If the document establishes two different listed answers and does not say which prevails, choose the option that says it gives conflicting answers. A replaced or withdrawn statement establishes nothing. Respond with exactly one letter. Do not explain.'
|
| 18 |
+
|
| 19 |
+
ORDERED_R = 'Task: the options form an ordered scale, lowest first, followed by two special options. Choose the single level that the document establishes. If the document does not establish any level, choose the option that says it does not state this. If it establishes two different levels and does not say which prevails, choose the option that says it gives conflicting answers. A replaced or withdrawn statement establishes nothing. Respond with exactly one letter. Do not explain.'
|
| 20 |
+
|
| 21 |
+
SINGLE_S = CHOICE_TASK
|
| 22 |
+
|
| 23 |
+
ORDERED_S = 'Task: the options form an ordered scale, lowest first. Choose the single level that the document best supports. Respond with exactly one letter. Do not explain.'
|
| 24 |
+
|
| 25 |
+
SUFFICIENCY = 'Task: classify what the document establishes about the answer to the question, using only the document. A = it establishes exactly one of the listed answers. B = it does not establish any of the listed answers. C = it establishes two or more different listed answers and does not say which prevails. A missing fact is not a negative fact. A replaced or withdrawn statement establishes nothing. Respond with exactly one letter: A, B, or C. Do not explain.'
|
| 26 |
+
|
| 27 |
+
LABEL = 'Task: decide whether the label applies, using only the document. A = the document establishes that it applies, and nothing in it establishes that it does not. B = the document establishes that it does not apply, and nothing in it establishes that it does. C = the document establishes neither. D = the document establishes both. A missing fact is not a negative fact. Evidence about another person or subject does not count. A replaced or withdrawn statement establishes nothing. Respond with exactly one letter: A, B, C, or D. Do not explain.'
|
| 28 |
+
|
| 29 |
+
OPTION = 'Task: decide whether the proposed answer is correct, using only the document. A = the document establishes this answer, and nothing in it establishes a different one. B = the document establishes a different answer, or establishes that this one is wrong, and nothing in it establishes this one. C = the document establishes neither. D = the document establishes both this answer and a different one. A missing fact is not a negative fact. A replaced or withdrawn statement establishes nothing. Respond with exactly one letter: A, B, C, or D. Do not explain.'
|
| 30 |
+
|
| 31 |
+
def _lettered(options):
|
| 32 |
+
return '\n'.join((f'{LETTERS[i]}. {text}' for i, text in enumerate(options)))
|
| 33 |
+
|
| 34 |
+
def listwise_block(question, options, ordered=False, reserved=True):
|
| 35 |
+
"""Caller options in caller order; with `reserved` the service appends the two reserved outcomes."""
|
| 36 |
+
if not 2 <= len(options) <= 8 or len(set(options)) != len(options):
|
| 37 |
+
raise ValueError('needs 2 to 8 distinct options')
|
| 38 |
+
shown = list(options) + (RESERVED if reserved else [])
|
| 39 |
+
task = (ORDERED_R if ordered else SINGLE_R) if reserved else ORDERED_S if ordered else SINGLE_S
|
| 40 |
+
return (task + '\nQuestion: ' + question + '\nOptions:\n' + _lettered(shown) + '\nAnswer (one letter):', len(shown))
|
| 41 |
+
|
| 42 |
+
def label_block(question, label):
|
| 43 |
+
return (LABEL + '\nQuestion: ' + question + '\nLabel: ' + label + '\nAnswer (one letter):', 4)
|
mlx/src/solomon_mlx/_vendor/retrieval.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
| 3 |
+
"""Inference-only source candidates and explicitly labelled retrieval baselines."""
|
| 4 |
+
import re
|
| 5 |
+
from .evidence import digest,rank_candidates,validate_spans
|
| 6 |
+
|
| 7 |
+
def candidates(text):
|
| 8 |
+
"""Source sentences retaining exact character ranges; no authoring labels."""
|
| 9 |
+
ends=[m.end() for m in re.finditer(r'(?<=[.!?])(?:[ \t]+|\n+)|\n\s*\n',text)]+[len(text)]
|
| 10 |
+
result=[];start=0
|
| 11 |
+
for end in ends:
|
| 12 |
+
if end>start and text[start:end].strip():
|
| 13 |
+
result.append({'id':f'text:{start}:{end}','kind':'text','start':start,'end':end,
|
| 14 |
+
'text':text[start:end],'source_sha256':digest(text)})
|
| 15 |
+
start=end
|
| 16 |
+
return result
|
| 17 |
+
|
| 18 |
+
def governing_context(text,spans=None):
|
| 19 |
+
"""Generic rule/retraction interpretation context, independent of question gold."""
|
| 20 |
+
spans=candidates(text) if spans is None else spans
|
| 21 |
+
pattern=re.compile(r'general rule|both limbs|same (?:person|courier|member|officer)|neither limb|missing requirement|silence|withdrawn passage|dates and seniority|a withdrawn|outside these|bands are|order of the levels|no.*precedence|each passage|a grant in force|an exception to a rule',re.I)
|
| 22 |
+
return [s for s in spans if pattern.search(s['text'])]
|
| 23 |
+
|
| 24 |
+
def merge(text,spans):
|
| 25 |
+
intervals=[]
|
| 26 |
+
for span in sorted(spans,key=lambda s:(s['start'],s['end'])):
|
| 27 |
+
a,b=span['start'],span['end']
|
| 28 |
+
if intervals and a<=intervals[-1][1]:intervals[-1]=(intervals[-1][0],max(b,intervals[-1][1]))
|
| 29 |
+
else:intervals.append((a,b))
|
| 30 |
+
result=[{'id':f'text:{a}:{b}','kind':'text','start':a,'end':b,'text':text[a:b],'source_sha256':digest(text)} for a,b in intervals]
|
| 31 |
+
return validate_spans(text,result)
|
| 32 |
+
|
| 33 |
+
def render_subset(text,spans,*,include_context=True):
|
| 34 |
+
selected=merge(text,list(spans)+(governing_context(text) if include_context else []))
|
| 35 |
+
return '\n\n'.join(s['text'] for s in selected),selected
|
| 36 |
+
|
| 37 |
+
_WORD=re.compile(r'\w+')
|
| 38 |
+
_SCALE=re.compile(r'\bbands?\b|\bscale\b|from lowest to highest|order of the levels',re.I)
|
| 39 |
+
POOL_V2={'name':'idf-rare-rule-v2','idf_limit':24,'rare_df':16,'rules':True}
|
| 40 |
+
|
| 41 |
+
def _words(s):return set(_WORD.findall(s.casefold()))
|
| 42 |
+
|
| 43 |
+
def rule_candidates(text,spans=None):
|
| 44 |
+
"""Question-independent rule, exception, withdrawal-convention and scale passages."""
|
| 45 |
+
spans=candidates(text) if spans is None else spans
|
| 46 |
+
rules={s['id'] for s in governing_context(text,spans)}
|
| 47 |
+
return [s for s in spans if s['id'] in rules or _SCALE.search(s['text'])]
|
| 48 |
+
|
| 49 |
+
def candidate_pool(question,spans,text=None,*,idf_limit=24,rare_df=16,rules=True,**_):
|
| 50 |
+
"""Bounded source-only pool: document-IDF top-k, every passage sharing a rare
|
| 51 |
+
question term (typically the subject's name), plus question-independent rules.
|
| 52 |
+
|
| 53 |
+
Candidate order is source order. candidate_score stays the plain lexical-overlap
|
| 54 |
+
fraction used by the frozen relevance-head feature, so heads remain comparable.
|
| 55 |
+
Gold is never an input.
|
| 56 |
+
"""
|
| 57 |
+
import math
|
| 58 |
+
if idf_limit<1 or rare_df<0:raise ValueError('invalid candidate pool policy')
|
| 59 |
+
ranked=rank_candidates(question,spans,len(spans)) if spans else []
|
| 60 |
+
words=[_words(c['text']) for c in ranked];q=_words(question);n=len(ranked)
|
| 61 |
+
df={}
|
| 62 |
+
for ws in words:
|
| 63 |
+
for w in ws:df[w]=df.get(w,0)+1
|
| 64 |
+
idf=[sum(math.log((n+1)/(df[w]+.5)) for w in ws&q) for ws in words]
|
| 65 |
+
order=sorted(range(n),key=lambda i:(-idf[i],ranked[i]['start']))
|
| 66 |
+
reason={}
|
| 67 |
+
for i in order[:idf_limit]:reason.setdefault(ranked[i]['id'],'idf')
|
| 68 |
+
rare={w for w in q if df.get(w,0)<=rare_df}
|
| 69 |
+
for c,ws in zip(ranked,words):
|
| 70 |
+
if ws&rare:reason.setdefault(c['id'],'rare_term')
|
| 71 |
+
if rules:
|
| 72 |
+
for c in rule_candidates(text or '',ranked):reason.setdefault(c['id'],'rule')
|
| 73 |
+
return sorted(({**c,'pool_reason':reason[c['id']]} for c in ranked if c['id'] in reason),key=lambda c:c['start'])
|
| 74 |
+
|
| 75 |
+
_WITHDRAW=re.compile(r'withdr[ae]w|withdrawn|take back|disregard|rescind|retract|should not be relied|there is substituted|is deleted|expressly delete',re.I)
|
| 76 |
+
_REFERENCE=re.compile(r'(?:message of|wrote on|message dated) (\d{1,2} [A-Z][a-z]+)|minute (\d+)|[Ee]ntry (\d+) of [Ss]chedule (\d+)|clause ([\d.]+)|passage in my message')
|
| 77 |
+
_EXCEPTION=re.compile(r'does not apply to|subject to the exception|is an exception|except (?:where|that|for)\b',re.I)
|
| 78 |
+
_STOP={'this','that','these','those','with','under','which','what','does','file','correspondence','record','records','recorded',
|
| 79 |
+
'minutes','agreement','bundle','messages','message','stand','stands','taking','reading','whole','strength','position',
|
| 80 |
+
'open','given','have','been','applies','apply','entitled','allowed','liberty','free','from','there','their','they',
|
| 81 |
+
'decisions','here','schedules','schedule','papers','office','shown','show','shows','case','matters','terms','place','placed'}
|
| 82 |
+
DEPENDENCIES_V1={'name':'withdrawal-exception-v1','withdrawals':True,'exceptions':True,'prune_withdrawn':False,'rare_df':16}
|
| 83 |
+
|
| 84 |
+
def _topic(words,exclude):
|
| 85 |
+
return {w for w in words if len(w)>=4 and w not in _STOP and w not in exclude and not w.isdigit()}
|
| 86 |
+
|
| 87 |
+
def _withdrawn_block(text,passage):
|
| 88 |
+
"""Source range that a withdrawal refers to (dated message or numbered minute); None if not resolvable."""
|
| 89 |
+
m=_REFERENCE.search(passage)
|
| 90 |
+
if not m:return None
|
| 91 |
+
if m.group(1):head=re.search(r'Message \d+\. '+re.escape(m.group(1))+r'\.',text)
|
| 92 |
+
elif m.group(2):head=re.search(r'(?:^|\n)'+m.group(2)+r'\. ',text)
|
| 93 |
+
else:return None
|
| 94 |
+
if not head:return None
|
| 95 |
+
end=text.find('\n\n',head.end());return head.start(),(len(text) if end<0 else end)
|
| 96 |
+
|
| 97 |
+
def dependency_expand(question,spans,selected_ids,text,*,withdrawals=True,exceptions=True,prune_withdrawn=False,rare_df=16,**_):
|
| 98 |
+
"""Complete a unit's selected evidence with its withdrawal/exception dependencies.
|
| 99 |
+
|
| 100 |
+
Source text and the already-selected passages only; never gold. Units with no
|
| 101 |
+
selection are unchanged, so no-positive-support decisions are preserved.
|
| 102 |
+
- withdrawal: a passage with a withdrawal verb AND an explicit reference (message/minute/
|
| 103 |
+
entry/clause) that names the question's subject (a rare capitalised name, also present in a
|
| 104 |
+
selected passage) and its most specific in-source topic word;
|
| 105 |
+
- exception: an exception clause immediately following a selected passage;
|
| 106 |
+
- prune_withdrawn (optional): drop selected passages inside the dated message / numbered
|
| 107 |
+
minute a kept withdrawal refers to, when they share its subject and a topic word.
|
| 108 |
+
Returns {'keep','added','pruned'} as candidate id lists in source order.
|
| 109 |
+
"""
|
| 110 |
+
selected=[s for s in spans if s['id'] in set(selected_ids)]
|
| 111 |
+
if not selected:return {'keep':[],'added':[],'pruned':[]}
|
| 112 |
+
words=[_words(s['text']) for s in spans];df={}
|
| 113 |
+
for ws in words:
|
| 114 |
+
for w in ws:df[w]=df.get(w,0)+1
|
| 115 |
+
# Subject: capitalised non-initial question tokens (names) that are rare in the source.
|
| 116 |
+
names=re.findall(r'(?<!^)(?<![.?!] )\b[A-Z][\w&\'-]*',question.strip())
|
| 117 |
+
subject={w for n in names for w in _words(n) if len(w)>=3 and df.get(w,0)<=rare_df}
|
| 118 |
+
q=_words(question);present=[w for w in _topic(q,subject) if df.get(w,0)]
|
| 119 |
+
# The withdrawal must name the question's most specific in-source topic word (e.g. the attribute).
|
| 120 |
+
topic={min(present,key=lambda w:(df[w],w))} if present else set()
|
| 121 |
+
chosen={s['id'] for s in selected};sel_words=set().union(*(_words(s['text']) for s in selected));added=[]
|
| 122 |
+
for i,(s,ws) in enumerate(zip(spans,words)):
|
| 123 |
+
if s['id'] in chosen:continue
|
| 124 |
+
if (withdrawals and _WITHDRAW.search(s['text']) and _REFERENCE.search(s['text'])
|
| 125 |
+
and ws&subject&sel_words and ws&topic):added.append(s['id']);continue
|
| 126 |
+
if exceptions and i>0 and spans[i-1]['id'] in chosen and _EXCEPTION.search(s['text']):added.append(s['id'])
|
| 127 |
+
keep=chosen|set(added);pruned=[]
|
| 128 |
+
if prune_withdrawn:
|
| 129 |
+
for s,ws in zip(spans,words):
|
| 130 |
+
if s['id'] not in keep or not _WITHDRAW.search(s['text']):continue
|
| 131 |
+
block=_withdrawn_block(text,s['text'])
|
| 132 |
+
if block is None:continue
|
| 133 |
+
key=ws&subject;about=_topic(ws,subject)
|
| 134 |
+
for t,tw in zip(spans,words):
|
| 135 |
+
if (t['id'] in keep and t['id']!=s['id'] and block[0]<=t['start'] and t['end']<=block[1]+2
|
| 136 |
+
and tw&key and tw&about and not _WITHDRAW.search(t['text'])):pruned.append(t['id'])
|
| 137 |
+
order=[s['id'] for s in spans];pruned=set(pruned)
|
| 138 |
+
return {'keep':[i for i in order if i in keep and i not in pruned],'added':[i for i in order if i in set(added)],
|
| 139 |
+
'pruned':[i for i in order if i in pruned]}
|
| 140 |
+
|
| 141 |
+
def lexical_select(text,questions,limit=4):
|
| 142 |
+
source=candidates(text);chosen={}
|
| 143 |
+
for q in questions:
|
| 144 |
+
for candidate in rank_candidates(q,source,limit):
|
| 145 |
+
if candidate['candidate_score']>0:chosen[candidate['id']]=candidate
|
| 146 |
+
return {'evidence':sorted(chosen.values(),key=lambda c:c['start']),
|
| 147 |
+
'method':'lexical_overlap','verification':'retrieval_only','faithfulness_established':False}
|
| 148 |
+
|
| 149 |
+
def remove(text,spans):
|
| 150 |
+
spans=merge(text,spans);cursor=0;parts=[]
|
| 151 |
+
for s in spans:parts.append(text[cursor:s['start']]);cursor=s['end']
|
| 152 |
+
parts.append(text[cursor:]);return ''.join(parts)
|
mlx/src/solomon_mlx/_vendor/semantics.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 Doccy Pty Ltd. Apache-2.0.
|
| 2 |
+
# Adapted from pinned Solomon v1.1; see NOTICE and MODIFICATIONS.md.
|
| 3 |
+
"""Scope 9 answer semantics (docs/plans/2026-09-20-scope9-noul-final-refinement.md §1).
|
| 4 |
+
|
| 5 |
+
Yes/no, entity and multi-label candidates are Nouls: one probability P(yes). Gold yes only when the
|
| 6 |
+
document clearly establishes it; not stated and conflicting are no. Choice (single, ordered) is a
|
| 7 |
+
distribution over the listed options only; reserved-gold items have no Scope 9 target.
|
| 8 |
+
|
| 9 |
+
Works for both readouts: four_collapsed (four-state letter logits A/B/C/D, collapsed) and two_letter (A/B).
|
| 10 |
+
"""
|
| 11 |
+
import numpy as np
|
| 12 |
+
|
| 13 |
+
YES, NO, NOT_STATED, CONFLICTING = 0, 1, 2, 3
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def softmax(x, t=1.0):
|
| 17 |
+
z = np.asarray(x, np.float64) / t
|
| 18 |
+
z = z - z.max()
|
| 19 |
+
e = np.exp(z)
|
| 20 |
+
return e / e.sum()
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def noul_gold(gold4):
|
| 24 |
+
"""Four-state (or two-state) gold -> 1 for yes, 0 for no."""
|
| 25 |
+
return int(int(gold4) == YES)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def noul_logit(letter_logits):
|
| 29 |
+
"""Binary log-odds z = log P(yes)/P(no) of a Noul branch: letter A against everything else."""
|
| 30 |
+
logits = np.asarray(letter_logits, np.float64)
|
| 31 |
+
if len(logits) not in (2, 4):
|
| 32 |
+
raise ValueError(f'Noul branch must have 2 or 4 letters, got {len(logits)}')
|
| 33 |
+
rest = logits[1:] - logits[1:].max()
|
| 34 |
+
return float(logits[YES] - (logits[1:].max() + np.log(np.exp(rest).sum())))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def p_yes(letter_logits, t=1.0):
|
| 38 |
+
"""P(yes) from a Noul branch: letter A of a 2-letter (two_letter) or 4-state (four_collapsed) readout.
|
| 39 |
+
|
| 40 |
+
Temperature applies to the COLLAPSED binary logit, not to the letters: a Noul is a binary unit whose
|
| 41 |
+
'no' mass may be spread over several reserved letters, so p_yes(t) = sigmoid(z/t) with z = noul_logit.
|
| 42 |
+
At t = 1 this is exactly softmax over the letters at A (the two forms only differ once t != 1, where the
|
| 43 |
+
letterwise form would decay toward 1/len(letters) instead of toward 1/2). scope9.qualification.p_yes and
|
| 44 |
+
abstention_refit/readout.py fit and evaluate the collapsed form, so the serving path must match it.
|
| 45 |
+
"""
|
| 46 |
+
logits = np.asarray(letter_logits, np.float64)
|
| 47 |
+
if len(logits) not in (2, 4):
|
| 48 |
+
raise ValueError(f'Noul branch must have 2 or 4 letters, got {len(logits)}')
|
| 49 |
+
if t == 1.0:
|
| 50 |
+
return float(softmax(logits)[YES])
|
| 51 |
+
z = noul_logit(logits) / float(t)
|
| 52 |
+
return float(1.0 / (1.0 + np.exp(-z))) if z > -700 else 0.0
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def noul_confidence(p):
|
| 56 |
+
return max(p, 1.0 - p)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def listed_gold(gold, n_options):
|
| 60 |
+
"""Listed option index, or None when the old gold was a reserved slot (not stated / none-of-listed / conflicting)."""
|
| 61 |
+
return int(gold) if isinstance(gold, (int, np.integer)) and 0 <= int(gold) < n_options else None
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def listed_probs(letter_logits, n_options, t=1.0):
|
| 65 |
+
"""Choice distribution over the listed options only (reserved slots, if present, are discarded)."""
|
| 66 |
+
return softmax(np.asarray(letter_logits, np.float64)[:n_options], t)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def complement_deviation(p, p_negated):
|
| 70 |
+
"""G3a under Scope 9: a statement and its negation should sum to 1."""
|
| 71 |
+
return abs(p - (1.0 - p_negated))
|
mlx/src/solomon_mlx/api.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Public document-state API and four-state answer semantics."""
|
| 2 |
+
|
| 3 |
+
import copy
|
| 4 |
+
import json
|
| 5 |
+
import math
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
from ._vendor.contract import _state_parts, decision, parse_questions, present
|
| 9 |
+
from ._vendor.prompts import boolean_block, label_block, listwise_block
|
| 10 |
+
from ._vendor.semantics import listed_probs, p_yes
|
| 11 |
+
from .artifacts import digest, sha256
|
| 12 |
+
|
| 13 |
+
TASKS = ("boolean", "single", "ordered", "multilabel", "entity")
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def branches(spec):
|
| 17 |
+
task, req = spec["task"], spec["request"]
|
| 18 |
+
if task == "boolean":
|
| 19 |
+
return [(boolean_block(req["question"]), 4, "boolean/state4")]
|
| 20 |
+
if task in ("single", "ordered"):
|
| 21 |
+
block, width = listwise_block(
|
| 22 |
+
req["question"], req["options"], ordered=task == "ordered", reserved=task == "single"
|
| 23 |
+
)
|
| 24 |
+
return [(block, width, task + ("/choiceR" if task == "single" else "/choiceS"))]
|
| 25 |
+
if task == "entity":
|
| 26 |
+
return [
|
| 27 |
+
(boolean_block(req["template"].replace("{entity}", c)), 4, "entity/state4")
|
| 28 |
+
for c in req["entities"]
|
| 29 |
+
]
|
| 30 |
+
return [(*label_block(req["question"], c), "multilabel/state4") for c in req["labels"]]
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def distributions(spec, rows, temperature):
|
| 34 |
+
if spec["task"] in ("boolean", "entity", "multilabel"):
|
| 35 |
+
values = [p_yes(r["letter_logits"], temperature) for r in rows]
|
| 36 |
+
return [[p, 1 - p] for p in values]
|
| 37 |
+
return [listed_probs(rows[0]["letter_logits"], len(spec["texts"]), temperature).tolist()]
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def ordering_score(values):
|
| 41 |
+
"""Product of per-unit top probabilities; not a calibrated joint probability."""
|
| 42 |
+
if not values:
|
| 43 |
+
raise ValueError("At least one answer unit is required")
|
| 44 |
+
for p in values:
|
| 45 |
+
if len(p) < 2 or not all(math.isfinite(v) and v >= 0 for v in p) or abs(sum(p) - 1) > 1e-6:
|
| 46 |
+
raise ValueError("Invalid answer distribution")
|
| 47 |
+
return math.prod(max(p) for p in values)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class DocumentState:
|
| 51 |
+
def __init__(self, owner, data):
|
| 52 |
+
self._owner, self._data, self.closed = owner, data, False
|
| 53 |
+
self.image_hashes = {p["image"]: sha256(p["image"]) for p in data["parts"] if "image" in p}
|
| 54 |
+
|
| 55 |
+
@property
|
| 56 |
+
def prefix_tokens(self):
|
| 57 |
+
self._check()
|
| 58 |
+
return len(self._data["prefix_ids"])
|
| 59 |
+
|
| 60 |
+
def _check(self):
|
| 61 |
+
if self.closed:
|
| 62 |
+
raise ValueError("Document state is closed")
|
| 63 |
+
if any(sha256(path) != value for path, value in self.image_hashes.items()):
|
| 64 |
+
raise ValueError("Document image changed after prefill")
|
| 65 |
+
|
| 66 |
+
def save(self, path):
|
| 67 |
+
"""Save a source-bound replay recipe, never pickle executable cache objects."""
|
| 68 |
+
self._check()
|
| 69 |
+
body = {
|
| 70 |
+
"format": "solomon-mlx-replay-v1",
|
| 71 |
+
"runtime": self._owner.identity["fingerprint"],
|
| 72 |
+
"parts": self._data["parts"],
|
| 73 |
+
"image_hashes": self.image_hashes,
|
| 74 |
+
"prefix_ids_sha256": digest(self._data["prefix_ids"]),
|
| 75 |
+
}
|
| 76 |
+
Path(path).write_text(json.dumps({**body, "sha256": digest(body)}, indent=2))
|
| 77 |
+
|
| 78 |
+
def close(self):
|
| 79 |
+
with self._owner.engine.lock:
|
| 80 |
+
self._data.clear()
|
| 81 |
+
self.closed = True
|
| 82 |
+
|
| 83 |
+
def __enter__(self):
|
| 84 |
+
self._check()
|
| 85 |
+
return self
|
| 86 |
+
|
| 87 |
+
def __exit__(self, *args):
|
| 88 |
+
self.close()
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
class Solomon:
|
| 92 |
+
@classmethod
|
| 93 |
+
def load(
|
| 94 |
+
cls,
|
| 95 |
+
model_dir,
|
| 96 |
+
profile="quality",
|
| 97 |
+
*,
|
| 98 |
+
chunk_size=2048,
|
| 99 |
+
max_tokens=40960,
|
| 100 |
+
page_selector=None,
|
| 101 |
+
calibration=None,
|
| 102 |
+
):
|
| 103 |
+
if profile != "quality":
|
| 104 |
+
raise ValueError("Only full BF16 quality is implemented; quantization is secondary")
|
| 105 |
+
from .engine import Engine
|
| 106 |
+
|
| 107 |
+
return cls(
|
| 108 |
+
Engine(model_dir, chunk_size=chunk_size, max_tokens=max_tokens),
|
| 109 |
+
page_selector=page_selector,
|
| 110 |
+
calibration=calibration,
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
def __init__(self, engine, *, page_selector=None, calibration=None):
|
| 114 |
+
self.engine, self.identity, self.page_selector = engine, engine.identity, page_selector
|
| 115 |
+
self.temperatures = dict.fromkeys(TASKS, 1.0)
|
| 116 |
+
self.calibration_status = "uncalibrated"
|
| 117 |
+
if calibration is not None:
|
| 118 |
+
artifact = json.loads(Path(calibration).read_text())
|
| 119 |
+
payload = {k: v for k, v in artifact.items() if k != "sha256"}
|
| 120 |
+
if (
|
| 121 |
+
artifact.get("sha256") != digest(payload)
|
| 122 |
+
or artifact["runtime"] != self.identity["fingerprint"]
|
| 123 |
+
):
|
| 124 |
+
raise ValueError("Calibration checksum or MLX runtime identity mismatch")
|
| 125 |
+
temps = artifact["temperatures"]
|
| 126 |
+
if set(temps) != set(TASKS) or any(
|
| 127 |
+
isinstance(v, bool)
|
| 128 |
+
or not isinstance(v, (int, float))
|
| 129 |
+
or not math.isfinite(v)
|
| 130 |
+
or not 0 < v <= 20
|
| 131 |
+
for v in temps.values()
|
| 132 |
+
):
|
| 133 |
+
raise ValueError("Invalid temperatures")
|
| 134 |
+
self.temperatures, self.calibration_status = temps, "profile_fitted"
|
| 135 |
+
|
| 136 |
+
def prefill(self, document):
|
| 137 |
+
parts = copy.deepcopy(_state_parts(document))
|
| 138 |
+
if not parts:
|
| 139 |
+
parts = [{"text": ""}]
|
| 140 |
+
for p in parts:
|
| 141 |
+
if not isinstance(p, dict) or set(p) not in ({"text"}, {"image"}):
|
| 142 |
+
raise ValueError("Each document part must contain only text or image")
|
| 143 |
+
if "text" in p and not isinstance(p["text"], str):
|
| 144 |
+
raise ValueError("Text parts must be strings")
|
| 145 |
+
if "image" in p:
|
| 146 |
+
p["image"] = str(Path(p["image"]).resolve(strict=True))
|
| 147 |
+
hashes = {p["image"]: sha256(p["image"]) for p in parts if "image" in p}
|
| 148 |
+
state = DocumentState(self, self.engine.prefill(parts))
|
| 149 |
+
if state.image_hashes != hashes:
|
| 150 |
+
state.close()
|
| 151 |
+
raise ValueError("Image changed while document was being prefilled")
|
| 152 |
+
return state
|
| 153 |
+
|
| 154 |
+
def replay(self, path):
|
| 155 |
+
body = json.loads(Path(path).read_text())
|
| 156 |
+
expected = body.pop("sha256")
|
| 157 |
+
if (
|
| 158 |
+
digest(body) != expected
|
| 159 |
+
or body["format"] != "solomon-mlx-replay-v1"
|
| 160 |
+
or body["runtime"] != self.identity["fingerprint"]
|
| 161 |
+
):
|
| 162 |
+
raise ValueError("Replay checksum or runtime mismatch")
|
| 163 |
+
if any(sha256(p) != h for p, h in body["image_hashes"].items()):
|
| 164 |
+
raise ValueError("Replay image changed")
|
| 165 |
+
state = self.prefill(body["parts"])
|
| 166 |
+
if digest(state._data["prefix_ids"]) != body["prefix_ids_sha256"]:
|
| 167 |
+
state.close()
|
| 168 |
+
raise ValueError("Replay tokenization differs")
|
| 169 |
+
return state
|
| 170 |
+
|
| 171 |
+
def _answer(self, state, spec, execution="cached"):
|
| 172 |
+
rows = [self.engine.ask(state._data, b, n, h, execution=execution) for b, n, h in branches(spec)]
|
| 173 |
+
dists = distributions(spec, rows, self.temperatures[spec["task"]])
|
| 174 |
+
return {
|
| 175 |
+
**present(spec, dists),
|
| 176 |
+
"ordering_score": ordering_score(dists),
|
| 177 |
+
"temperature": self.temperatures[spec["task"]],
|
| 178 |
+
}, rows
|
| 179 |
+
|
| 180 |
+
def decide(
|
| 181 |
+
self,
|
| 182 |
+
*,
|
| 183 |
+
state,
|
| 184 |
+
questions,
|
| 185 |
+
evidence="support",
|
| 186 |
+
evidence_max_calls=64,
|
| 187 |
+
execution="cached",
|
| 188 |
+
diagnostics=False,
|
| 189 |
+
):
|
| 190 |
+
if not isinstance(state, DocumentState) or state._owner is not self:
|
| 191 |
+
raise ValueError("State belongs to a different model instance")
|
| 192 |
+
if evidence not in ("none", "support", "sufficiency", "removal"):
|
| 193 |
+
raise ValueError("Invalid evidence level")
|
| 194 |
+
if type(evidence_max_calls) is not int or not 0 <= evidence_max_calls <= 512:
|
| 195 |
+
raise ValueError("Invalid evidence call budget")
|
| 196 |
+
specs = parse_questions(questions)
|
| 197 |
+
with self.engine.lock:
|
| 198 |
+
state._check()
|
| 199 |
+
answers, usage = {}, {"branches": 0, "input_tokens": 0, "evidence_calls": 0}
|
| 200 |
+
for spec in specs:
|
| 201 |
+
answer, rows = self._answer(state, spec, execution)
|
| 202 |
+
body = self._evidence(state, spec, answer, evidence, evidence_max_calls)
|
| 203 |
+
answer.update(
|
| 204 |
+
evidence=body["references"], evidence_status=body["status"], evidence_detail=body
|
| 205 |
+
)
|
| 206 |
+
if diagnostics:
|
| 207 |
+
answer["branches"] = rows
|
| 208 |
+
answers[spec["id"]] = answer
|
| 209 |
+
usage["branches"] += len(rows)
|
| 210 |
+
usage["input_tokens"] += sum(
|
| 211 |
+
r["branch_tokens"] if execution == "cached" else r["prompt_tokens"] for r in rows
|
| 212 |
+
)
|
| 213 |
+
usage["evidence_calls"] += body.get("calls", 0)
|
| 214 |
+
return {
|
| 215 |
+
"answers": answers,
|
| 216 |
+
"usage": usage,
|
| 217 |
+
"runtime": self.identity,
|
| 218 |
+
"calibration_status": self.calibration_status,
|
| 219 |
+
"answer_policy": "always_answers",
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
def _fresh(self, document, spec):
|
| 223 |
+
with self.prefill(document) as state:
|
| 224 |
+
answer, _ = self._answer(state, spec)
|
| 225 |
+
return decision(spec, answer)
|
| 226 |
+
|
| 227 |
+
def _evidence(self, state, spec, answer, level, budget):
|
| 228 |
+
from ._vendor import evidence_v3 as v3
|
| 229 |
+
from ._vendor.evidence import image_pages, validate_pages, validate_spans
|
| 230 |
+
from ._vendor.retrieval import lexical_select, remove
|
| 231 |
+
|
| 232 |
+
body = {
|
| 233 |
+
"references": [],
|
| 234 |
+
"status": "not_requested",
|
| 235 |
+
"calls": 0,
|
| 236 |
+
"verification": "none",
|
| 237 |
+
"faithfulness_established": False,
|
| 238 |
+
}
|
| 239 |
+
if level == "none":
|
| 240 |
+
return body
|
| 241 |
+
parts, req = state._data["parts"], spec["request"]
|
| 242 |
+
task = spec["task"]
|
| 243 |
+
if task == "entity":
|
| 244 |
+
questions = [req["template"].replace("{entity}", c) for c in req["entities"]]
|
| 245 |
+
elif task == "multilabel":
|
| 246 |
+
questions = [req["question"] + " Label: " + c for c in req["labels"]]
|
| 247 |
+
else:
|
| 248 |
+
questions = [req["question"] + (" " + " ".join(req["options"]) if "options" in req else "")]
|
| 249 |
+
images = [p["image"] for p in parts if "image" in p]
|
| 250 |
+
needed = (1 if images else len(questions)) if level in ("sufficiency", "removal") else 0
|
| 251 |
+
needed += int(level == "removal")
|
| 252 |
+
if needed > budget:
|
| 253 |
+
return {**body, "status": "budget_exhausted", "required_calls": needed}
|
| 254 |
+
baseline = decision(spec, answer)
|
| 255 |
+
if images:
|
| 256 |
+
if self.page_selector is None:
|
| 257 |
+
return {**body, "status": "unsupported_page_selector", "pages_available": len(images)}
|
| 258 |
+
pages = image_pages(images)
|
| 259 |
+
selector = self.page_selector
|
| 260 |
+
plan = None
|
| 261 |
+
if hasattr(selector, "plan"):
|
| 262 |
+
plan = selector.plan(
|
| 263 |
+
pages, questions, **({"task": task} if getattr(selector, "task_aware", False) else {})
|
| 264 |
+
)
|
| 265 |
+
if type(plan.get("calls")) is not int or plan["calls"] < 0:
|
| 266 |
+
raise ValueError("Invalid page selector call estimate")
|
| 267 |
+
if needed + plan["calls"] > budget:
|
| 268 |
+
return {**body, "status": "budget_exhausted", "required_calls": needed + plan["calls"]}
|
| 269 |
+
selection = (
|
| 270 |
+
selector.execute(plan) if plan is not None else selector(copy.deepcopy(pages), questions)
|
| 271 |
+
)
|
| 272 |
+
calls = selection.get("cost", {}).get("calls", 0)
|
| 273 |
+
if calls != (plan["calls"] if plan is not None else 0):
|
| 274 |
+
raise ValueError("Page selector exceeded its declared call budget")
|
| 275 |
+
refs = validate_pages(pages, selection["evidence"])
|
| 276 |
+
body["calls"] = calls
|
| 277 |
+
selected = {r["page"] for r in refs}
|
| 278 |
+
page, remainder = 0, []
|
| 279 |
+
for part in parts:
|
| 280 |
+
if "image" in part:
|
| 281 |
+
page += 1
|
| 282 |
+
if page in selected:
|
| 283 |
+
continue
|
| 284 |
+
remainder.append(part)
|
| 285 |
+
subsets = [([{"image": r["path"]} for r in refs], spec)]
|
| 286 |
+
else:
|
| 287 |
+
text = "".join(p["text"] for p in parts)
|
| 288 |
+
selection = lexical_select(text, questions)
|
| 289 |
+
refs = validate_spans(text, selection["evidence"])
|
| 290 |
+
structure = v3.Structure(text)
|
| 291 |
+
packages, subsets = [], []
|
| 292 |
+
for i, q in enumerate(questions):
|
| 293 |
+
subject = req["entities"][i] if task == "entity" else None
|
| 294 |
+
package = v3.build(text, q, refs, subject=subject, structure=structure)
|
| 295 |
+
unit = copy.deepcopy(spec)
|
| 296 |
+
if "candidates" in spec:
|
| 297 |
+
candidate = spec["candidates"][i]
|
| 298 |
+
unit["candidates"] = [candidate]
|
| 299 |
+
unit["request"]["entities" if task == "entity" else "labels"] = [candidate]
|
| 300 |
+
subsets.append((package["text"], unit))
|
| 301 |
+
packages.append({k: v for k, v in package.items() if k != "text"})
|
| 302 |
+
body["packages"] = packages
|
| 303 |
+
remainder = remove(text, refs)
|
| 304 |
+
body.update(
|
| 305 |
+
references=refs, status="found" if refs else "no_support_found", verification="retrieval_only"
|
| 306 |
+
)
|
| 307 |
+
if level in ("sufficiency", "removal"):
|
| 308 |
+
predictions = [self._fresh(doc, unit) for doc, unit in subsets]
|
| 309 |
+
assembled = (
|
| 310 |
+
{k: v for d in predictions for k, v in d.items()}
|
| 311 |
+
if "candidates" in spec and not images
|
| 312 |
+
else predictions[0]
|
| 313 |
+
)
|
| 314 |
+
body["evidence_only"] = {"prediction": assembled, "agrees_with_full": assembled == baseline}
|
| 315 |
+
body["calls"] += len(subsets)
|
| 316 |
+
body["verification"] = "fresh_source_reencoding"
|
| 317 |
+
if level == "removal":
|
| 318 |
+
removed = self._fresh(remainder, spec)
|
| 319 |
+
body["evidence_removed"] = {"prediction": removed, "agrees_with_full": removed == baseline}
|
| 320 |
+
body["calls"] += 1
|
| 321 |
+
return body
|
mlx/src/solomon_mlx/artifacts.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Artifact verification and distinct MLX runtime identities."""
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
from importlib.metadata import version
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
SOLOMON_REVISION = "5c0a4a82ddaeca6da2e3013f7045a8196c86957d"
|
| 9 |
+
BASE_REVISION = "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0"
|
| 10 |
+
ADAPTER_SHA = "2addaf841ecc58829ad73081603b8d3e52743c53c6d558a17a1dd30e9bd2dbca"
|
| 11 |
+
HEADS_SHA = "126a9b5487dca937a768a4f228f2d2e7d513900d8ad0e99c4137fbaa42a1aa6f"
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def sha256(path):
|
| 15 |
+
h = hashlib.sha256()
|
| 16 |
+
with Path(path).open("rb") as f:
|
| 17 |
+
for block in iter(lambda: f.read(8 << 20), b""):
|
| 18 |
+
h.update(block)
|
| 19 |
+
return h.hexdigest()
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def digest(value):
|
| 23 |
+
return hashlib.sha256(
|
| 24 |
+
json.dumps(value, sort_keys=True, separators=(",", ":"), allow_nan=False).encode()
|
| 25 |
+
).hexdigest()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def verify_release(root):
|
| 29 |
+
root = Path(root)
|
| 30 |
+
manifest = json.loads((root / "MANIFEST.json").read_text())
|
| 31 |
+
checked = {}
|
| 32 |
+
for row in manifest["files"]:
|
| 33 |
+
rel = row["destination"]
|
| 34 |
+
path = (root / rel).resolve()
|
| 35 |
+
if not path.is_relative_to(root.resolve()):
|
| 36 |
+
raise ValueError("Manifest path escapes source directory")
|
| 37 |
+
expected = row.get("staged_sha256")
|
| 38 |
+
size = row.get("staged_bytes")
|
| 39 |
+
actual = sha256(path)
|
| 40 |
+
if expected and actual != expected:
|
| 41 |
+
raise ValueError(f"Source checksum mismatch: {rel}")
|
| 42 |
+
if size is not None and path.stat().st_size != size:
|
| 43 |
+
raise ValueError(f"Source size mismatch: {rel}")
|
| 44 |
+
checked[rel] = actual
|
| 45 |
+
return checked
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def code_identity():
|
| 49 |
+
root = Path(__file__).parent
|
| 50 |
+
return digest({str(p.relative_to(root)): sha256(p) for p in sorted(root.rglob("*.py"))})
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def runtime_identity(binding, *, chunk_size=2048, max_tokens=40960):
|
| 54 |
+
import platform
|
| 55 |
+
|
| 56 |
+
import mlx.core as mx
|
| 57 |
+
|
| 58 |
+
value = {
|
| 59 |
+
"backend": "mlx-metal",
|
| 60 |
+
"contract": "solomon-mlx-v1",
|
| 61 |
+
"source_contract": "solomon-v1",
|
| 62 |
+
"profile": binding["profile"],
|
| 63 |
+
"chunk_size": chunk_size,
|
| 64 |
+
"max_tokens": max_tokens,
|
| 65 |
+
"metal_device": mx.device_info(),
|
| 66 |
+
"macos_version": platform.mac_ver()[0],
|
| 67 |
+
"model_binding": digest(binding),
|
| 68 |
+
"code_sha256": code_identity(),
|
| 69 |
+
"versions": {p: version(p) for p in ("mlx", "mlx-vlm", "transformers", "numpy", "pillow")},
|
| 70 |
+
"placement": "question",
|
| 71 |
+
"lora_scale": 2.0,
|
| 72 |
+
"answer_projection": "trained-semantic-head-float32",
|
| 73 |
+
"recurrence": "mlx-float32",
|
| 74 |
+
"solomon_revision": SOLOMON_REVISION,
|
| 75 |
+
"base_revision": BASE_REVISION,
|
| 76 |
+
}
|
| 77 |
+
return {**value, "fingerprint": digest(value)}
|
mlx/src/solomon_mlx/budget.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Fail-closed local cost reservations for serialized Modal reference jobs."""
|
| 2 |
+
|
| 3 |
+
import fcntl
|
| 4 |
+
import json
|
| 5 |
+
import math
|
| 6 |
+
import os
|
| 7 |
+
import time
|
| 8 |
+
import uuid
|
| 9 |
+
from contextlib import contextmanager
|
| 10 |
+
from pathlib import Path
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class Budget:
|
| 14 |
+
def __init__(self, path, cap=250.0):
|
| 15 |
+
self.path, self.cap = Path(path), cap
|
| 16 |
+
if not math.isfinite(cap) or not 0 < cap <= 250:
|
| 17 |
+
raise ValueError("The authorized cap is at most US$250")
|
| 18 |
+
|
| 19 |
+
@contextmanager
|
| 20 |
+
def reserve(self, amount, label):
|
| 21 |
+
if not math.isfinite(amount) or amount <= 0:
|
| 22 |
+
raise ValueError("Positive finite reservation required")
|
| 23 |
+
self.path.parent.mkdir(parents=True, exist_ok=True)
|
| 24 |
+
with self.path.with_suffix(".lock").open("a") as lock:
|
| 25 |
+
# Held until the synchronous remote call finishes. Refuse concurrent jobs.
|
| 26 |
+
try:
|
| 27 |
+
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
| 28 |
+
except BlockingIOError:
|
| 29 |
+
raise RuntimeError("Another reference job already owns the GPU budget") from None
|
| 30 |
+
ledger = (
|
| 31 |
+
json.loads(self.path.read_text()) if self.path.exists() else {"cap": self.cap, "entries": []}
|
| 32 |
+
)
|
| 33 |
+
if ledger["cap"] != self.cap:
|
| 34 |
+
raise ValueError("Budget cap changed")
|
| 35 |
+
if any(e["status"] == "reserved" for e in ledger["entries"]):
|
| 36 |
+
raise RuntimeError(
|
| 37 |
+
"Unresolved prior dispatch: reconcile its remote status before another GPU job"
|
| 38 |
+
)
|
| 39 |
+
if any(
|
| 40 |
+
type(e.get("reserved_usd")) not in (int, float)
|
| 41 |
+
or not math.isfinite(e["reserved_usd"])
|
| 42 |
+
or e["reserved_usd"] <= 0
|
| 43 |
+
or e.get("status") not in ("reserved", "completed_conservative_charge")
|
| 44 |
+
for e in ledger["entries"]
|
| 45 |
+
):
|
| 46 |
+
raise ValueError("Corrupt budget ledger")
|
| 47 |
+
used = sum(e["reserved_usd"] for e in ledger["entries"])
|
| 48 |
+
if used + amount > self.cap:
|
| 49 |
+
raise RuntimeError("Modal budget exhausted before dispatch")
|
| 50 |
+
entry = {
|
| 51 |
+
"id": uuid.uuid4().hex,
|
| 52 |
+
"label": label,
|
| 53 |
+
"reserved_usd": amount,
|
| 54 |
+
"status": "reserved",
|
| 55 |
+
"time": time.time(),
|
| 56 |
+
}
|
| 57 |
+
ledger["entries"].append(entry)
|
| 58 |
+
self._write(ledger)
|
| 59 |
+
# If interrupted, leave the reservation unresolved.
|
| 60 |
+
yield entry
|
| 61 |
+
entry["status"] = "completed_conservative_charge"
|
| 62 |
+
entry["completed"] = time.time()
|
| 63 |
+
self._write(ledger)
|
| 64 |
+
|
| 65 |
+
def _write(self, value):
|
| 66 |
+
tmp = self.path.with_suffix(".tmp")
|
| 67 |
+
with tmp.open("w") as file:
|
| 68 |
+
file.write(json.dumps(value, indent=2))
|
| 69 |
+
file.flush()
|
| 70 |
+
os.fsync(file.fileno())
|
| 71 |
+
tmp.replace(self.path)
|
mlx/src/solomon_mlx/cli.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def main():
|
| 7 |
+
parser = argparse.ArgumentParser(description="Private Solomon BF16 MLX tooling")
|
| 8 |
+
commands = parser.add_subparsers(dest="command", required=True)
|
| 9 |
+
verify = commands.add_parser("verify-source")
|
| 10 |
+
verify.add_argument("directory")
|
| 11 |
+
download = commands.add_parser("download-base")
|
| 12 |
+
download.add_argument("--output", default="snapshots/base")
|
| 13 |
+
convert = commands.add_parser("prepare")
|
| 14 |
+
convert.add_argument("--base", default="snapshots/base")
|
| 15 |
+
convert.add_argument("--solomon", default="snapshots/solomon")
|
| 16 |
+
convert.add_argument("--manifest", default="snapshots/base-manifest.json")
|
| 17 |
+
convert.add_argument("--output", default="models/quality")
|
| 18 |
+
decide = commands.add_parser("decide")
|
| 19 |
+
decide.add_argument("--model", default="models/quality")
|
| 20 |
+
decide.add_argument("--document", required=True)
|
| 21 |
+
decide.add_argument("--questions", required=True)
|
| 22 |
+
decide.add_argument(
|
| 23 |
+
"--evidence", choices=["none", "support", "sufficiency", "removal"], default="support"
|
| 24 |
+
)
|
| 25 |
+
args = parser.parse_args()
|
| 26 |
+
if args.command == "verify-source":
|
| 27 |
+
from .artifacts import verify_release
|
| 28 |
+
|
| 29 |
+
print(json.dumps(verify_release(args.directory), indent=2))
|
| 30 |
+
elif args.command == "download-base":
|
| 31 |
+
from huggingface_hub import HfApi, snapshot_download
|
| 32 |
+
|
| 33 |
+
from .artifacts import BASE_REVISION
|
| 34 |
+
from .prepare import verify_base
|
| 35 |
+
|
| 36 |
+
model = HfApi().model_info("Qwen/Qwen3.8-27B", revision=BASE_REVISION, files_metadata=True)
|
| 37 |
+
manifest = {
|
| 38 |
+
"revision": model.sha,
|
| 39 |
+
"files": [
|
| 40 |
+
{
|
| 41 |
+
"name": f.rfilename,
|
| 42 |
+
"size": f.size,
|
| 43 |
+
"blob_id": f.blob_id,
|
| 44 |
+
"sha256": f.lfs.sha256 if f.lfs else None,
|
| 45 |
+
}
|
| 46 |
+
for f in model.siblings
|
| 47 |
+
],
|
| 48 |
+
}
|
| 49 |
+
Path(args.output).parent.mkdir(parents=True, exist_ok=True)
|
| 50 |
+
Path(args.output + "-manifest.json").write_text(json.dumps(manifest, indent=2))
|
| 51 |
+
snapshot_download("Qwen/Qwen3.8-27B", revision=BASE_REVISION, local_dir=args.output, max_workers=18)
|
| 52 |
+
verified = verify_base(args.output, manifest)
|
| 53 |
+
Path(args.output + "-verified.json").write_text(json.dumps(verified, indent=2))
|
| 54 |
+
elif args.command == "prepare":
|
| 55 |
+
from .prepare import prepare
|
| 56 |
+
|
| 57 |
+
prepare(args.base, args.solomon, args.output, args.manifest)
|
| 58 |
+
else:
|
| 59 |
+
from .api import Solomon
|
| 60 |
+
|
| 61 |
+
model = Solomon.load(args.model)
|
| 62 |
+
with model.prefill(Path(args.document).read_text()) as state:
|
| 63 |
+
print(
|
| 64 |
+
json.dumps(
|
| 65 |
+
model.decide(
|
| 66 |
+
state=state,
|
| 67 |
+
questions=json.loads(Path(args.questions).read_text()),
|
| 68 |
+
evidence=args.evidence,
|
| 69 |
+
),
|
| 70 |
+
indent=2,
|
| 71 |
+
)
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
if __name__ == "__main__":
|
| 76 |
+
main()
|
mlx/src/solomon_mlx/engine.py
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""BF16 Metal execution with instance-owned adaptation and isolated question caches."""
|
| 2 |
+
|
| 3 |
+
import copy
|
| 4 |
+
import json
|
| 5 |
+
import threading
|
| 6 |
+
import time
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
import mlx.core as mx
|
| 10 |
+
import numpy as np
|
| 11 |
+
from mlx import nn
|
| 12 |
+
from PIL import Image
|
| 13 |
+
|
| 14 |
+
from ._vendor.prompts import PAGE, SYSTEM
|
| 15 |
+
from .artifacts import ADAPTER_SHA, BASE_REVISION, HEADS_SHA, SOLOMON_REVISION, runtime_identity, sha256
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class SwitchLoRA(nn.Module):
|
| 19 |
+
def __init__(self, linear, a, b, context):
|
| 20 |
+
super().__init__()
|
| 21 |
+
self.linear, self.lora_a, self.lora_b = linear, a, b
|
| 22 |
+
self._context = context
|
| 23 |
+
|
| 24 |
+
def __call__(self, x):
|
| 25 |
+
y = self.linear(x)
|
| 26 |
+
start = self._context["start"]
|
| 27 |
+
if start is None or start >= x.shape[1]:
|
| 28 |
+
return y
|
| 29 |
+
delta = (2.0 * ((x[:, start:].astype(mx.float32) @ self.lora_a) @ self.lora_b)).astype(y.dtype)
|
| 30 |
+
return y + delta if start == 0 else mx.concatenate([y[:, :start], y[:, start:] + delta], axis=1)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def fork_cache(caches):
|
| 34 |
+
"""New cache containers and array handles; MLX owns copy-on-write storage.
|
| 35 |
+
|
| 36 |
+
mx.array creates a distinct handle, so slice updates cannot change a prefix's
|
| 37 |
+
Python array. Recurrent/window updates replace the branch's private slots.
|
| 38 |
+
"""
|
| 39 |
+
from mlx_vlm.models.cache import ArraysCache, KVCache
|
| 40 |
+
|
| 41 |
+
result = []
|
| 42 |
+
for original in caches:
|
| 43 |
+
if isinstance(original, ArraysCache):
|
| 44 |
+
branch = ArraysCache(len(original.cache))
|
| 45 |
+
branch.cache = [None if x is None else mx.array(x) for x in original.cache]
|
| 46 |
+
elif isinstance(original, KVCache):
|
| 47 |
+
branch = KVCache()
|
| 48 |
+
branch.state = tuple(None if x is None else mx.array(x) for x in original.state)
|
| 49 |
+
else:
|
| 50 |
+
raise TypeError(f"Unsupported prefix cache: {type(original).__name__}")
|
| 51 |
+
result.append(branch)
|
| 52 |
+
return result
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class Engine:
|
| 56 |
+
def __init__(self, directory, *, chunk_size=2048, max_tokens=40960):
|
| 57 |
+
from mlx_vlm.models.qwen3_vl.processing_qwen3_vl import Qwen3VLProcessor
|
| 58 |
+
from mlx_vlm.utils import load_model
|
| 59 |
+
|
| 60 |
+
self.directory = Path(directory).resolve()
|
| 61 |
+
self.binding = json.loads((self.directory / "binding.json").read_text())
|
| 62 |
+
if (
|
| 63 |
+
self.binding.get("schema") != "solomon-mlx-binding-v1"
|
| 64 |
+
or self.binding.get("base_revision") != BASE_REVISION
|
| 65 |
+
or self.binding.get("solomon_revision") != SOLOMON_REVISION
|
| 66 |
+
):
|
| 67 |
+
raise ValueError("Unrecognized or unpinned Solomon MLX binding")
|
| 68 |
+
if self.binding["profile"] != "quality" or self.binding["dtype"] != "bfloat16":
|
| 69 |
+
raise ValueError("This runtime currently accepts only the BF16 quality profile")
|
| 70 |
+
for name, expected in self.binding["files"].items():
|
| 71 |
+
path = (self.directory / name).resolve()
|
| 72 |
+
if not path.is_relative_to(self.directory) or sha256(path) != expected:
|
| 73 |
+
raise ValueError(f"Model artifact checksum mismatch: {name}")
|
| 74 |
+
adapter, heads = self.directory / "adapter.safetensors", self.directory / "heads.npz"
|
| 75 |
+
if sha256(adapter) != ADAPTER_SHA or sha256(heads) != HEADS_SHA:
|
| 76 |
+
raise ValueError("Solomon checkpoint identity mismatch")
|
| 77 |
+
if not 1 <= chunk_size <= 2048 or not 1 <= max_tokens <= 40960:
|
| 78 |
+
raise ValueError("Invalid chunk size or context ceiling")
|
| 79 |
+
weight_bytes = sum(
|
| 80 |
+
(self.directory / name).stat().st_size
|
| 81 |
+
for name in self.binding["files"]
|
| 82 |
+
if name.endswith((".safetensors", ".npz"))
|
| 83 |
+
)
|
| 84 |
+
if weight_bytes + 4 * 2**30 > mx.device_info()["max_recommended_working_set_size"]:
|
| 85 |
+
raise MemoryError(
|
| 86 |
+
"Full BF16 weights and minimum workspace exceed this Mac’s recommended Metal working set"
|
| 87 |
+
)
|
| 88 |
+
self.chunk_size, self.max_tokens = chunk_size, max_tokens
|
| 89 |
+
self.lock = threading.RLock()
|
| 90 |
+
self.context = {"start": None}
|
| 91 |
+
self.model = load_model(self.directory / "backbone", lazy=True, strict=True)
|
| 92 |
+
self.processor = Qwen3VLProcessor.from_pretrained(
|
| 93 |
+
str(self.directory / "backbone"), trust_remote_code=False
|
| 94 |
+
)
|
| 95 |
+
self.lm, self.t = self.model.language_model, self.processor.tokenizer
|
| 96 |
+
self.pad = self.t.convert_tokens_to_ids("<|image_pad|>")
|
| 97 |
+
weights = mx.load(str(adapter))
|
| 98 |
+
for name in sorted({key.rsplit(".", 1)[0] for key in weights}):
|
| 99 |
+
parts = name.split(".")
|
| 100 |
+
if parts[:2] != ["model", "layers"]:
|
| 101 |
+
raise ValueError(f"Unexpected adapter target: {name}")
|
| 102 |
+
owner = self.lm.model.layers[int(parts[2])]
|
| 103 |
+
for part in parts[3:-1]:
|
| 104 |
+
owner = getattr(owner, part)
|
| 105 |
+
linear = getattr(owner, parts[-1])
|
| 106 |
+
a, b = weights[name + ".lora_a"].astype(mx.float32), weights[name + ".lora_b"].astype(mx.float32)
|
| 107 |
+
if a.shape != (linear.weight.shape[1], 64) or b.shape != (64, linear.weight.shape[0]):
|
| 108 |
+
raise ValueError(f"Adapter orientation/shape mismatch: {name}")
|
| 109 |
+
setattr(owner, parts[-1], SwitchLoRA(linear, a, b, self.context))
|
| 110 |
+
with np.load(heads, allow_pickle=False) as archive:
|
| 111 |
+
keys = {k[:-7] for k in archive.files if k.endswith("/weight")}
|
| 112 |
+
required_heads = {
|
| 113 |
+
"boolean/state4",
|
| 114 |
+
"entity/state4",
|
| 115 |
+
"multilabel/state4",
|
| 116 |
+
"ordered/threshold4",
|
| 117 |
+
"single/choiceR",
|
| 118 |
+
"single/choiceS",
|
| 119 |
+
"single/sufficiency3",
|
| 120 |
+
"ordered/choiceR",
|
| 121 |
+
"ordered/choiceS",
|
| 122 |
+
"ordered/sufficiency3",
|
| 123 |
+
}
|
| 124 |
+
if keys != required_heads:
|
| 125 |
+
raise ValueError("All ten semantic heads are required")
|
| 126 |
+
self.heads = {}
|
| 127 |
+
for key in keys:
|
| 128 |
+
w, b = archive[key + "/weight"], archive[key + "/bias"]
|
| 129 |
+
if (
|
| 130 |
+
w.shape != (10, 5120)
|
| 131 |
+
or b.shape != (10,)
|
| 132 |
+
or not np.isfinite(w).all()
|
| 133 |
+
or not np.isfinite(b).all()
|
| 134 |
+
):
|
| 135 |
+
raise ValueError("Invalid semantic head")
|
| 136 |
+
self.heads[key] = (mx.array(w, mx.float32), mx.array(b, mx.float32))
|
| 137 |
+
self.model.freeze()
|
| 138 |
+
self.model.eval()
|
| 139 |
+
mx.eval(self.model.parameters(), self.heads)
|
| 140 |
+
self.identity = runtime_identity(self.binding, chunk_size=self.chunk_size, max_tokens=self.max_tokens)
|
| 141 |
+
|
| 142 |
+
def render(self, parts, block):
|
| 143 |
+
content = ""
|
| 144 |
+
for i, p in enumerate(parts):
|
| 145 |
+
if "text" in p:
|
| 146 |
+
content += ("\n" if i and "image" in parts[i - 1] else "") + p["text"]
|
| 147 |
+
else:
|
| 148 |
+
content += ("\n" if i and "text" in parts[i - 1] else "") + PAGE
|
| 149 |
+
return self.t.apply_chat_template(
|
| 150 |
+
[
|
| 151 |
+
{"role": "system", "content": SYSTEM},
|
| 152 |
+
{"role": "user", "content": "Document:\n" + content + "\n\n" + block},
|
| 153 |
+
],
|
| 154 |
+
tokenize=False,
|
| 155 |
+
add_generation_prompt=True,
|
| 156 |
+
enable_thinking=False,
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
def expand(self, ids, counts):
|
| 160 |
+
out, index = [], 0
|
| 161 |
+
for token in ids:
|
| 162 |
+
if token == self.pad:
|
| 163 |
+
if index >= len(counts):
|
| 164 |
+
raise ValueError("Unexpected image placeholder in document text")
|
| 165 |
+
out.extend([token] * counts[index])
|
| 166 |
+
index += 1
|
| 167 |
+
else:
|
| 168 |
+
out.append(token)
|
| 169 |
+
if index != len(counts):
|
| 170 |
+
raise ValueError("Image placeholder count mismatch")
|
| 171 |
+
return out
|
| 172 |
+
|
| 173 |
+
def positions(self, start, count):
|
| 174 |
+
return mx.broadcast_to(mx.arange(start, start + count)[None, None, :], (3, 1, count))
|
| 175 |
+
|
| 176 |
+
def admit(self, count):
|
| 177 |
+
if count < 1 or count > self.max_tokens:
|
| 178 |
+
raise ValueError(f"{count} tokens exceeds the {self.max_tokens}-token scope ceiling")
|
| 179 |
+
# Conservative allowance: BF16 attention KV + FP32 recurrent states and
|
| 180 |
+
# chunk intermediates. This supplements the token ceiling, not a promise
|
| 181 |
+
# of availability in the presence of other processes.
|
| 182 |
+
temporary = 4 * 2**30 + count * 16 * 2 * 4 * 256 * 2
|
| 183 |
+
limit = mx.device_info()["max_recommended_working_set_size"]
|
| 184 |
+
if mx.get_active_memory() + temporary > limit:
|
| 185 |
+
raise MemoryError("Insufficient recommended Metal working set for this request")
|
| 186 |
+
|
| 187 |
+
def forward(self, ids, positions, cache, *, embeds=None, adapter_from=None, taps=()):
|
| 188 |
+
hidden, captured = None, {}
|
| 189 |
+
try:
|
| 190 |
+
for start in range(0, len(ids), self.chunk_size):
|
| 191 |
+
end = min(start + self.chunk_size, len(ids))
|
| 192 |
+
self.context["start"] = None if adapter_from is None else max(0, adapter_from - start)
|
| 193 |
+
last = end == len(ids)
|
| 194 |
+
out = self.lm(
|
| 195 |
+
mx.array([ids[start:end]]),
|
| 196 |
+
cache=cache,
|
| 197 |
+
position_ids=positions[:, :, start:end],
|
| 198 |
+
inputs_embeds=None if embeds is None else embeds[:, start:end],
|
| 199 |
+
skip_logits=True,
|
| 200 |
+
return_hidden=last,
|
| 201 |
+
capture_layer_ids=list(taps) if last else None,
|
| 202 |
+
)
|
| 203 |
+
if last:
|
| 204 |
+
hidden = out.hidden_states[-1][0, -1].astype(mx.float32)
|
| 205 |
+
captured = {
|
| 206 |
+
str(i): self.lm.model.norm(h[:, -1:])[0, -1].astype(mx.float32)
|
| 207 |
+
for i, h in zip(sorted(set(taps)), out.hidden_states[:-1])
|
| 208 |
+
}
|
| 209 |
+
mx.eval(hidden, captured)
|
| 210 |
+
mx.eval([c.state for c in cache])
|
| 211 |
+
return hidden, captured
|
| 212 |
+
finally:
|
| 213 |
+
self.context["start"] = None
|
| 214 |
+
|
| 215 |
+
def prefill(self, parts):
|
| 216 |
+
with self.lock:
|
| 217 |
+
prefill_started = time.perf_counter()
|
| 218 |
+
text = self.render(parts, "X")
|
| 219 |
+
boundary = text.rfind("\n\nX")
|
| 220 |
+
if boundary < 0:
|
| 221 |
+
raise ValueError("Missing document boundary")
|
| 222 |
+
raw = self.t.encode(text[:boundary], add_special_tokens=False)
|
| 223 |
+
if "text" in parts[-1]:
|
| 224 |
+
raw = raw[:-1]
|
| 225 |
+
vision_started = time.perf_counter()
|
| 226 |
+
counts, grids, features = [], [], []
|
| 227 |
+
for part in parts:
|
| 228 |
+
if "image" not in part:
|
| 229 |
+
continue
|
| 230 |
+
with Image.open(part["image"]) as image:
|
| 231 |
+
processed = self.processor.image_processor(images=[image.convert("RGB")])
|
| 232 |
+
grid_np = np.asarray(processed["image_grid_thw"])
|
| 233 |
+
count = int(grid_np.prod()) // self.model.config.vision_config.spatial_merge_size**2
|
| 234 |
+
self.admit(len(raw) + sum(counts) + count - len(counts) - 1)
|
| 235 |
+
grid = mx.array(grid_np)
|
| 236 |
+
pixels = mx.array(np.asarray(processed["pixel_values"])).astype(
|
| 237 |
+
self.model.vision_tower.patch_embed.proj.weight.dtype
|
| 238 |
+
)
|
| 239 |
+
feature, _ = self.model.vision_tower(pixels, grid)
|
| 240 |
+
mx.eval(feature)
|
| 241 |
+
counts.append(count)
|
| 242 |
+
grids.append(grid)
|
| 243 |
+
features.append(feature)
|
| 244 |
+
vision_seconds = time.perf_counter() - vision_started if counts else 0.0
|
| 245 |
+
ids = self.expand(raw, counts)
|
| 246 |
+
self.admit(len(ids))
|
| 247 |
+
embeds, delta, feats, grid = None, 0, None, None
|
| 248 |
+
if counts:
|
| 249 |
+
feats, grid = mx.concatenate(features), mx.concatenate(grids)
|
| 250 |
+
f = self.model.get_input_embeddings(
|
| 251 |
+
mx.array([ids]), mx.zeros((1,)), image_grid_thw=grid, cached_image_features=feats
|
| 252 |
+
)
|
| 253 |
+
embeds, positions = f.inputs_embeds, f.position_ids
|
| 254 |
+
delta = int(np.asarray(f.rope_deltas).reshape(-1)[0])
|
| 255 |
+
if delta != int(mx.max(positions).item()) + 1 - len(ids):
|
| 256 |
+
raise ValueError("Multimodal RoPE offset mismatch")
|
| 257 |
+
else:
|
| 258 |
+
positions = self.positions(0, len(ids))
|
| 259 |
+
cache = self.lm.make_cache()
|
| 260 |
+
started = time.perf_counter()
|
| 261 |
+
self.forward(ids, positions, cache, embeds=embeds)
|
| 262 |
+
return {
|
| 263 |
+
"parts": copy.deepcopy(parts),
|
| 264 |
+
"prefix_ids": ids,
|
| 265 |
+
"cache": cache,
|
| 266 |
+
"counts": counts,
|
| 267 |
+
"rope_delta": delta,
|
| 268 |
+
"features": feats,
|
| 269 |
+
"grid": grid,
|
| 270 |
+
"positions": positions,
|
| 271 |
+
"prefill_seconds": time.perf_counter() - prefill_started,
|
| 272 |
+
"language_prefill_seconds": time.perf_counter() - started,
|
| 273 |
+
"vision_seconds": vision_seconds,
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
def ask(self, state, block, width, head, *, execution="cached", taps=()):
|
| 277 |
+
with self.lock:
|
| 278 |
+
if head not in self.heads or not 2 <= width <= 10:
|
| 279 |
+
raise ValueError("Unknown semantic head or invalid width")
|
| 280 |
+
ids = self.expand(
|
| 281 |
+
self.t.encode(self.render(state["parts"], block), add_special_tokens=False), state["counts"]
|
| 282 |
+
)
|
| 283 |
+
self.admit(len(ids))
|
| 284 |
+
p = len(state["prefix_ids"])
|
| 285 |
+
if ids[:p] != state["prefix_ids"]:
|
| 286 |
+
raise ValueError("Question token prefix differs from cached document")
|
| 287 |
+
started = time.perf_counter()
|
| 288 |
+
if execution == "cached":
|
| 289 |
+
hidden, captured = self.forward(
|
| 290 |
+
ids[p:],
|
| 291 |
+
self.positions(p + state["rope_delta"], len(ids) - p),
|
| 292 |
+
fork_cache(state["cache"]),
|
| 293 |
+
adapter_from=0,
|
| 294 |
+
taps=taps,
|
| 295 |
+
)
|
| 296 |
+
elif execution == "full":
|
| 297 |
+
embeds = None
|
| 298 |
+
if state["counts"]:
|
| 299 |
+
f = self.model.get_input_embeddings(
|
| 300 |
+
mx.array([ids]),
|
| 301 |
+
mx.zeros((1,)),
|
| 302 |
+
image_grid_thw=state["grid"],
|
| 303 |
+
cached_image_features=state["features"],
|
| 304 |
+
)
|
| 305 |
+
embeds, positions = f.inputs_embeds, f.position_ids
|
| 306 |
+
else:
|
| 307 |
+
positions = self.positions(0, len(ids))
|
| 308 |
+
hidden, captured = self.forward(
|
| 309 |
+
ids, positions, self.lm.make_cache(), embeds=embeds, adapter_from=p, taps=taps
|
| 310 |
+
)
|
| 311 |
+
else:
|
| 312 |
+
raise ValueError("Execution must be cached or full")
|
| 313 |
+
w, b = self.heads[head]
|
| 314 |
+
logits = (w @ hidden + b)[:width]
|
| 315 |
+
mx.eval(logits)
|
| 316 |
+
values = np.asarray(logits)
|
| 317 |
+
if not np.isfinite(values).all():
|
| 318 |
+
raise ValueError("Nonfinite trained-head output")
|
| 319 |
+
result = {
|
| 320 |
+
"letter_logits": values.tolist(),
|
| 321 |
+
"head_key": head,
|
| 322 |
+
"prompt_tokens": len(ids),
|
| 323 |
+
"branch_tokens": len(ids) - p,
|
| 324 |
+
"reused_prefix_tokens": p if execution == "cached" else 0,
|
| 325 |
+
"seconds": time.perf_counter() - started,
|
| 326 |
+
}
|
| 327 |
+
if taps:
|
| 328 |
+
result.update(
|
| 329 |
+
hidden=np.asarray(hidden).tolist(),
|
| 330 |
+
taps={k: np.asarray(v).tolist() for k, v in captured.items()},
|
| 331 |
+
token_ids=ids,
|
| 332 |
+
)
|
| 333 |
+
return result
|
mlx/src/solomon_mlx/evaluation.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Resumable panel scoring, fit-only calibration and one-shot held-out reports."""
|
| 2 |
+
|
| 3 |
+
import gzip
|
| 4 |
+
import hashlib
|
| 5 |
+
import json
|
| 6 |
+
from collections import defaultdict
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
from scipy.optimize import minimize_scalar
|
| 11 |
+
|
| 12 |
+
from ._vendor.semantics import listed_probs, p_yes
|
| 13 |
+
from .api import TASKS
|
| 14 |
+
from .artifacts import ADAPTER_SHA, HEADS_SHA, digest, sha256
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def load_panel(directory):
|
| 18 |
+
directory = Path(directory)
|
| 19 |
+
manifest = json.loads((directory / "manifest.json").read_text())
|
| 20 |
+
if (
|
| 21 |
+
manifest["adapter_sha256"] != ADAPTER_SHA
|
| 22 |
+
or manifest["heads_sha256"] != HEADS_SHA
|
| 23 |
+
or manifest["readout_mode"] != "four_collapsed"
|
| 24 |
+
):
|
| 25 |
+
raise ValueError("Panel belongs to a different checkpoint or answer semantics")
|
| 26 |
+
raw = gzip.decompress((directory / "jobs.json.gz").read_bytes())
|
| 27 |
+
if hashlib.sha256(raw).hexdigest() != manifest["jobs_sha256"]:
|
| 28 |
+
raise ValueError("Panel jobs checksum mismatch")
|
| 29 |
+
jobs = json.loads(raw)
|
| 30 |
+
if len({r["id"] for r in jobs}) != len(jobs):
|
| 31 |
+
raise ValueError("Duplicate panel branch IDs")
|
| 32 |
+
return jobs, manifest
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def score_panel(model, panel, output):
|
| 36 |
+
"""Atomically persist each document so interruption never requires rescoring it."""
|
| 37 |
+
jobs, manifest = load_panel(panel)
|
| 38 |
+
output = Path(output)
|
| 39 |
+
output.mkdir(parents=True, exist_ok=True)
|
| 40 |
+
identity = {
|
| 41 |
+
"runtime": model.identity,
|
| 42 |
+
"panel_sha256": manifest["jobs_sha256"],
|
| 43 |
+
"panel_role": Path(panel).name.split("-")[0],
|
| 44 |
+
}
|
| 45 |
+
meta = output / "identity.json"
|
| 46 |
+
if meta.exists() and json.loads(meta.read_text()) != identity:
|
| 47 |
+
raise ValueError("Cannot resume with different model code, weights or panel")
|
| 48 |
+
meta.write_text(json.dumps(identity, indent=2))
|
| 49 |
+
documents = defaultdict(list)
|
| 50 |
+
for row in jobs:
|
| 51 |
+
documents[row["document_key"]].append(row)
|
| 52 |
+
for key, group in documents.items():
|
| 53 |
+
path = output / (key + ".json")
|
| 54 |
+
if path.exists():
|
| 55 |
+
record = json.loads(path.read_text())
|
| 56 |
+
body = {k: v for k, v in record.items() if k != "sha256"}
|
| 57 |
+
if (
|
| 58 |
+
record["sha256"] != digest(body)
|
| 59 |
+
or record["identity"] != digest(identity)
|
| 60 |
+
or [r["id"] for r in record["rows"]] != [r["id"] for r in group]
|
| 61 |
+
):
|
| 62 |
+
raise ValueError("Corrupt or mismatched resumed document")
|
| 63 |
+
continue
|
| 64 |
+
parts = group[0].get("parts") or [{"text": group[0]["doc"]}]
|
| 65 |
+
if any((r.get("parts") or [{"text": r["doc"]}]) != parts for r in group):
|
| 66 |
+
raise ValueError("Document key aliases different sources")
|
| 67 |
+
with model.prefill(parts) as state:
|
| 68 |
+
rows = []
|
| 69 |
+
for job in group:
|
| 70 |
+
result = model.engine.ask(state._data, job["block"], job["n"], job["head_key"])
|
| 71 |
+
rows.append({**result, **{k: job[k] for k in ("id", "task", "gold", "n", "question_id")}})
|
| 72 |
+
body = {
|
| 73 |
+
"identity": digest(identity),
|
| 74 |
+
"rows": rows,
|
| 75 |
+
"prefix_tokens": state.prefix_tokens,
|
| 76 |
+
"prefill_seconds": state._data["prefill_seconds"],
|
| 77 |
+
}
|
| 78 |
+
temp = path.with_suffix(".tmp")
|
| 79 |
+
temp.write_text(json.dumps({**body, "sha256": digest(body)}))
|
| 80 |
+
temp.replace(path)
|
| 81 |
+
print("Scored " + key + " " + str(len(rows)) + " branches", flush=True)
|
| 82 |
+
completed = {
|
| 83 |
+
"identity": digest(identity),
|
| 84 |
+
"documents": len(documents),
|
| 85 |
+
"branches": len(jobs),
|
| 86 |
+
"files": {key + ".json": sha256(output / (key + ".json")) for key in documents},
|
| 87 |
+
}
|
| 88 |
+
(output / "complete.json").write_text(json.dumps(completed, indent=2))
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def read_scores(directory):
|
| 92 |
+
directory = Path(directory)
|
| 93 |
+
identity = json.loads((directory / "identity.json").read_text())
|
| 94 |
+
completed = json.loads((directory / "complete.json").read_text())
|
| 95 |
+
if completed["identity"] != digest(identity):
|
| 96 |
+
raise ValueError("Score identity mismatch")
|
| 97 |
+
rows = []
|
| 98 |
+
for name, checksum in completed["files"].items():
|
| 99 |
+
p = directory / name
|
| 100 |
+
if not p.resolve().is_relative_to(directory.resolve()) or sha256(p) != checksum:
|
| 101 |
+
raise ValueError("Score checksum mismatch")
|
| 102 |
+
record = json.loads(p.read_text())
|
| 103 |
+
rows.extend(record["rows"])
|
| 104 |
+
if len(rows) != completed["branches"]:
|
| 105 |
+
raise ValueError("Incomplete score set")
|
| 106 |
+
return rows, identity
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def unit(row, temperature=1.0):
|
| 110 |
+
logits = row["letter_logits"]
|
| 111 |
+
task = row["task"]
|
| 112 |
+
gold = row["gold"]
|
| 113 |
+
if task in ("boolean", "entity", "multilabel"):
|
| 114 |
+
p = p_yes(logits, temperature)
|
| 115 |
+
return [1 - p, p], int(gold == 0)
|
| 116 |
+
width = row["n"] - 2 if row["head_key"].endswith("choiceR") else row["n"]
|
| 117 |
+
if not isinstance(gold, int) or not 0 <= gold < width:
|
| 118 |
+
return None, None
|
| 119 |
+
return listed_probs(logits, width, temperature).tolist(), gold
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def fit_calibration(scores, output, *, panel_role):
|
| 123 |
+
if panel_role != "fit":
|
| 124 |
+
raise ValueError("Temperature fitting accepts fit panels only")
|
| 125 |
+
rows, identity = read_scores(scores)
|
| 126 |
+
if identity["panel_role"] != "fit":
|
| 127 |
+
raise ValueError("Scores were not generated from a fit panel")
|
| 128 |
+
output = Path(output)
|
| 129 |
+
if output.exists():
|
| 130 |
+
raise FileExistsError("Calibration artifacts are immutable")
|
| 131 |
+
temperatures, losses = {}, {}
|
| 132 |
+
for task in TASKS:
|
| 133 |
+
selected = [r for r in rows if r["task"] == task and unit(r)[0] is not None]
|
| 134 |
+
if not selected:
|
| 135 |
+
raise ValueError("No fit examples for " + task)
|
| 136 |
+
|
| 137 |
+
def loss(log_t, selected=selected):
|
| 138 |
+
t = float(np.exp(log_t))
|
| 139 |
+
return float(np.mean([-np.log(max(unit(r, t)[0][unit(r, t)[1]], 1e-300)) for r in selected]))
|
| 140 |
+
|
| 141 |
+
fit = minimize_scalar(loss, bounds=(np.log(0.05), np.log(20)), method="bounded")
|
| 142 |
+
temperatures[task] = float(np.exp(fit.x))
|
| 143 |
+
losses[task] = {"before": loss(0.0), "after": float(fit.fun), "units": len(selected)}
|
| 144 |
+
payload = {
|
| 145 |
+
"schema": "solomon-mlx-temperature-v1",
|
| 146 |
+
"runtime": identity["runtime"]["fingerprint"],
|
| 147 |
+
"temperatures": temperatures,
|
| 148 |
+
"fit_panel_sha256": identity["panel_sha256"],
|
| 149 |
+
"losses": losses,
|
| 150 |
+
"selection_role": "fit",
|
| 151 |
+
"heldout_used": False,
|
| 152 |
+
}
|
| 153 |
+
output.write_text(json.dumps({**payload, "sha256": digest(payload)}, indent=2))
|
| 154 |
+
return payload
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def compare_rows(mlx_rows, cuda_rows, *, temperatures=None, reference_temperatures=None):
|
| 158 |
+
temperatures = temperatures or dict.fromkeys(TASKS, 1.0)
|
| 159 |
+
reference_temperatures = reference_temperatures or dict.fromkeys(TASKS, 1.0)
|
| 160 |
+
reference = {r["id"]: r for r in cuda_rows}
|
| 161 |
+
if len(reference) != len(cuda_rows) or set(reference) != {r["id"] for r in mlx_rows}:
|
| 162 |
+
raise ValueError("Comparison panels have different or duplicate branch IDs")
|
| 163 |
+
units = []
|
| 164 |
+
questions = defaultdict(list)
|
| 165 |
+
for row in mlx_rows:
|
| 166 |
+
other = {**row, "letter_logits": reference[row["id"]]["letter_logits"]}
|
| 167 |
+
p, gold = unit(row, temperatures[row["task"]])
|
| 168 |
+
q, _ = unit(other, reference_temperatures[row["task"]])
|
| 169 |
+
if p is None:
|
| 170 |
+
continue
|
| 171 |
+
left, right = int(np.argmax(p)), int(np.argmax(q))
|
| 172 |
+
item = {
|
| 173 |
+
"agreement": left == right,
|
| 174 |
+
"mlx_correct": left == gold,
|
| 175 |
+
"cuda_correct": right == gold,
|
| 176 |
+
"probability_drift": float(np.max(np.abs(np.asarray(p) - q))),
|
| 177 |
+
}
|
| 178 |
+
units.append(item)
|
| 179 |
+
questions[row["question_id"]].append(item)
|
| 180 |
+
if not units:
|
| 181 |
+
raise ValueError("No defined comparison targets")
|
| 182 |
+
agreement = float(np.mean([r["agreement"] for r in units]))
|
| 183 |
+
question_agreement = float(np.mean([all(x["agreement"] for x in r) for r in questions.values()]))
|
| 184 |
+
mlx_accuracy = float(np.mean([all(x["mlx_correct"] for x in r) for r in questions.values()]))
|
| 185 |
+
cuda_accuracy = float(np.mean([all(x["cuda_correct"] for x in r) for r in questions.values()]))
|
| 186 |
+
return {
|
| 187 |
+
"units": len(units),
|
| 188 |
+
"questions": len(questions),
|
| 189 |
+
"unit_decision_agreement": agreement,
|
| 190 |
+
"question_decision_agreement": float(
|
| 191 |
+
np.mean([all(x["agreement"] for x in r) for r in questions.values()])
|
| 192 |
+
),
|
| 193 |
+
"mlx_whole_question_accuracy": mlx_accuracy,
|
| 194 |
+
"cuda_whole_question_accuracy": cuda_accuracy,
|
| 195 |
+
"accuracy_degradation_percentage_points": 100 * (cuda_accuracy - mlx_accuracy),
|
| 196 |
+
"max_probability_drift": max(r["probability_drift"] for r in units),
|
| 197 |
+
"probability_comparison": {
|
| 198 |
+
"mlx_temperatures": temperatures,
|
| 199 |
+
"cuda_temperatures": reference_temperatures,
|
| 200 |
+
},
|
| 201 |
+
"mean_probability_drift": float(np.mean([r["probability_drift"] for r in units])),
|
| 202 |
+
"quality_gate_passed": agreement >= 0.999
|
| 203 |
+
and question_agreement >= 0.999
|
| 204 |
+
and cuda_accuracy - mlx_accuracy <= 0.0025,
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def read_cuda_scores(directory, panel, reference_identity):
|
| 209 |
+
"""Reuse only scores bound to the exact pinned CUDA runtime and panel."""
|
| 210 |
+
jobs, manifest = load_panel(panel)
|
| 211 |
+
directory = Path(directory)
|
| 212 |
+
result = {}
|
| 213 |
+
for file in sorted(directory.glob("scores*.json.gz")):
|
| 214 |
+
payload = json.loads(gzip.decompress(file.read_bytes()))
|
| 215 |
+
identity = payload["identity"]
|
| 216 |
+
if not payload["complete"] or identity["runtime"] != reference_identity:
|
| 217 |
+
raise ValueError("Existing CUDA scores do not match the fresh reference runtime")
|
| 218 |
+
if identity["manifest"]["jobs_sha256"] != manifest["jobs_sha256"]:
|
| 219 |
+
raise ValueError("CUDA scores use another panel")
|
| 220 |
+
for key, row in payload["scores"].items():
|
| 221 |
+
if key in result:
|
| 222 |
+
raise ValueError("Duplicate CUDA score ID")
|
| 223 |
+
result[key] = row
|
| 224 |
+
if set(result) != {r["id"] for r in jobs}:
|
| 225 |
+
raise ValueError("CUDA score set is incomplete")
|
| 226 |
+
return [{**r, **result[r["id"]]} for r in jobs]
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
def select_calibration(fitted, dev_scores, output):
|
| 230 |
+
fitted, output = Path(fitted), Path(output)
|
| 231 |
+
if output.exists():
|
| 232 |
+
raise FileExistsError("Selected calibration is immutable")
|
| 233 |
+
fit = json.loads(fitted.read_text())
|
| 234 |
+
fit_payload = {k: v for k, v in fit.items() if k != "sha256"}
|
| 235 |
+
rows, identity = read_scores(dev_scores)
|
| 236 |
+
if (
|
| 237 |
+
fit["sha256"] != digest(fit_payload)
|
| 238 |
+
or identity["runtime"]["fingerprint"] != fit["runtime"]
|
| 239 |
+
or identity["panel_role"] != "dev"
|
| 240 |
+
):
|
| 241 |
+
raise ValueError("Calibration or development identity mismatch")
|
| 242 |
+
temperatures, selection = {}, {}
|
| 243 |
+
for task in TASKS:
|
| 244 |
+
selected = [r for r in rows if r["task"] == task and unit(r)[0] is not None]
|
| 245 |
+
if not selected:
|
| 246 |
+
raise ValueError("Missing development task " + task)
|
| 247 |
+
|
| 248 |
+
def loss(t, selected=selected):
|
| 249 |
+
values = [unit(r, t) for r in selected]
|
| 250 |
+
return float(np.mean([-np.log(max(p[g], 1e-300)) for p, g in values]))
|
| 251 |
+
|
| 252 |
+
original, candidate = loss(1.0), loss(fit["temperatures"][task])
|
| 253 |
+
temperatures[task] = fit["temperatures"][task] if candidate < original else 1.0
|
| 254 |
+
selection[task] = {"untempered_nll": original, "fit_temperature_nll": candidate}
|
| 255 |
+
payload = {
|
| 256 |
+
**fit_payload,
|
| 257 |
+
"temperatures": temperatures,
|
| 258 |
+
"selection_role": "dev_selected",
|
| 259 |
+
"fit_artifact_sha256": sha256(fitted),
|
| 260 |
+
"dev_panel_sha256": identity["panel_sha256"],
|
| 261 |
+
"development_selection": selection,
|
| 262 |
+
}
|
| 263 |
+
output.write_text(json.dumps({**payload, "sha256": digest(payload)}, indent=2))
|
| 264 |
+
return payload
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def heldout_report(
|
| 268 |
+
scores,
|
| 269 |
+
cuda_directory,
|
| 270 |
+
panel,
|
| 271 |
+
calibration,
|
| 272 |
+
reference,
|
| 273 |
+
output,
|
| 274 |
+
*,
|
| 275 |
+
reference_binding="evaluations/cuda-acceptance/input/serving-binding.json",
|
| 276 |
+
):
|
| 277 |
+
"""Evaluate a frozen configuration once; an existing output cannot be replaced."""
|
| 278 |
+
output = Path(output)
|
| 279 |
+
if output.exists():
|
| 280 |
+
raise FileExistsError("Held-out report already exists; do not reuse it for selection")
|
| 281 |
+
rows, identity = read_scores(scores)
|
| 282 |
+
cal = json.loads(Path(calibration).read_text())
|
| 283 |
+
payload = {k: v for k, v in cal.items() if k != "sha256"}
|
| 284 |
+
if (
|
| 285 |
+
cal["sha256"] != digest(payload)
|
| 286 |
+
or cal["runtime"] != identity["runtime"]["fingerprint"]
|
| 287 |
+
or cal["selection_role"] != "dev_selected"
|
| 288 |
+
or identity["panel_role"] != "cert"
|
| 289 |
+
):
|
| 290 |
+
raise ValueError(
|
| 291 |
+
"Held-out evaluation requires frozen development-selected calibration and cert scores"
|
| 292 |
+
)
|
| 293 |
+
ref = json.loads(Path(reference).read_text())
|
| 294 |
+
cuda = read_cuda_scores(cuda_directory, panel, ref["identity"])
|
| 295 |
+
binding_path = Path(reference_binding)
|
| 296 |
+
source_manifest = json.loads((binding_path.parent / "manifest.json").read_text())
|
| 297 |
+
if sha256(binding_path) != source_manifest["files"][binding_path.name]:
|
| 298 |
+
raise ValueError("CUDA acceptance binding checksum mismatch")
|
| 299 |
+
binding = json.loads(binding_path.read_text())
|
| 300 |
+
for key in (
|
| 301 |
+
"adapter_sha256",
|
| 302 |
+
"trained_heads_sha256",
|
| 303 |
+
"model_sha256",
|
| 304 |
+
"numerics",
|
| 305 |
+
"placement",
|
| 306 |
+
"arithmetic",
|
| 307 |
+
):
|
| 308 |
+
if binding["runtime"][key] != ref["identity"][key]:
|
| 309 |
+
raise ValueError("CUDA calibration belongs to another reference runtime")
|
| 310 |
+
reference_temperatures = {task: binding["temperatures"]["models"][task]["temperature"] for task in TASKS}
|
| 311 |
+
report = {
|
| 312 |
+
**compare_rows(
|
| 313 |
+
rows, cuda, temperatures=cal["temperatures"], reference_temperatures=reference_temperatures
|
| 314 |
+
),
|
| 315 |
+
"cuda_calibration_binding_sha256": sha256(binding_path),
|
| 316 |
+
"runtime": identity["runtime"],
|
| 317 |
+
"panel_sha256": identity["panel_sha256"],
|
| 318 |
+
"calibration_sha256": sha256(calibration),
|
| 319 |
+
"reference_sha256": sha256(reference),
|
| 320 |
+
"scope": "text-only held-out panel",
|
| 321 |
+
"image_qualification": False,
|
| 322 |
+
}
|
| 323 |
+
output.write_text(json.dumps(report, indent=2))
|
| 324 |
+
return report
|
mlx/src/solomon_mlx/prepare.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Verify immutable input snapshots and create a separately checksummed BF16 model."""
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
import shutil
|
| 6 |
+
from importlib.metadata import version
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
from .artifacts import BASE_REVISION, SOLOMON_REVISION, sha256, verify_release
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def verify_base(root, manifest):
|
| 13 |
+
root = Path(root)
|
| 14 |
+
if manifest["revision"] != BASE_REVISION:
|
| 15 |
+
raise ValueError("Wrong pinned base revision")
|
| 16 |
+
result = {}
|
| 17 |
+
for row in manifest["files"]:
|
| 18 |
+
path = root / row["name"]
|
| 19 |
+
if not path.resolve().is_relative_to(root.resolve()):
|
| 20 |
+
raise ValueError("Unsafe base manifest path")
|
| 21 |
+
if path.stat().st_size != row["size"]:
|
| 22 |
+
raise ValueError("Base size mismatch: " + row["name"])
|
| 23 |
+
actual = sha256(path)
|
| 24 |
+
if row["sha256"]:
|
| 25 |
+
if actual != row["sha256"]:
|
| 26 |
+
raise ValueError("Base checksum mismatch: " + row["name"])
|
| 27 |
+
else:
|
| 28 |
+
data = path.read_bytes()
|
| 29 |
+
git_hash = hashlib.sha1(b"blob " + str(len(data)).encode() + b"\0" + data).hexdigest()
|
| 30 |
+
if git_hash != row["blob_id"]:
|
| 31 |
+
raise ValueError("Base Git blob mismatch: " + row["name"])
|
| 32 |
+
result[row["name"]] = actual
|
| 33 |
+
return result
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def prepare(base, solomon, output, manifest):
|
| 37 |
+
|
| 38 |
+
base, solomon, output = map(Path, (base, solomon, output))
|
| 39 |
+
source_hashes = verify_release(solomon)
|
| 40 |
+
base_hashes = verify_base(base, json.loads(Path(manifest).read_text()))
|
| 41 |
+
if output.exists():
|
| 42 |
+
raise FileExistsError("Use a new output directory; existing conversions are immutable")
|
| 43 |
+
output.mkdir(parents=True)
|
| 44 |
+
convert_bf16(base, output / "backbone")
|
| 45 |
+
shutil.copy2(solomon / "adapter/adapter.safetensors", output / "adapter.safetensors")
|
| 46 |
+
shutil.copy2(solomon / "adapter/heads.npz", output / "heads.npz")
|
| 47 |
+
for name in ("LICENSE", "NOTICE", "MODIFICATIONS.md"):
|
| 48 |
+
shutil.copy2(solomon / name, output / name)
|
| 49 |
+
files = {
|
| 50 |
+
str(p.relative_to(output)): sha256(p)
|
| 51 |
+
for p in sorted(output.rglob("*"))
|
| 52 |
+
if p.is_file() and ".cache" not in p.parts
|
| 53 |
+
}
|
| 54 |
+
binding = {
|
| 55 |
+
"schema": "solomon-mlx-binding-v1",
|
| 56 |
+
"profile": "quality",
|
| 57 |
+
"dtype": "bfloat16",
|
| 58 |
+
"adapter_dtype": "float32",
|
| 59 |
+
"head_dtype": "float32",
|
| 60 |
+
"recurrent_state_dtype": "float32",
|
| 61 |
+
"sensitive_parameters": "FP32 normalization weights, A_log and dt_bias",
|
| 62 |
+
"conversion": "upstream Qwen3.5 sanitization, norms promoted before unit offset",
|
| 63 |
+
"adapter_scale": 2.0,
|
| 64 |
+
"adapter_placement": "question",
|
| 65 |
+
"quantization": None,
|
| 66 |
+
"base_revision": BASE_REVISION,
|
| 67 |
+
"solomon_revision": SOLOMON_REVISION,
|
| 68 |
+
"source_hashes": source_hashes,
|
| 69 |
+
"base_hashes": base_hashes,
|
| 70 |
+
"dependencies": {p: version(p) for p in ("mlx", "mlx-vlm", "transformers", "numpy")},
|
| 71 |
+
"files": files,
|
| 72 |
+
}
|
| 73 |
+
(output / "binding.json").write_text(json.dumps(binding, indent=2, sort_keys=True))
|
| 74 |
+
return binding
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def convert_bf16(base, output):
|
| 78 |
+
"""Convert one original shard at a time; never copy download caches.
|
| 79 |
+
|
| 80 |
+
Keep normalization offsets in FP32 before adding one. Adding the unit
|
| 81 |
+
offset in BF16 would irreversibly round trained normalization parameters.
|
| 82 |
+
Large backbone matrices remain unquantized BF16.
|
| 83 |
+
"""
|
| 84 |
+
import mlx.core as mx
|
| 85 |
+
from mlx.utils import tree_flatten
|
| 86 |
+
from mlx_vlm.models.qwen3_5.config import ModelConfig
|
| 87 |
+
from mlx_vlm.models.qwen3_5.qwen3_5 import Model
|
| 88 |
+
|
| 89 |
+
base, output = Path(base), Path(output)
|
| 90 |
+
output.mkdir(parents=True, exist_ok=False)
|
| 91 |
+
config = json.loads((base / "config.json").read_text())
|
| 92 |
+
if config.get("model_type") != "qwen3_5" or config.get("quantization"):
|
| 93 |
+
raise ValueError("Expected original unquantized Qwen3.5 architecture")
|
| 94 |
+
model = Model(ModelConfig.from_dict(config))
|
| 95 |
+
expected = {k: v.shape for k, v in tree_flatten(model.parameters())}
|
| 96 |
+
index = {"metadata": {"total_size": 0}, "weight_map": {}}
|
| 97 |
+
source_index = json.loads((base / "model.safetensors.index.json").read_text())
|
| 98 |
+
for filename in sorted(set(source_index["weight_map"].values())):
|
| 99 |
+
arrays = mx.load(str(base / filename))
|
| 100 |
+
for key, value in arrays.items():
|
| 101 |
+
sensitive = value.ndim == 1 and ("norm" in key or key.endswith(("A_log", "dt_bias")))
|
| 102 |
+
arrays[key] = value.astype(mx.float32 if sensitive else mx.bfloat16)
|
| 103 |
+
arrays = model.sanitize(arrays)
|
| 104 |
+
arrays = model.vision_tower.sanitize(arrays)
|
| 105 |
+
for key, value in arrays.items():
|
| 106 |
+
if key not in expected or value.shape != expected[key]:
|
| 107 |
+
raise ValueError("Converted tensor shape mismatch: " + key)
|
| 108 |
+
if key in index["weight_map"]:
|
| 109 |
+
raise ValueError("Duplicate converted tensor: " + key)
|
| 110 |
+
index["weight_map"][key] = filename
|
| 111 |
+
index["metadata"]["total_size"] += value.nbytes
|
| 112 |
+
mx.save_safetensors(str(output / filename), arrays, metadata={"format": "mlx"})
|
| 113 |
+
del arrays
|
| 114 |
+
mx.clear_cache()
|
| 115 |
+
print("Converted " + filename, flush=True)
|
| 116 |
+
if set(index["weight_map"]) != set(expected):
|
| 117 |
+
raise ValueError("Converted backbone is missing required parameters")
|
| 118 |
+
(output / "model.safetensors.index.json").write_text(json.dumps(index, indent=2, sort_keys=True))
|
| 119 |
+
for file in base.iterdir():
|
| 120 |
+
if file.is_file() and file.name != "model.safetensors.index.json" and file.suffix != ".safetensors":
|
| 121 |
+
shutil.copy2(file, output / file.name)
|
mlx/src/solomon_mlx_hub/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Prepare the adapter-only Hub release for the frozen Solomon MLX runtime."""
|
| 2 |
+
|
| 3 |
+
from .prepare import load, prepare_from_hub, prepare_from_snapshot, verify_prepared
|
| 4 |
+
|
| 5 |
+
__all__ = ["load", "prepare_from_hub", "prepare_from_snapshot", "verify_prepared"]
|