diff --git a/.agents/skills/review-doc-style/SKILL.md b/.agents/skills/review-doc-style/SKILL.md index ec37ceb40..061ee6c1e 100644 --- a/.agents/skills/review-doc-style/SKILL.md +++ b/.agents/skills/review-doc-style/SKILL.md @@ -37,7 +37,7 @@ and NVIDIA NeMo Fabric repo conventions. - Keep docs aligned with current NeMo Fabric behavior, repo layout, and entry points - Apply NVIDIA technical-writing guidance where it improves clarity and consistency without watering down technical precision - The full product name is "NVIDIA NeMo Fabric". - - The first usage of the name (typically in the title and H1 tag) should use the full product name. + - The first usage of the name (typically in the title and H1 tag) should use the full product name. - All other uses of the name can use the shortened form "NeMo Fabric". - The only acceptable usage of "fabric" by itself is when referring to the CLI tool, and these references must be surrounded by back-ticks. diff --git a/ATTRIBUTIONS-Rust.md b/ATTRIBUTIONS-Rust.md index 921e0d77b..d71db631c 100644 --- a/ATTRIBUTIONS-Rust.md +++ b/ATTRIBUTIONS-Rust.md @@ -9,11 +9,14 @@ This project uses the following third-party libraries. Each library is open-sour This file is automatically generated. Please do not edit it directly. Regenerate with `./scripts/generate_attributions.sh rust`. -## anstream - 1.0.0 +## anstyle - 1.0.14 + **Repository URL**: https://github.com/rust-cli/anstyle.git **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -219,11 +222,14 @@ This file is automatically generated. Please do not edit it directly. Regenerate ``` -## anstyle - 1.0.14 -**Repository URL**: https://github.com/rust-cli/anstyle.git +## clap - 4.6.2 + +**Repository URL**: https://github.com/clap-rs/clap **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -429,11 +435,14 @@ This file is automatically generated. Please do not edit it directly. Regenerate ``` -## anstyle-parse - 1.0.0 -**Repository URL**: https://github.com/rust-cli/anstyle.git +## clap_builder - 4.6.2 + +**Repository URL**: https://github.com/clap-rs/clap **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -639,11 +648,14 @@ This file is automatically generated. Please do not edit it directly. Regenerate ``` -## anstyle-query - 1.1.5 -**Repository URL**: https://github.com/rust-cli/anstyle.git +## clap_derive - 4.6.1 + +**Repository URL**: https://github.com/clap-rs/clap **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -849,11 +861,14 @@ This file is automatically generated. Please do not edit it directly. Regenerate ``` -## anstyle-wincon - 3.0.11 -**Repository URL**: https://github.com/rust-cli/anstyle.git +## clap_lex - 1.1.0 + +**Repository URL**: https://github.com/clap-rs/clap **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -1059,198 +1074,73 @@ This file is automatically generated. Please do not edit it directly. Regenerate ``` -## bitflags - 2.13.0 -**Repository URL**: https://github.com/bitflags/bitflags +## dyn-clone - 1.0.20 + +**Repository URL**: https://github.com/dtolnay/dyn-clone **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ + +```text +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] @@ -1258,7 +1148,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -1268,37 +1158,14 @@ limitations under the License. ``` -## block2 - 0.6.2 -**Repository URL**: https://github.com/madsmtm/objc2 -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -``` +## heck - 0.5.0 -## cfg-if - 1.0.4 -**Repository URL**: https://github.com/rust-lang/cfg-if +**Repository URL**: https://github.com/withoutboats/heck **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -1503,3517 +1370,21 @@ limitations under the License. ``` -## cfg_aliases - 0.2.1 -**Repository URL**: https://github.com/katharostech/cfg_aliases -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -MIT License +## itoa - 1.0.18 -Copyright (c) 2020 Katharos Technology +**Repository URL**: https://github.com/dtolnay/itoa +**License Type(s)**: Apache-2.0 -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +### License: https://spdx.org/licenses/Apache-2.0.html -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +```text +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -``` - -## clap - 4.6.1 -**Repository URL**: https://github.com/clap-rs/clap -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## clap_builder - 4.6.0 -**Repository URL**: https://github.com/clap-rs/clap -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## clap_derive - 4.6.1 -**Repository URL**: https://github.com/clap-rs/clap -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## clap_lex - 1.1.0 -**Repository URL**: https://github.com/clap-rs/clap -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## colorchoice - 1.0.5 -**Repository URL**: https://github.com/rust-cli/anstyle.git -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## ctrlc - 3.5.2 -**Repository URL**: https://github.com/Detegr/rust-ctrlc.git -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2017 CtrlC developers - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## dispatch2 - 0.3.1 -**Repository URL**: https://github.com/madsmtm/objc2 -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## dyn-clone - 1.0.20 -**Repository URL**: https://github.com/dtolnay/dyn-clone -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## equivalent - 1.0.2 -**Repository URL**: https://github.com/indexmap-rs/equivalent -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## hashbrown - 0.17.1 -**Repository URL**: https://github.com/rust-lang/hashbrown -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## heck - 0.5.0 -**Repository URL**: https://github.com/withoutboats/heck -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## indexmap - 2.14.0 -**Repository URL**: https://github.com/indexmap-rs/indexmap -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## is_terminal_polyfill - 1.70.2 -**Repository URL**: https://github.com/polyfill-rs/is_terminal_polyfill -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## itoa - 1.0.18 -**Repository URL**: https://github.com/dtolnay/itoa -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## libc - 0.2.186 -**Repository URL**: https://github.com/rust-lang/libc -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## memchr - 2.8.1 -**Repository URL**: https://github.com/BurntSushi/memchr -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -``` - -## nix - 0.31.3 -**Repository URL**: https://github.com/nix-rust/nix -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -The MIT License (MIT) - -Copyright (c) 2015 Carl Lerche + nix-rust Authors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -``` - -## objc2 - 0.6.4 -**Repository URL**: https://github.com/madsmtm/objc2 -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -``` - -## objc2-encode - 4.1.0 -**Repository URL**: https://github.com/madsmtm/objc2 -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. - -``` - -## once_cell - 1.21.4 -**Repository URL**: https://github.com/matklad/once_cell -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## once_cell_polyfill - 1.70.2 -**Repository URL**: https://github.com/polyfill-rs/once_cell_polyfill -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -``` - -## portable-atomic - 1.13.1 -**Repository URL**: https://github.com/taiki-e/portable-atomic -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## proc-macro2 - 1.0.106 -**Repository URL**: https://github.com/dtolnay/proc-macro2 -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## pyo3 - 0.28.3 -**Repository URL**: https://github.com/pyo3/pyo3 -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## pyo3-build-config - 0.28.3 -**Repository URL**: https://github.com/pyo3/pyo3 -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## pyo3-ffi - 0.28.3 -**Repository URL**: https://github.com/pyo3/pyo3 -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. +1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. @@ -5083,11 +1454,14 @@ limitations under the License. ``` -## pyo3-macros - 0.28.3 -**Repository URL**: https://github.com/pyo3/pyo3 +## libc - 0.2.186 + +**Repository URL**: https://github.com/rust-lang/libc **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5164,70 +1538,233 @@ limitations under the License. ``` -## pyo3-macros-backend - 0.28.3 -**Repository URL**: https://github.com/pyo3/pyo3 +## memchr - 2.8.1 + +**Repository URL**: https://github.com/BurntSushi/memchr +**License Type(s)**: MIT + +### License: https://spdx.org/licenses/MIT.html + +```text +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +``` + +## once_cell - 1.21.4 + +**Repository URL**: https://github.com/matklad/once_cell **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ + +```text + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. Copyright [yyyy] [name of copyright owner] @@ -5235,7 +1772,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -5245,11 +1782,14 @@ limitations under the License. ``` -## quote - 1.0.45 -**Repository URL**: https://github.com/dtolnay/quote +## portable-atomic - 1.13.1 + +**Repository URL**: https://github.com/taiki-e/portable-atomic **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5326,11 +1866,14 @@ limitations under the License. ``` -## ref-cast - 1.0.25 -**Repository URL**: https://github.com/dtolnay/ref-cast +## proc-macro2 - 1.0.106 + +**Repository URL**: https://github.com/dtolnay/proc-macro2 **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5407,11 +1950,14 @@ limitations under the License. ``` -## ref-cast-impl - 1.0.25 -**Repository URL**: https://github.com/dtolnay/ref-cast +## pyo3 - 0.28.3 + +**Repository URL**: https://github.com/pyo3/pyo3 **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5488,11 +2034,14 @@ limitations under the License. ``` -## ryu - 1.0.23 -**Repository URL**: https://github.com/dtolnay/ryu +## pyo3-build-config - 0.28.3 + +**Repository URL**: https://github.com/pyo3/pyo3 **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5569,69 +2118,14 @@ limitations under the License. ``` -## schemars - 1.2.1 -**Repository URL**: https://github.com/GREsau/schemars -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -MIT License - -Copyright (c) 2019 Graham Esau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -``` - -## schemars_derive - 1.2.1 -**Repository URL**: https://github.com/GREsau/schemars -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -MIT License - -Copyright (c) 2019 Graham Esau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -``` +## pyo3-ffi - 0.28.3 -## serde - 1.0.228 -**Repository URL**: https://github.com/serde-rs/serde +**Repository URL**: https://github.com/pyo3/pyo3 **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5708,11 +2202,14 @@ limitations under the License. ``` -## serde_core - 1.0.228 -**Repository URL**: https://github.com/serde-rs/serde +## pyo3-macros - 0.28.3 + +**Repository URL**: https://github.com/pyo3/pyo3 **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5789,11 +2286,14 @@ limitations under the License. ``` -## serde_derive - 1.0.228 -**Repository URL**: https://github.com/serde-rs/serde +## pyo3-macros-backend - 0.28.3 + +**Repository URL**: https://github.com/pyo3/pyo3 **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5870,11 +2370,14 @@ limitations under the License. ``` -## serde_derive_internals - 0.29.1 -**Repository URL**: https://github.com/serde-rs/serde +## quote - 1.0.45 + +**Repository URL**: https://github.com/dtolnay/quote **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -5951,11 +2454,14 @@ limitations under the License. ``` -## serde_json - 1.0.150 -**Repository URL**: https://github.com/serde-rs/json +## ref-cast - 1.0.25 + +**Repository URL**: https://github.com/dtolnay/ref-cast **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6032,11 +2538,14 @@ limitations under the License. ``` -## serde_yaml - 0.9.34+deprecated -**Repository URL**: https://github.com/dtolnay/serde-yaml +## ref-cast-impl - 1.0.25 + +**Repository URL**: https://github.com/dtolnay/ref-cast **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6113,16 +2622,49 @@ limitations under the License. ``` -## strsim - 0.11.1 -**Repository URL**: https://github.com/rapidfuzz/strsim-rs +## schemars - 1.2.1 + +**Repository URL**: https://github.com/GREsau/schemars **License Type(s)**: MIT + ### License: https://spdx.org/licenses/MIT.html + +```text +MIT License + +Copyright (c) 2019 Graham Esau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + ``` -The MIT License (MIT) -Copyright (c) 2015 Danny Guo -Copyright (c) 2016 Titus Wormer -Copyright (c) 2018 Akash Kurdekar +## schemars_derive - 1.2.1 + +**Repository URL**: https://github.com/GREsau/schemars +**License Type(s)**: MIT + +### License: https://spdx.org/licenses/MIT.html + +```text +MIT License + +Copyright (c) 2019 Graham Esau Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -6144,11 +2686,14 @@ SOFTWARE. ``` -## syn - 2.0.117 -**Repository URL**: https://github.com/dtolnay/syn +## serde - 1.0.228 + +**Repository URL**: https://github.com/serde-rs/serde **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6225,239 +2770,98 @@ limitations under the License. ``` -## target-lexicon - 0.13.5 -**Repository URL**: https://github.com/bytecodealliance/target-lexicon -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. +## serde_core - 1.0.228 - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +**Repository URL**: https://github.com/serde-rs/serde +**License Type(s)**: Apache-2.0 - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +### License: https://spdx.org/licenses/Apache-2.0.html - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. +```text +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. +1. Definitions. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - END OF TERMS AND CONDITIONS +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - APPENDIX: How to apply the Apache License to your work. +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - Copyright [yyyy] [name of copyright owner] +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - http://www.apache.org/licenses/LICENSE-2.0 +END OF TERMS AND CONDITIONS - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +APPENDIX: How to apply the Apache License to your work. +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. ---- LLVM Exceptions to the Apache 2.0 License ---- +Copyright [yyyy] [name of copyright owner] -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. ``` -## thiserror - 2.0.18 -**Repository URL**: https://github.com/dtolnay/thiserror +## serde_derive - 1.0.228 + +**Repository URL**: https://github.com/serde-rs/serde **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6534,11 +2938,14 @@ limitations under the License. ``` -## thiserror-impl - 2.0.18 -**Repository URL**: https://github.com/dtolnay/thiserror +## serde_derive_internals - 0.29.1 + +**Repository URL**: https://github.com/serde-rs/serde **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6615,11 +3022,14 @@ limitations under the License. ``` -## unicode-ident - 1.0.24 -**Repository URL**: https://github.com/dtolnay/unicode-ident +## serde_json - 1.0.150 + +**Repository URL**: https://github.com/serde-rs/json **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6696,89 +3106,48 @@ limitations under the License. ``` -## unicode-ident - 1.0.24 -**Repository URL**: https://github.com/dtolnay/unicode-ident -**License Type(s)**: Unicode-3.0 -### License: https://spdx.org/licenses/Unicode-3.0.html -``` -UNICODE LICENSE V3 - -COPYRIGHT AND PERMISSION NOTICE - -Copyright © 1991-2023 Unicode, Inc. - -NOTICE TO USER: Carefully read the following legal agreement. BY -DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR -SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE -TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT -DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of data files and any associated documentation (the "Data Files") or -software and any associated documentation (the "Software") to deal in the -Data Files or Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Data Files or Software, and to permit persons to whom the -Data Files or Software are furnished to do so, provided that either (a) -this copyright and permission notice appear with all copies of the Data -Files or Software, or (b) this copyright and permission notice appear in -associated Documentation. +## strsim - 0.11.1 -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF -THIRD PARTY RIGHTS. +**Repository URL**: https://github.com/rapidfuzz/strsim-rs +**License Type(s)**: MIT -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE -BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, -OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA -FILES OR SOFTWARE. +### License: https://spdx.org/licenses/MIT.html -Except as contained in this notice, the name of a copyright holder shall -not be used in advertising or otherwise to promote the sale, use or other -dealings in these Data Files or Software without prior written -authorization of the copyright holder. +```text +The MIT License (MIT) -``` +Copyright (c) 2015 Danny Guo +Copyright (c) 2016 Titus Wormer +Copyright (c) 2018 Akash Kurdekar -## unsafe-libyaml - 0.2.11 -**Repository URL**: https://github.com/dtolnay/unsafe-libyaml -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. ``` -## utf8parse - 0.2.2 -**Repository URL**: https://github.com/alacritty/vte +## syn - 2.0.117 + +**Repository URL**: https://github.com/dtolnay/syn **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -6855,11 +3224,15 @@ limitations under the License. ``` -## windows-link - 0.2.1 -**Repository URL**: https://github.com/microsoft/windows-rs +## target-lexicon - 0.13.5 + +**Repository URL**: https://github.com/bytecodealliance/target-lexicon **License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html -``` + +```text + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -7048,236 +3421,350 @@ limitations under the License. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright (c) Microsoft Corporation. + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + + +``` + +## thiserror - 2.0.18 + +**Repository URL**: https://github.com/dtolnay/thiserror +**License Type(s)**: Apache-2.0 + +### License: https://spdx.org/licenses/Apache-2.0.html + +```text +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## thiserror-impl - 2.0.18 + +**Repository URL**: https://github.com/dtolnay/thiserror +**License Type(s)**: Apache-2.0 + +### License: https://spdx.org/licenses/Apache-2.0.html + +```text +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## unicode-ident - 1.0.24 + +**Repository URL**: https://github.com/dtolnay/unicode-ident +**License Type(s)**: Apache-2.0 + +### License: https://spdx.org/licenses/Apache-2.0.html + +```text +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - http://www.apache.org/licenses/LICENSE-2.0 +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). -``` +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. -## windows-sys - 0.61.2 -**Repository URL**: https://github.com/microsoft/windows-rs -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - 1. Definitions. +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: +END OF TERMS AND CONDITIONS - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and +APPENDIX: How to apply the Apache License to your work. - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and +Copyright [yyyy] [name of copyright owner] - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. +http://www.apache.org/licenses/LICENSE-2.0 - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. +``` - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. +## unicode-ident - 1.0.24 - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. +**Repository URL**: https://github.com/dtolnay/unicode-ident +**License Type(s)**: Unicode-3.0 - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. +### License: https://spdx.org/licenses/Unicode-3.0.html - END OF TERMS AND CONDITIONS +```text +UNICODE LICENSE V3 - APPENDIX: How to apply the Apache License to your work. +COPYRIGHT AND PERMISSION NOTICE - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +Copyright © 1991-2023 Unicode, Inc. - Copyright (c) Microsoft Corporation. +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. - http://www.apache.org/licenses/LICENSE-2.0 +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. ``` ## zmij - 1.0.21 + **Repository URL**: https://github.com/dtolnay/zmij **License Type(s)**: MIT + ### License: https://spdx.org/licenses/MIT.html -``` + +```text Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f02a31a4..ec1fc0a9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ build wheels from a source checkout: ```bash just wheels -uv pip install --find-links dist "nemo-fabric[runtime]" +uv pip install --find-links dist nemo-fabric ``` Adapters are distributed as optional extras. For example, install the Hermes adapter with: @@ -249,7 +249,7 @@ Valid types: Examples: ```text -feat: add typed runtime configuration overlays +feat: add typed runtime diagnostics fix: preserve adapter errors in run results docs: clarify Hermes adapter installation test: cover concurrent Python runtime invocations diff --git a/Cargo.lock b/Cargo.lock index 1aeec1992..afa7716d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,88 +2,17 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - [[package]] name = "anstyle" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys", -] - -[[package]] -name = "bitflags" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" - -[[package]] -name = "block2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" -dependencies = [ - "objc2", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "clap" -version = "4.6.1" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "dd059f9da4f5c36b3787f65d38ccaab1cc315f07b01f89abc8359ee6a8205011" dependencies = [ "clap_builder", "clap_derive", @@ -91,11 +20,10 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b" dependencies = [ - "anstream", "anstyle", "clap_lex", "strsim", @@ -119,47 +47,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "ctrlc" -version = "3.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" -dependencies = [ - "dispatch2", - "nix", - "windows-sys", -] - -[[package]] -name = "dispatch2" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" -dependencies = [ - "bitflags", - "block2", - "libc", - "objc2", -] - [[package]] name = "dyn-clone" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - [[package]] name = "fabric-python" version = "0.1.0" @@ -170,34 +63,12 @@ dependencies = [ "serde_json", ] -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - [[package]] name = "itoa" version = "1.0.18" @@ -221,7 +92,6 @@ name = "nemo-fabric-cli" version = "0.1.0" dependencies = [ "clap", - "ctrlc", "nemo-fabric-core", "serde_json", ] @@ -233,49 +103,15 @@ dependencies = [ "schemars", "serde", "serde_json", - "serde_yaml", "thiserror", ] -[[package]] -name = "nix" -version = "0.31.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "objc2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" -dependencies = [ - "objc2-encode", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - [[package]] name = "portable-atomic" version = "1.13.1" @@ -378,12 +214,6 @@ dependencies = [ "syn", ] -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - [[package]] name = "schemars" version = "1.2.1" @@ -463,19 +293,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "strsim" version = "0.11.1" @@ -525,33 +342,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index 05332e3c5..fc77c16f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,12 +22,10 @@ repository = "https://github.com/NVIDIA/nemo-fabric" [workspace.dependencies] nemo-fabric-core = { path = "crates/fabric-core", version = "0.1.0" } -clap = { version = "4", features = ["derive"] } -ctrlc = "3" +clap = { version = "4", default-features = false, features = ["derive", "std", "help", "usage", "error-context", "suggestions"] } schemars = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] } serde_json = "1" -serde_yaml = "0.9" thiserror = "2" pyo3 = "0.28.2" diff --git a/README.md b/README.md index e6df11fbe..b279ef14b 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,17 @@ artifacts from agent harnesses. Fabric provides: -- a versioned typed config contract, with `agent.yaml` as the portable file - format; -- profile-based config variation for evaluation and ablation runs; +- a versioned, typed `FabricConfig` contract constructed through the SDK; +- ordinary Python composition for harness and experiment variants; - adapter descriptors for harness-specific launch and control; -- a Rust core with a CLI and Python bindings; +- a Rust core, Python SDK, and standalone experimentation CLI; - JSON Schema snapshots for the public config and runtime contract; - normalized run results, artifact manifests, and telemetry references. ```mermaid flowchart TB Consumer["Consumer\nCLI | Python SDK | integrations"] - Config["Agent source\nagent.yaml or FabricConfig"] + Config["Typed source\nFabricConfig"] Core["Fabric Rust core\nresolve | plan | create | invoke | destroy"] Adapter["Selected Fabric adapter"] Harness["Agent harness runtime\nHermes | Codex | custom"] @@ -47,6 +46,32 @@ flowchart TB Harness -. harness telemetry .-> Relay ``` +## Quick Start: Experimentation CLI + +The `nemo-fabric` CLI is a maintained, experimental developer interface for +quick harness experiments, smoke tests, examples, planning, and diagnostics. +Its command contract can evolve as experiments mature. The Python SDK remains +the stable application-facing contract. + +Install the Rust CLI from this source checkout, verify it, and run the +credential-free preset: + +```bash +cargo install --path crates/fabric-cli --locked +nemo-fabric --version +nemo-fabric preset show scripted +nemo-fabric run --preset scripted --input "fabric works" +``` + +Copy an editable Python starting point with: + +```bash +nemo-fabric example init code-review ./my-agent --language python +``` + +See the [experimentation CLI guide](docs/experimentation/cli.mdx) for the CLI's +intent and boundaries. + ## Quick Start: Hermes Agent This path installs Fabric, installs Hermes Agent in a separate Python environment, @@ -81,7 +106,7 @@ just build-all just wheels ``` -Install Hermes into its own environment (the nemo-fabric[hermes] extra will install Hermes Agent, and the Hermes Agent adapter but not Fabric itself): +Install Fabric, Hermes Agent, and the Hermes adapter into an environment: ```bash # Use any Python 3.11-3.13 interpreter for Hermes. @@ -134,23 +159,20 @@ authentication, and execution details. ## Core Concepts -- **Agent source:** callers provide either an agent package path or a typed - `FabricConfig`. Start with `examples/code_review_agent/config.py` for the - application-facing Pydantic pattern. -- **Typed config:** SDK consumers can construct configuration in memory without - materializing an agent directory. `agent.yaml` remains the portable - representation for CLI use, CI, and reproducible runs. -- **Profiles:** named variations of the base config. Use profiles to vary the - harness, model, MCP, tools, skills, telemetry, or environment context without - editing `agent.yaml`. +- **Typed config:** callers construct a complete `FabricConfig` in Python. + Start with the [Python SDK guide](docs/sdk/python.mdx), and refer to + [`examples/code_review_agent/config.py`](examples/code_review_agent/config.py) + for a complete application example. +- **Variants:** ordinary Python functions copy and modify complete configs to + vary the harness, model, MCP, tools, skills, telemetry, or environment. +- **Experimentation CLI:** presets provide quick probes, examples provide + maintained runnable workflows, and `example init` generates editable Python + or Rust applications that call a language API directly. - **Tools policy:** use top-level `tools.blocked` for harness-neutral blocked tool policy. Names are interpreted by the selected adapter: - ```yaml - tools: - blocked: - - browser - - shell + ```python + config.block_tools("browser", "shell") ``` Hermes maps these names to disabled toolsets, Claude maps them to @@ -166,15 +188,9 @@ authentication, and execution details. - **Artifacts:** normalized output, logs, patches, and telemetry references returned through an `ArtifactManifest`. -Fabric applies profiles in caller order and validates the final effective config -before planning or running. - -Path sources select profiles by name. Typed `FabricConfig` sources usually -compose the final config in Python; `FabricProfileConfig` values are available -for callers that need ordered file-style overlays. The SDK rejects raw profile -mappings and mixed profile stacks. See the -[Python SDK guide](docs/sdk/python.mdx) for the complete public API, -type definitions, lifecycle semantics, and error behavior. +Fabric accepts complete typed configs. Compose variants in Python before +calling the SDK. Refer to the [Python SDK guide](docs/sdk/python.mdx) for the +complete public API, type definitions, lifecycle semantics, and error behavior. `run(...)` owns the complete start, invoke, and stop lifecycle. For typed in-memory configuration, planning and diagnostics, explicit requests, @@ -186,6 +202,8 @@ the [Python SDK guide](docs/sdk/python.mdx). Exact signatures are in the - [Python SDK guide](docs/sdk/python.mdx): typed configuration, planning, diagnostics, requests, multi-turn runtimes, parallelism, results, and errors. +- [Experimentation CLI](docs/experimentation/cli.mdx): presets, maintained + examples, editable application scaffolds, and explicit non-goals. - [Consumer integration skills](skills/README.md): repository-local coding-agent skills for integrating Fabric into an application through the Python SDK. - [Getting Started overview](docs/about-nemo-fabric/overview.mdx): interface diff --git a/TODO.md b/TODO.md index 25ed111bb..9bd12bc19 100644 --- a/TODO.md +++ b/TODO.md @@ -9,6 +9,33 @@ Track repository workarounds that must be removed after an upstream dependency ships. Each entry must identify an upstream reference, removal condition, and cleanup validation. +## Installed Adapter Descriptor Metadata + +- **Status:** Waiting for adapter wheel metadata support +- **Added:** July 19, 2026 +- **Affected implementation:** `crates/fabric-core/src/config.rs`, + `crates/fabric-cli/src/presets.rs`, `crates/fabric-cli/assets/adapters/`, and + the Python binding +- **Reason:** The published CLI crate currently carries package-local copies of + adapter descriptors because Cargo cannot package descriptors from the + repository-level adapter directories. A drift test keeps those copies aligned + with the canonical descriptors, but the duplication is a packaging + workaround. CLI presets stage the embedded descriptors under a temporary + `adapters/` directory, and core also probes a compile-time repository path. +- **Upstream resolution:** NeMo Fabric adapter distributions advertise their + descriptors through installed wheel metadata (internal packaging milestone; + no external dependency). +- **Removal condition:** Python can discover installed adapter descriptors from + wheel metadata and pass them to core through an explicit, typed adapter + registry. +- **Cleanup:** Add adapter registrations to `ResolveContext`; remove implicit + repository and `base_dir/adapters` discovery from core; have the Python + binding register wheel-owned descriptors; revisit and remove the duplicated + CLI descriptor assets once wheel metadata is consumable; retain embedded or + staged files only for standalone CLI assets such as the scripted runner; and + validate both installed-wheel and standalone Rust CLI behavior before + removing this entry. + ## NeMo Relay 0.6.x Request Decoding Release - **Status:** Waiting for an upstream release @@ -42,3 +69,22 @@ cleanup validation. PyPI in a version the skill can target. - **Cleanup:** Replace the source and wheel install steps in the skill with the published `pip install "nemo-fabric[...]"` instructions and remove this entry. + +# Planned Work + +## Example Authoring Skill + +- **Status:** Not started +- **Purpose:** Add a guided workflow for users who need help designing a new + example, selecting the closest preset or maintained example, customizing the + generated code, and adding documentation and tests. +- **Boundary:** Keep `nemo-fabric example init` as the deterministic operation + for users who already know which example and variant they want to customize. + The skill provides authoring judgment and validation around that operation. +- **Implementation:** Have the skill invoke or reuse `example init` as its + starting point, then modify and validate the generated application. Do not + create a separate template collection or scaffolding implementation in the + skill. +- **Completion condition:** The skill can guide a user from an example idea to + a runnable, documented, and tested Python or Rust example while keeping the + CLI scaffold as the single source for generated starter code. diff --git a/adapters/claude/README.md b/adapters/claude/README.md index a0d159936..776521424 100644 --- a/adapters/claude/README.md +++ b/adapters/claude/README.md @@ -35,6 +35,13 @@ bearer credential, `ANTHROPIC_API_KEY` for a static API credential, or Anthropic Workload Identity Federation (WIF) for production and CI workloads that should not store a long-lived API key. +When `models.default.provider` is `nvidia`, the adapter reads the selected +model's credential from `api_key_env` (default: `NVIDIA_API_KEY`) and translates +the configured NVIDIA `/v1` endpoint into the host URL expected by Claude Code. +Set the endpoint in `models.default.settings.base_url` or +`NVIDIA_FRONTIER_BASE_URL`; the adapter does not assume a default frontier +endpoint. This request-scoped mapping does not change the parent environment. + The adapter forwards the Anthropic profile and federation environment variables that Claude Code and the Claude Agent SDK consume. This includes `ANTHROPIC_CONFIG_DIR`, `ANTHROPIC_PROFILE`, the direct federation identifiers, @@ -74,9 +81,9 @@ stays resident. Configure portable capabilities through the normalized `FabricConfig` fields: -- `models` selects the Claude model. A configured model must use - `provider="anthropic"`; normalized hosted/custom provider resolution is - tracked in [FABRIC-64](https://linear.app/nvidia/issue/FABRIC-64/add-normalized-model-provider-resolution-and-harness-compatibility). +- `models` selects the Claude model. The adapter accepts the native `anthropic` + provider and NVIDIA-hosted Anthropic Messages-compatible models through the + `nvidia` provider. - `environment.workspace` sets the Claude working directory. - `tools.blocked` maps to Claude `disallowed_tools` using Claude-native tool names. diff --git a/adapters/claude/src/nemo_fabric_adapters/claude/adapter.py b/adapters/claude/src/nemo_fabric_adapters/claude/adapter.py index 2a04a5b6f..b76c0672c 100644 --- a/adapters/claude/src/nemo_fabric_adapters/claude/adapter.py +++ b/adapters/claude/src/nemo_fabric_adapters/claude/adapter.py @@ -217,14 +217,14 @@ def _selected_model_config(payload: dict[str, Any]) -> dict[str, Any]: def _resolve_path(payload: dict[str, Any], value: str | Path) -> Path: path = Path(value) if not path.is_absolute(): - path = Path(common_utils.config_root(payload)) / path + path = Path(common_utils.base_dir(payload)) / path return path def resolve_cwd(payload: dict[str, Any]) -> Path: environment = common_utils.environment_payload(payload) workspace = environment.get("workspace") - return _resolve_path(payload, workspace or common_utils.config_root(payload)) + return _resolve_path(payload, workspace or common_utils.base_dir(payload)) def selected_model(payload: dict[str, Any]) -> str | None: @@ -232,16 +232,56 @@ def selected_model(payload: dict[str, Any]) -> str | None: value = model_config.get("model") if value is None: return None - if model_config.get("provider") != "anthropic": + provider = model_config.get("provider") + if provider not in {"anthropic", "nvidia"}: raise AdapterConfigError( "claude_invalid_configuration", - "models.default.provider must be anthropic for the Claude adapter", + "models.default.provider must be anthropic or nvidia for the Claude adapter", ) if not isinstance(value, str) or not value: raise AdapterConfigError( "claude_invalid_configuration", "model must be a non-empty string" ) - return value.removeprefix("anthropic/") + return value.removeprefix("anthropic/") if provider == "anthropic" else value + + +def _nvidia_environment(payload: dict[str, Any]) -> dict[str, str]: + model = _selected_model_config(payload) + if model.get("provider") != "nvidia": + return {} + api_key_env = model.get("api_key_env") or "NVIDIA_API_KEY" + if not isinstance(api_key_env, str) or not api_key_env: + raise AdapterConfigError( + "claude_invalid_configuration", + "models.default.api_key_env must be a non-empty string", + ) + api_key = os.environ.get(api_key_env) + if not api_key: + raise AdapterConfigError( + "claude_invalid_configuration", + f"{api_key_env} is required for the NVIDIA model provider", + ) + settings = _settings(payload) + model_settings = _mapping(model.get("settings"), name="models.default.settings") + base_url = ( + settings.get("base_url") + or model_settings.get("base_url") + or os.environ.get("NVIDIA_FRONTIER_BASE_URL") + ) + if not isinstance(base_url, str) or not base_url: + raise AdapterConfigError( + "claude_invalid_configuration", + "models.default.settings.base_url or NVIDIA_FRONTIER_BASE_URL is required " + "for the NVIDIA model provider", + ) + # Claude Code appends the Anthropic API version path itself, while Fabric's + # shared NVIDIA endpoint includes it for OpenAI-compatible clients. + claude_base_url = base_url.rstrip("/").removesuffix("/v1") + return { + "ANTHROPIC_API_KEY": api_key, + "ANTHROPIC_AUTH_TOKEN": "", + "ANTHROPIC_BASE_URL": claude_base_url, + } def _mcp_servers(payload: dict[str, Any]) -> dict[str, Any]: @@ -388,7 +428,7 @@ def prepare_claude_relay(payload: dict[str, Any]) -> ClaudeRelaySettings | None: ) try: executable = relay_gateway.resolve_relay_command( - Path(common_utils.config_root(payload)).resolve(), + Path(common_utils.base_dir(payload)).resolve(), command, ) except FileNotFoundError as error: @@ -530,7 +570,7 @@ def _artifact_root(payload: dict[str, Any]) -> Path: root = artifacts.get("root") if isinstance(artifacts, dict) else None if root: return Path(root) - return Path(common_utils.config_root(payload)) / "artifacts" / "claude" + return Path(common_utils.base_dir(payload)) / "artifacts" / "claude" def runtime_state_path(payload: dict[str, Any], fabric_runtime_id: str) -> Path: @@ -705,6 +745,7 @@ def child_environment( "claude_invalid_configuration", "harness.settings.env must contain strings" ) values.update(configured) + values.update(_nvidia_environment(payload)) if relay_gateway_url is not None: values["NEMO_RELAY_GATEWAY_URL"] = relay_gateway_url values["ANTHROPIC_BASE_URL"] = relay_gateway_url diff --git a/adapters/codex/README.md b/adapters/codex/README.md index 4275e9c76..28a2c07e0 100644 --- a/adapters/codex/README.md +++ b/adapters/codex/README.md @@ -49,6 +49,14 @@ the SDK runtime. The current real-agent acceptance path validates an existing Codex login; it does not yet claim a raw environment variable as a complete login flow. +When `models.default.provider` is `nvidia`, the adapter defines a request-scoped +Codex model provider for the configured NVIDIA Responses endpoint. It reads the +credential from `api_key_env` (default: `NVIDIA_API_KEY`) and isolates Codex +state under the Fabric artifact root, so the invocation does not depend on or +modify a user's Codex login. Set the endpoint in +`models.default.settings.base_url` or `NVIDIA_FRONTIER_BASE_URL`; the adapter +does not assume a default frontier endpoint. + The dependency graph includes `openai-codex-cli-bin`. The Codex SDK owns this pinned app-server distribution; Fabric does not treat it as a user-installed command or an adapter descriptor requirement. @@ -57,7 +65,7 @@ This adapter pins `openai-codex==0.1.0b3`, which pins `openai-codex-cli-bin==0.137.0a4`. A newer `codex` command on `PATH` is not used implicitly. When testing a newer compatible runtime, set `harness.settings.codex_bin` to an app-server path that is absolute or relative -to the Fabric config root. Fabric passes the resolved path through +to the explicit `base_dir`. Fabric passes the resolved path through `CodexConfig.codex_bin`; the SDK remains the execution driver. ## Execution Model @@ -76,8 +84,9 @@ return codes, stdout, or stderr. Use normalized `FabricConfig` fields for portable configuration: -- `models` selects the Codex model. The adapter requires and explicitly selects - the built-in `openai` provider. +- `models` selects the Codex model. The adapter supports the built-in `openai` + provider and NVIDIA-hosted Responses-compatible models through the `nvidia` + provider. - `environment.workspace` sets the working directory. - `telemetry` enables native OpenTelemetry or NeMo Relay observability. @@ -94,9 +103,8 @@ Codex-specific controls belong in `harness.settings`: - `env` for variables explicitly forwarded to the Codex runtime - `nemo_relay_command` for the optional external Relay gateway executable -The removed CLI settings `codex_command`, `codex_args`, `codex_profile`, -`codex_state_dir`, and `skip_git_repo_check` are errors. `model_name` and `cwd` -must use the normalized model and environment fields. +Set model selection through `models` and the working directory through +`environment.workspace`. The adapter filters the inherited environment. It retains portable OS and Codex state variables, the selected model's `api_key_env`, and explicit @@ -127,6 +135,13 @@ capture Responses traffic. Fabric does not spoof the Codex CLI identity or fall back to CLI execution. Relay routes and observes requests; it does not provide OpenAI credentials or change the selected Codex authentication mode. +Relay-enabled Codex runs require `models.default.provider: openai`. The custom +`nvidia` provider is not supported with Relay because its configured NVIDIA +Responses base URL bypasses the built-in `openai_base_url` redirect. Run the +`nvidia` provider without Relay and supply its credential through `api_key_env` +(default: `NVIDIA_API_KEY`) and its endpoint through +`models.default.settings.base_url` or `NVIDIA_FRONTIER_BASE_URL`. + Relay-enabled runs require the external `nemo-relay` CLI in addition to the Python package dependencies. Fabric accepts CLI versions `>=0.6.0,<0.7.0`. Until the request-decoding fix is released, install the tested PR revision: @@ -157,4 +172,3 @@ For Phoenix, native Codex OpenTelemetry targets the OTLP collector at Relay OpenInference provides the semantic chain, LLM, and tool hierarchy with decoded prompt, response, and token attributes. Prefer Relay OpenInference for agent-turn inspection. - diff --git a/adapters/codex/src/nemo_fabric_adapters/codex/adapter.py b/adapters/codex/src/nemo_fabric_adapters/codex/adapter.py index 17959350c..ca1e606b9 100644 --- a/adapters/codex/src/nemo_fabric_adapters/codex/adapter.py +++ b/adapters/codex/src/nemo_fabric_adapters/codex/adapter.py @@ -177,10 +177,10 @@ def resolve_cwd(payload: dict[str, Any]) -> Path: environment = _mapping( common_utils.environment_payload(payload), name="runtime environment" ) - value = environment.get("workspace") or common_utils.config_root(payload) + value = environment.get("workspace") or common_utils.base_dir(payload) path = Path(str(value)) if not path.is_absolute(): - path = Path(common_utils.config_root(payload)) / path + path = Path(common_utils.base_dir(payload)) / path return path.resolve() @@ -196,16 +196,61 @@ def selected_model(payload: dict[str, Any]) -> str | None: value = model_config.get("model") if value is None: return None - if model_config.get("provider") != "openai": + provider = model_config.get("provider") + if provider not in {"openai", "nvidia"}: raise AdapterConfigError( "codex_invalid_configuration", - "selected model provider must be openai for the Codex adapter", + "selected model provider must be openai or nvidia for the Codex adapter", ) if not isinstance(value, str) or not value: raise AdapterConfigError( "codex_invalid_configuration", "model must be a non-empty string" ) - return value.removeprefix("openai/") + return value.removeprefix("openai/") if provider == "openai" else value + + +def selected_model_provider(payload: dict[str, Any]) -> str: + return str(_selected_model_config(payload).get("provider") or "openai") + + +def nvidia_model_provider_config(payload: dict[str, Any]) -> dict[str, Any]: + model_config = _selected_model_config(payload) + if model_config.get("provider") != "nvidia": + return {} + api_key_env = model_config.get("api_key_env") or "NVIDIA_API_KEY" + if not isinstance(api_key_env, str) or not api_key_env: + raise AdapterConfigError( + "codex_invalid_configuration", + "models.default.api_key_env must be a non-empty string", + ) + if not os.environ.get(api_key_env): + raise AdapterConfigError( + "codex_invalid_configuration", + f"{api_key_env} is required for the NVIDIA model provider", + ) + model_settings = _mapping( + model_config.get("settings"), name="selected model settings" + ) + base_url = ( + model_settings.get("base_url") + or os.environ.get("NVIDIA_FRONTIER_BASE_URL") + ) + if not isinstance(base_url, str) or not base_url: + raise AdapterConfigError( + "codex_invalid_configuration", + "models.default.settings.base_url or NVIDIA_FRONTIER_BASE_URL is required " + "for the NVIDIA model provider", + ) + return { + "model_providers": { + "nvidia": { + "name": "NVIDIA", + "base_url": base_url.rstrip("/"), + "env_key": api_key_env, + "wire_api": "responses", + } + } + } def sandbox(payload: dict[str, Any]) -> Sandbox: @@ -296,6 +341,9 @@ def child_environment( "harness.settings.env must contain strings", ) values.update(configured) + if selected_model_provider(payload) == "nvidia": + codex_home = state_dir(payload) / "nvidia-home" + values["CODEX_HOME"] = str(codex_home) # The SDK overlays this mapping on the parent environment. An empty # originator is still treated as an override by Codex and produces invalid # initialize metadata ("/"). Use the official SDK client identity @@ -311,7 +359,7 @@ def _artifact_root(payload: dict[str, Any]) -> Path: root = artifacts.get("root") if isinstance(artifacts, dict) else None if root: return Path(str(root)) - return Path(common_utils.config_root(payload)) / "artifacts" / "codex" + return Path(common_utils.base_dir(payload)) / "artifacts" / "codex" def state_dir(payload: dict[str, Any]) -> Path: @@ -471,7 +519,7 @@ def prepare_codex_relay(payload: dict[str, Any]) -> CodexRelaySettings | None: ) try: executable = relay_gateway.resolve_relay_command( - Path(common_utils.config_root(payload)).resolve(), command + Path(common_utils.base_dir(payload)).resolve(), command ) except FileNotFoundError as error: raise AdapterRelayError( @@ -520,6 +568,7 @@ def thread_config( """Build request-scoped Codex config without writing a user profile.""" config = native_codex_telemetry_config(payload) + _merge_config(config, nvidia_model_provider_config(payload)) overrides = _mapping( _settings(payload).get("config_overrides"), name="harness.settings.config_overrides", @@ -559,7 +608,7 @@ def sdk_config( if codex_bin is not None: path = Path(codex_bin) if not path.is_absolute(): - path = (Path(common_utils.config_root(payload)) / path).resolve() + path = (Path(common_utils.base_dir(payload)) / path).resolve() codex_bin = str(path) return CodexConfig( codex_bin=codex_bin, @@ -624,6 +673,14 @@ def validate_payload(payload: dict[str, Any]) -> str: _personality(payload) _reasoning_effort(payload) _output_schema(payload) + if ( + common_utils.relay_enabled(payload) + and selected_model_provider(payload) != "openai" + ): + raise AdapterConfigError( + "codex_invalid_configuration", + "NeMo Relay requires the built-in openai model provider", + ) child_environment(payload) thread_config(payload, None) return fabric_runtime_id @@ -765,11 +822,19 @@ async def invoke_codex_sdk( settings = _settings(payload) config = thread_config(payload, relay) - codex = AsyncCodex(config=sdk_config(payload, relay)) + client_config = sdk_config(payload, relay) + codex: AsyncCodex | None = None handle = None output: dict[str, Any] thread_id: str | None = None try: + if selected_model_provider(payload) == "nvidia": + await asyncio.to_thread( + Path(client_config.env["CODEX_HOME"]).mkdir, + parents=True, + exist_ok=True, + ) + codex = AsyncCodex(config=client_config) async with asyncio.timeout(timeout_seconds(payload)): common = { "approval_mode": approval_mode(payload), @@ -780,7 +845,7 @@ async def invoke_codex_sdk( settings, "developer_instructions" ), "model": selected_model(payload), - "model_provider": "openai", + "model_provider": selected_model_provider(payload), "personality": _personality(payload), "sandbox": sandbox(payload), "service_tier": _optional_string(settings, "service_tier"), @@ -813,12 +878,13 @@ async def invoke_codex_sdk( except (CodexError, RuntimeError, OSError) as error: output = sdk_failure(error) finally: - try: - await codex.close() - except Exception: - output = _failure( - "codex_sdk_stop_failed", "Codex SDK runtime failed to stop" - ) + if codex is not None: + try: + await codex.close() + except Exception: + output = _failure( + "codex_sdk_stop_failed", "Codex SDK runtime failed to stop" + ) return output, thread_id diff --git a/adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py b/adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py index 0dc1ff585..3d7d1f71d 100644 --- a/adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py +++ b/adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py @@ -47,14 +47,14 @@ class RelayCliContract: observability_version: int -def resolve_relay_command(config_root: Path, value: str | Path) -> Path: +def resolve_relay_command(base_dir: Path, value: str | Path) -> Path: """Resolve the configured Relay CLI to one absolute executable path.""" command = Path(value) if len(command.parts) == 1: resolved = shutil.which(str(command)) else: - candidate = command if command.is_absolute() else config_root / command + candidate = command if command.is_absolute() else base_dir / command resolved = shutil.which(str(candidate.resolve())) if resolved is None: raise FileNotFoundError("NeMo Relay CLI executable was not found") diff --git a/adapters/common/src/nemo_fabric_adapters/common/utils.py b/adapters/common/src/nemo_fabric_adapters/common/utils.py index f815bfe53..9697690c2 100644 --- a/adapters/common/src/nemo_fabric_adapters/common/utils.py +++ b/adapters/common/src/nemo_fabric_adapters/common/utils.py @@ -54,20 +54,21 @@ def request_payload(payload: dict[str, Any]) -> dict[str, Any]: return payload.get("request") or {} -def effective_config(payload: dict[str, Any]) -> dict[str, Any]: - return payload.get("effective_config") or {} - - def fabric_config(payload: dict[str, Any]) -> dict[str, Any]: - return effective_config(payload).get("config") or {} + return payload.get("config") or {} -def config_root(payload: dict[str, Any]) -> str: - return effective_config(payload).get("config_root") or payload.get("config_root") or "." +def base_dir(payload: dict[str, Any]) -> str: + value = payload.get("base_dir") + if not isinstance(value, str) or not value: + raise ValueError("base_dir is required") + if not Path(value).is_absolute(): + raise ValueError("base_dir must be an absolute path") + return value def agent_name(payload: dict[str, Any]) -> str: - return effective_config(payload).get("agent_name") or payload.get("agent_name") or "fabric-agent" + return payload.get("agent_name") or "fabric-agent" def load_payload() -> dict[str, Any]: @@ -234,7 +235,7 @@ def load_relay_plugin_config(payload: dict[str, Any]) -> dict[str, Any]: def normalize_relay_output_dirs(plugin_config: dict[str, Any], payload: dict[str, Any]) -> None: - base = Path(config_root(payload)).resolve() + base = Path(base_dir(payload)).resolve() runtime_id = runtime_context(payload)["runtime_id"] for component in plugin_config.get("components", []): if component.get("kind") != "observability": diff --git a/adapters/deepagents/README.md b/adapters/deepagents/README.md index 5566220d2..2077546e1 100644 --- a/adapters/deepagents/README.md +++ b/adapters/deepagents/README.md @@ -109,10 +109,9 @@ artifacts directory). Fabric owns the runtime-to-thread correlation record; LangGraph owns the transcript. The `deepagents_config()` builder in `examples/code_review_agent` is the SDK -example; the `deepagents` profile under -`tests/fixtures/file-config-agent/profiles/` covers file-based resolution. Run it -from the CLI with `python -m examples.code_review_agent --variant deepagents ---input "..."`, or drive the SDK directly: +example. Run it from the CLI with +`python -m examples.code_review_agent --variant deepagents --input "..."`, or +drive the SDK directly: ```python from examples.code_review_agent import BASE_DIR, deepagents_config @@ -162,8 +161,9 @@ pip install "nemo-fabric-adapters-deepagents[relay]" # -> nemo-relay[deepagent Runs emit ATOF/ATIF artifacts to the configured output directory, referenced in the normalized result's `relay_artifacts` (and the `RunResult` `ArtifactManifest`). - OTel/OpenInference export is available through the relay plugin config (see the - `relay-otel` and `relay-openinference` profiles). + OTel/OpenInference export is available through the relay plugin config; the + example provides `with_relay_otel(...)` and + `with_relay_openinference(...)` variants. - **Native** (`telemetry.providers.native.config`): the provider config OpenTelemetry/OpenInference exporter is applied and spans export directly to the configured collector, without writing ATOF/ATIF relay artifacts. diff --git a/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py b/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py index a5d1399c3..0adc94c2d 100644 --- a/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py +++ b/adapters/deepagents/src/nemo_fabric_adapters/deepagents/adapter.py @@ -225,7 +225,7 @@ def resolve_backend(payload: dict[str, Any]) -> Any: return None root = Path(str(workspace)) if not root.is_absolute(): - root = Path(common_utils.config_root(payload)) / root + root = Path(common_utils.base_dir(payload)) / root from deepagents.backends import FilesystemBackend # virtual_mode=True confines the agent to root_dir; absolute paths and ``..`` @@ -309,17 +309,17 @@ def _mcp_connection(name: str, spec: dict[str, Any]) -> dict[str, Any]: def state_dir(payload: dict[str, Any]) -> Path: - config_root = Path(common_utils.config_root(payload)).resolve() + base_dir = Path(common_utils.base_dir(payload)).resolve() settings = common_utils.settings_payload(payload) configured = settings.get("state_dir") if configured: path = Path(str(configured)) - return path if path.is_absolute() else config_root / path + return path if path.is_absolute() else base_dir / path artifacts = common_utils.runtime_context(payload).get("artifacts") or {} root = artifacts.get("root") or os.environ.get("FABRIC_ARTIFACTS") if root: return Path(str(root)).resolve() / ".fabric" / "deepagents" - return config_root / "artifacts" / "deepagents" / ".fabric" + return base_dir / "artifacts" / "deepagents" / ".fabric" def runtime_state_paths(payload: dict[str, Any], runtime_id: str) -> tuple[Path, Path]: @@ -507,16 +507,16 @@ async def run_deepagents(payload: dict[str, Any]) -> dict[str, Any]: import importlib.util if importlib.util.find_spec("nemo_relay") is None: - raise RuntimeError( - "telemetry is enabled but the 'nemo-relay' package is not installed; " - "install the Relay extra (pip install 'nemo-fabric-adapters-deepagents[relay]')." + raise _relay_dependency_error() + try: + api_config = common_utils.relay_api_plugin_config(observability.plugin_config) + from nemo_relay import ScopeType, plugin, scope + from nemo_relay.integrations.deepagents import ( + NemoRelayDeepAgentsCallbackHandler, + add_nemo_relay_integration, ) - api_config = common_utils.relay_api_plugin_config(observability.plugin_config) - from nemo_relay import ScopeType, plugin, scope - from nemo_relay.integrations.deepagents import ( - NemoRelayDeepAgentsCallbackHandler, - add_nemo_relay_integration, - ) + except (ImportError, AttributeError) as exc: + raise _relay_dependency_error() from exc # add_nemo_relay_integration injects the Deep Agents middleware (model/tool # calls, skill/subagent config marks) into create_deep_agent's kwargs and the @@ -645,6 +645,13 @@ class Observability(NamedTuple): collect_artifacts: bool +def _relay_dependency_error() -> RuntimeError: + return RuntimeError( + "telemetry is enabled but a compatible 'nemo-relay' package is not installed; " + "install the Relay extra (pip install 'nemo-fabric-adapters-deepagents[relay]')." + ) + + def resolve_observability( payload: dict[str, Any], telemetry_provider: str, relay_enabled: bool ) -> Observability | None: diff --git a/adapters/hermes/README.md b/adapters/hermes/README.md index 4d125f8bc..4d560ba2e 100644 --- a/adapters/hermes/README.md +++ b/adapters/hermes/README.md @@ -53,7 +53,7 @@ Keep `fabric-adapter.json` aligned with the Python implementation: the adapter can produce or forward. Do not put end-user agent settings in this directory. Users vary harness, -model, skills, MCP, tools, telemetry, and runtime behavior through `agent.yaml` -and profiles. The adapter descriptor describes adapter capabilities; it is not a -profile. Add descriptor fields only when Fabric core or the SDK actually uses -them. +model, skills, MCP, tools, telemetry, and runtime behavior through complete +typed `FabricConfig` values and ordinary Python composition. The adapter +descriptor describes adapter capabilities; it is not an agent configuration. +Add descriptor fields only when Fabric core or the SDK actually uses them. diff --git a/adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py b/adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py index e3c21a82c..1faf92eaa 100755 --- a/adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py +++ b/adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py @@ -192,7 +192,7 @@ async def run_hermes(payload: dict[str, Any]) -> dict[str, Any]: settings = common_utils.settings_payload(payload) request = common_utils.request_payload(payload) model_config = common_utils.selected_model_config(payload) - hermes_home_base = Path(common_utils.config_root(payload)).joinpath( + hermes_home_base = Path(common_utils.base_dir(payload)).joinpath( settings.get("hermes_home", "./artifacts/hermes-home") ) hermes_home = common_utils.runtime_state_directory(hermes_home_base, payload) diff --git a/crates/fabric-cli/Cargo.toml b/crates/fabric-cli/Cargo.toml index b347ff0b8..2645f9743 100644 --- a/crates/fabric-cli/Cargo.toml +++ b/crates/fabric-cli/Cargo.toml @@ -7,11 +7,11 @@ version.workspace = true edition.workspace = true license.workspace = true repository.workspace = true -description = "Command-line interface for NeMo Fabric." +description = "Experimentation CLI for NeMo Fabric." readme = "README.md" [[bin]] -name = "fabric" +name = "nemo-fabric" path = "src/main.rs" [lints] @@ -19,6 +19,5 @@ workspace = true [dependencies] clap.workspace = true -ctrlc.workspace = true nemo-fabric-core.workspace = true serde_json.workspace = true diff --git a/crates/fabric-cli/README.md b/crates/fabric-cli/README.md index 55d0f5b02..b70d44ce5 100644 --- a/crates/fabric-cli/README.md +++ b/crates/fabric-cli/README.md @@ -5,20 +5,5 @@ SPDX-License-Identifier: Apache-2.0 # NVIDIA NeMo Fabric CLI -`nemo-fabric-cli` provides the `fabric` command-line interface for NVIDIA NeMo -Fabric, a runtime execution layer for agents. - -Install the CLI from crates.io: - -```bash -cargo install nemo-fabric-cli --locked -``` - -Use `fabric` to validate and inspect agent configurations, resolve run plans, -diagnose configuration issues, run or chat with agents through Fabric adapters, -and generate JSON Schema for the public configuration and runtime contracts. - -Run `fabric --help` for the complete command reference. - -For installation prerequisites, configuration concepts, adapters, and examples, -refer to the [NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric). +`nemo-fabric` is a small experimentation interface for presets and maintained +examples. Applications should construct `FabricConfig` through a language API. diff --git a/crates/fabric-cli/assets/adapters/claude/fabric-adapter.json b/crates/fabric-cli/assets/adapters/claude/fabric-adapter.json new file mode 100644 index 000000000..ed36b146a --- /dev/null +++ b/crates/fabric-cli/assets/adapters/claude/fabric-adapter.json @@ -0,0 +1,21 @@ +{ + "contract_version": "fabric.adapter/v1alpha1", + "adapter_id": "nvidia.fabric.claude", + "harness": "claude", + "adapter_kind": "python", + "runner": { + "module": "nemo_fabric_adapters.claude.adapter", + "callable": "run" + }, + "config": { + "accepts": ["models", "tools", "tools.blocked", "mcp", "skills", "telemetry"] + }, + "telemetry": { + "providers": { + "relay": { + "outputs": ["atif", "otel", "openinference"], + "integration_modes": ["hooks", "gateway"] + } + } + } +} diff --git a/crates/fabric-cli/assets/adapters/codex/fabric-adapter.json b/crates/fabric-cli/assets/adapters/codex/fabric-adapter.json new file mode 100644 index 000000000..9cbc7f147 --- /dev/null +++ b/crates/fabric-cli/assets/adapters/codex/fabric-adapter.json @@ -0,0 +1,24 @@ +{ + "contract_version": "fabric.adapter/v1alpha1", + "adapter_id": "nvidia.fabric.codex", + "harness": "codex", + "adapter_kind": "python", + "runner": { + "module": "nemo_fabric_adapters.codex.adapter", + "callable": "run" + }, + "config": { + "accepts": ["models", "telemetry"] + }, + "telemetry": { + "providers": { + "relay": { + "outputs": ["atif", "otel", "openinference"], + "integration_modes": ["hooks", "gateway"] + }, + "native": { + "outputs": ["otel"] + } + } + } +} diff --git a/crates/fabric-cli/assets/adapters/deepagents/fabric-adapter.json b/crates/fabric-cli/assets/adapters/deepagents/fabric-adapter.json new file mode 100644 index 000000000..78a09fe35 --- /dev/null +++ b/crates/fabric-cli/assets/adapters/deepagents/fabric-adapter.json @@ -0,0 +1,24 @@ +{ + "contract_version": "fabric.adapter/v1alpha1", + "adapter_id": "nvidia.fabric.langchain.deepagents", + "harness": "deepagents", + "adapter_kind": "python", + "runner": { + "module": "nemo_fabric_adapters.deepagents.adapter", + "callable": "run" + }, + "requirements": {}, + "config": { + "accepts": ["models", "tools", "tools.blocked", "mcp", "skills", "telemetry"] + }, + "telemetry": { + "providers": { + "relay": { + "outputs": ["atif", "otel", "openinference"] + }, + "native": { + "outputs": ["otel", "openinference"] + } + } + } +} diff --git a/crates/fabric-cli/assets/adapters/hermes/fabric-adapter.json b/crates/fabric-cli/assets/adapters/hermes/fabric-adapter.json new file mode 100644 index 000000000..f28574707 --- /dev/null +++ b/crates/fabric-cli/assets/adapters/hermes/fabric-adapter.json @@ -0,0 +1,36 @@ +{ + "contract_version": "fabric.adapter/v1alpha1", + "adapter_id": "nvidia.fabric.hermes", + "harness": "hermes", + "adapter_kind": "python", + "runner": { + "module": "nemo_fabric_adapters.hermes.adapter", + "callable": "run" + }, + "requirements": { + "env": [ + "NVIDIA_API_KEY" + ] + }, + "config": { + "accepts": [ + "models", + "tools", + "tools.blocked", + "mcp", + "skills", + "telemetry" + ] + }, + "telemetry": { + "providers": { + "relay": { + "outputs": [ + "atif", + "otel", + "openinference" + ] + } + } + } +} diff --git a/crates/fabric-cli/assets/adapters/scripted/fabric-adapter.json b/crates/fabric-cli/assets/adapters/scripted/fabric-adapter.json new file mode 100644 index 000000000..298b1e4e3 --- /dev/null +++ b/crates/fabric-cli/assets/adapters/scripted/fabric-adapter.json @@ -0,0 +1,11 @@ +{ + "contract_version": "fabric.adapter/v1alpha1", + "adapter_id": "nvidia.fabric.scripted", + "harness": "scripted", + "adapter_kind": "process", + "runner": { + "command": "python3", + "script": "run.py", + "stdin_payload": "fabric_request" + } +} diff --git a/crates/fabric-cli/assets/adapters/scripted/run.py b/crates/fabric-cli/assets/adapters/scripted/run.py new file mode 100644 index 000000000..1f0f3cce6 --- /dev/null +++ b/crates/fabric-cli/assets/adapters/scripted/run.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Deterministic process adapter for credential-free CLI experiments.""" + +import json +import sys + + +payload = json.load(sys.stdin) +request = payload["request"] +print( + json.dumps( + { + "response": request.get("input"), + "request_id": request["request_id"], + } + ) +) diff --git a/crates/fabric-cli/assets/examples/code-review/repo/calculator.py b/crates/fabric-cli/assets/examples/code-review/repo/calculator.py new file mode 100644 index 000000000..c53bc9482 --- /dev/null +++ b/crates/fabric-cli/assets/examples/code-review/repo/calculator.py @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Tiny workspace used by the installed code-review example.""" + + +def divide(total: float, count: float) -> float: + return total / count diff --git a/crates/fabric-cli/assets/examples/code-review/skills/code-review.md b/crates/fabric-cli/assets/examples/code-review/skills/code-review.md new file mode 100644 index 000000000..cbc0f18db --- /dev/null +++ b/crates/fabric-cli/assets/examples/code-review/skills/code-review.md @@ -0,0 +1,8 @@ + + +# Code Review + +Inspect the workspace, prioritize correctness issues, and explain concrete fixes. diff --git a/crates/fabric-cli/src/app.rs b/crates/fabric-cli/src/app.rs new file mode 100644 index 000000000..6093f356c --- /dev/null +++ b/crates/fabric-cli/src/app.rs @@ -0,0 +1,464 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! NeMo Fabric experimentation CLI. + +use clap::error::ErrorKind; +use clap::{ArgGroup, Args, Parser, Subcommand}; +use nemo_fabric_core::{ + ResolveContext, RunRequest, RunStatus, doctor_plan, resolve_run_plan_from_config, run_plan, +}; + +use crate::examples; +use crate::presets; +use crate::scaffold::{self, Language}; + +#[derive(Debug, Parser)] +#[command(name = "nemo-fabric")] +#[command(about = "Experiment with NeMo Fabric presets and maintained examples")] +#[command(arg_required_else_help = true)] +#[command(version)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + /// Discover complete built-in presets. + Preset { + #[command(subcommand)] + command: PresetCommand, + }, + /// Discover and initialize maintained examples. + Example { + #[command(subcommand)] + command: ExampleCommand, + }, + /// Resolve and print a run plan as JSON. + Plan(Selector), + /// Diagnose a selected configuration without running it. + Doctor(Selector), + /// Execute one request through a selected configuration. + Run { + #[command(flatten)] + selector: Selector, + /// Inline request text. + #[arg(long, default_value = "")] + input: String, + }, + /// Print the Fabric core version. + Version, +} + +#[derive(Debug, Subcommand)] +enum PresetCommand { + /// List available presets. + List, + /// Describe one preset without serializing its configuration. + Show { + /// Preset name. + name: String, + }, +} + +#[derive(Debug, Subcommand)] +enum ExampleCommand { + /// List maintained runnable examples. + List, + /// Describe one example and its complete variants. + Show { + /// Example name. + name: String, + }, + /// Generate an ordinary editable SDK application. + Init { + /// Example name. + name: String, + /// Destination directory; defaults to the example name. + destination: Option, + /// Language API used by the generated application. + #[arg(long, value_enum, default_value_t = Language::Python)] + language: Language, + /// Complete example variant rendered into source code. + #[arg(long)] + variant: Option, + }, +} + +#[derive(Debug, Args)] +#[command(group( + ArgGroup::new("source") + .required(true) + .multiple(false) + .args(["preset", "example"]) +))] +struct Selector { + /// Use a maintained, complete built-in preset. + #[arg(long, value_name = "NAME")] + preset: Option, + /// Use a maintained runnable example. + #[arg(long, value_name = "NAME")] + example: Option, + /// Select a complete example variant. + #[arg( + long, + value_name = "NAME", + requires = "example", + conflicts_with = "preset" + )] + variant: Option, + /// Override the preset's default model identifier. + #[arg( + long, + value_name = "MODEL", + conflicts_with = "example", + value_parser = clap::builder::NonEmptyStringValueParser::new() + )] + model: Option, + /// Override the preset's default model temperature. + #[arg( + long, + value_name = "FLOAT", + conflicts_with = "example", + value_parser = parse_temperature + )] + temperature: Option, +} + +fn parse_temperature(value: &str) -> Result { + let temperature = value + .parse::() + .map_err(|error| format!("invalid temperature: {error}"))?; + if !temperature.is_finite() { + return Err("temperature must be finite".to_string()); + } + Ok(temperature) +} + +enum SelectedSource { + Preset(presets::SelectedPreset), + Example(examples::SelectedExample), +} + +impl SelectedSource { + fn config(&self) -> &nemo_fabric_core::FabricConfig { + match self { + Self::Preset(selected) => &selected.config, + Self::Example(selected) => &selected.config, + } + } + + fn base_dir(&self) -> &std::path::Path { + match self { + Self::Preset(selected) => selected.base_dir(), + Self::Example(selected) => selected.base_dir(), + } + } +} + +/// Parse command-line arguments and execute the experimentation CLI. +pub fn execute_from(args: I) -> Result<(), String> +where + I: IntoIterator, + T: Into + Clone, +{ + let cli = match Cli::try_parse_from(args) { + Ok(cli) => cli, + Err(error) + if matches!( + error.kind(), + ErrorKind::DisplayHelp | ErrorKind::DisplayVersion + ) => + { + error.print().map_err(|error| error.to_string())?; + return Ok(()); + } + Err(error) => return Err(error.to_string()), + }; + run(cli).map_err(|error| error.to_string()) +} + +fn run(cli: Cli) -> Result<(), Box> { + match cli.command { + Command::Preset { + command: PresetCommand::List, + } => { + for preset in presets::all() { + println!("{:<12} {}", preset.name, preset.description); + } + } + Command::Preset { + command: PresetCommand::Show { name }, + } => { + let preset = find_preset(&name)?; + println!("{}\n {}", preset.name, preset.description); + if preset.required_env.is_empty() { + println!(" credentials: none"); + } else { + println!(" required environment: {}", preset.required_env.join(", ")); + } + } + Command::Example { + command: ExampleCommand::List, + } => { + for example in examples::all() { + println!("{:<12} {}", example.name, example.description); + } + } + Command::Example { + command: ExampleCommand::Show { name }, + } => { + let example = find_example(&name)?; + println!("{}\n {}", example.name, example.description); + println!(" default variant: {}", example.default_variant); + println!(" variants: {}", example.variants.join(", ")); + } + Command::Example { + command: + ExampleCommand::Init { + name, + destination, + language, + variant, + }, + } => { + let example = find_example(&name)?; + let destination = destination.unwrap_or_else(|| std::path::PathBuf::from(&name)); + let destination = scaffold::init(example, variant.as_deref(), language, &destination)?; + println!("created {}", destination.display()); + } + Command::Plan(selector) => { + let selected = select_source(&selector)?; + let plan = resolve_run_plan_from_config( + selected.config().clone(), + ResolveContext::new(selected.base_dir()), + )?; + println!("{}", serde_json::to_string_pretty(&plan)?); + } + Command::Doctor(selector) => { + let selected = select_source(&selector)?; + let plan = resolve_run_plan_from_config( + selected.config().clone(), + ResolveContext::new(selected.base_dir()), + )?; + println!("{}", serde_json::to_string_pretty(&doctor_plan(&plan))?); + } + Command::Run { selector, input } => { + let selected = select_source(&selector)?; + let plan = resolve_run_plan_from_config( + selected.config().clone(), + ResolveContext::new(selected.base_dir()), + )?; + let result = run_plan(&plan, RunRequest::text(input))?; + println!("{}", serde_json::to_string_pretty(&result)?); + require_successful_run(result.status)?; + } + Command::Version => println!("{}", nemo_fabric_core::version()), + } + Ok(()) +} + +fn require_successful_run(status: RunStatus) -> Result<(), String> { + match status { + RunStatus::Succeeded => Ok(()), + RunStatus::Failed => Err("run completed with status failed".to_string()), + RunStatus::Cancelled => Err("run completed with status cancelled".to_string()), + } +} + +fn select_source(selector: &Selector) -> Result> { + if let Some(name) = &selector.preset { + let mut selected = find_preset(name)?.stage()?; + apply_model_overrides(&mut selected.config, selector)?; + return Ok(SelectedSource::Preset(selected)); + } + if let Some(name) = &selector.example { + return Ok(SelectedSource::Example( + find_example(name)?.select(selector.variant.as_deref())?, + )); + } + unreachable!("Clap requires exactly one source selector") +} + +fn apply_model_overrides( + config: &mut nemo_fabric_core::FabricConfig, + selector: &Selector, +) -> Result<(), String> { + if selector.model.is_none() && selector.temperature.is_none() { + return Ok(()); + } + let default_model = config + .models + .get_mut("default") + .ok_or_else(|| "the selected preset does not define a default model".to_string())?; + if let Some(model) = &selector.model { + default_model.model.clone_from(model); + } + if let Some(temperature) = selector.temperature { + default_model.temperature = Some(temperature); + } + Ok(()) +} + +fn find_preset(name: &str) -> Result { + presets::find(name).ok_or_else(|| { + format!( + "unknown preset {name:?}; available: {}", + presets::all() + .iter() + .map(|preset| preset.name) + .collect::>() + .join(", ") + ) + }) +} + +fn find_example(name: &str) -> Result { + examples::find(name).ok_or_else(|| { + format!( + "unknown example {name:?}; available: {}", + examples::all() + .iter() + .map(|example| example.name) + .collect::>() + .join(", ") + ) + }) +} + +#[cfg(test)] +mod tests { + use clap::Parser; + + use super::*; + + #[test] + fn missing_subcommand_is_an_error() { + assert!(execute_from(["nemo-fabric"]).is_err()); + } + + #[test] + fn explicit_help_is_successful() { + assert!(execute_from(["nemo-fabric", "--help"]).is_ok()); + } + + #[test] + fn failed_and_cancelled_runs_are_errors() { + assert!(require_successful_run(RunStatus::Succeeded).is_ok()); + assert!(require_successful_run(RunStatus::Failed).is_err()); + assert!(require_successful_run(RunStatus::Cancelled).is_err()); + } + + #[test] + fn parses_preset_plan() { + let cli = Cli::try_parse_from(["nemo-fabric", "plan", "--preset", "scripted"]) + .expect("parse plan"); + assert!(matches!(cli.command, Command::Plan(_))); + } + + #[test] + fn preset_model_overrides_preserve_provider_settings() { + let selector = Selector { + preset: Some("hermes".to_string()), + example: None, + variant: None, + model: Some("meta/llama-3.3-70b-instruct".to_string()), + temperature: Some(0.2), + }; + let selected = select_source(&selector).expect("select preset"); + let model = selected.config().models.get("default").expect("model"); + + assert_eq!(model.provider, "nvidia"); + assert_eq!(model.model, "meta/llama-3.3-70b-instruct"); + assert_eq!(model.temperature, Some(0.2)); + assert_eq!(model.api_key_env.as_deref(), Some("NVIDIA_API_KEY")); + } + + #[test] + fn model_overrides_require_a_preset_with_a_default_model() { + assert!( + Cli::try_parse_from([ + "nemo-fabric", + "plan", + "--example", + "code-review", + "--model", + "other-model", + ]) + .is_err() + ); + + let selector = Selector { + preset: Some("scripted".to_string()), + example: None, + variant: None, + model: Some("other-model".to_string()), + temperature: None, + }; + assert_eq!( + select_source(&selector) + .err() + .expect("scripted has no default model") + .to_string(), + "the selected preset does not define a default model" + ); + + assert!( + Cli::try_parse_from([ + "nemo-fabric", + "plan", + "--preset", + "hermes", + "--temperature", + "NaN", + ]) + .is_err() + ); + } + + #[test] + fn parses_example_variant() { + let cli = Cli::try_parse_from([ + "nemo-fabric", + "run", + "--example", + "code-review", + "--variant", + "hermes", + ]) + .expect("parse example run"); + assert!(matches!(cli.command, Command::Run { .. })); + } + + #[test] + fn selectors_are_mutually_exclusive() { + assert!( + Cli::try_parse_from([ + "nemo-fabric", + "plan", + "--preset", + "scripted", + "--example", + "code-review", + ]) + .is_err() + ); + assert!( + Cli::try_parse_from([ + "nemo-fabric", + "plan", + "--preset", + "scripted", + "--variant", + "hermes", + ]) + .is_err() + ); + } + + #[test] + fn plan_requires_a_preset() { + assert!(Cli::try_parse_from(["nemo-fabric", "plan"]).is_err()); + } +} diff --git a/crates/fabric-cli/src/assets.rs b/crates/fabric-cli/src/assets.rs new file mode 100644 index 000000000..1aef9e4d4 --- /dev/null +++ b/crates/fabric-cli/src/assets.rs @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Embedded assets used by installation-safe CLI experiments. + +use std::fs; +use std::path::{Path, PathBuf}; +use std::time::{SystemTime, UNIX_EPOCH}; + +/// One embedded file and its path relative to a staged asset root. +#[derive(Debug, Clone, Copy)] +pub struct EmbeddedFile { + /// Relative path written under the staged root. + pub path: &'static str, + /// UTF-8 file contents. + pub contents: &'static str, +} + +/// Temporary asset root retained for the lifetime of a selected experiment. +#[derive(Debug)] +pub struct StagedAssets { + path: PathBuf, +} + +impl StagedAssets { + /// Stage embedded files and return their temporary base directory. + pub fn create(files: &[EmbeddedFile]) -> std::io::Result { + let nonce = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_nanos(); + let path = std::env::temp_dir().join(format!("nemo-fabric-{}-{nonce}", std::process::id())); + fs::create_dir(&path)?; + for file in files { + let destination = path.join(file.path); + if let Some(parent) = destination.parent() { + fs::create_dir_all(parent)?; + } + fs::write(destination, file.contents)?; + } + Ok(Self { path }) + } + + /// Return the staged base directory. + pub fn path(&self) -> &Path { + &self.path + } +} + +impl Drop for StagedAssets { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.path); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stages_and_removes_embedded_files() { + let root_path; + { + let root = StagedAssets::create(&[EmbeddedFile { + path: "nested/value.txt", + contents: "value", + }]) + .expect("stage assets"); + root_path = root.path().to_path_buf(); + assert_eq!( + fs::read_to_string(root.path().join("nested/value.txt")).expect("read asset"), + "value" + ); + } + assert!(!root_path.exists()); + } +} diff --git a/crates/fabric-cli/src/examples.rs b/crates/fabric-cli/src/examples.rs new file mode 100644 index 000000000..69670c375 --- /dev/null +++ b/crates/fabric-cli/src/examples.rs @@ -0,0 +1,186 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Maintained runnable examples composed from presets and shared assets. + +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +use nemo_fabric_core::{FabricConfig, MetadataConfig, SkillConfig}; + +use crate::assets::{EmbeddedFile, StagedAssets}; +use crate::presets::{self, Preset}; + +pub(crate) const CODE_REVIEW_WORKSPACE: &str = + include_str!("../assets/examples/code-review/repo/calculator.py"); +pub(crate) const CODE_REVIEW_SKILL: &str = + include_str!("../assets/examples/code-review/skills/code-review.md"); + +const CODE_REVIEW_FILES: &[EmbeddedFile] = &[ + EmbeddedFile { + path: "repo/calculator.py", + contents: CODE_REVIEW_WORKSPACE, + }, + EmbeddedFile { + path: "skills/code-review.md", + contents: CODE_REVIEW_SKILL, + }, +]; +const CODE_REVIEW_VARIANTS: &[&str] = &["scripted", "hermes", "claude", "codex", "deepagents"]; + +/// Metadata and variant catalog for one maintained CLI example. +#[derive(Debug, Clone, Copy)] +pub struct Example { + /// Stable command-line name. + pub name: &'static str, + /// Short experimentation-oriented description. + pub description: &'static str, + /// Variant selected when `--variant` is omitted. + pub default_variant: &'static str, + /// Complete supported variant names. + pub variants: &'static [&'static str], +} + +impl Example { + fn preset(self, variant: Option<&str>) -> Result { + let variant = variant.unwrap_or(self.default_variant); + if !self.variants.contains(&variant) { + return Err(format!( + "unknown variant {variant:?} for example {:?}; available: {}", + self.name, + self.variants.join(", ") + )); + } + presets::find(variant).ok_or_else(|| { + format!( + "example {:?} references missing preset {variant:?}", + self.name + ) + }) + } + + /// Construct one complete example config without staging its assets. + pub fn config(self, variant: Option<&str>) -> Result { + self.preset(variant).map(code_review_config) + } + + /// Construct and stage one complete example variant. + pub fn select(self, variant: Option<&str>) -> Result { + let preset = self.preset(variant)?; + let files = self.embedded_files(preset); + let assets = StagedAssets::create(&files) + .map_err(|error| format!("failed to stage example {:?}: {error}", self.name))?; + Ok(SelectedExample { + example: self, + variant: preset, + config: code_review_config(preset), + assets, + }) + } + + pub(crate) fn embedded_files(self, preset: Preset) -> Vec { + let mut files = Vec::from(preset.embedded_files()); + files.extend_from_slice(CODE_REVIEW_FILES); + files + } +} + +/// Selected example variant and its staged installation-safe assets. +#[derive(Debug)] +pub struct SelectedExample { + /// Example metadata. + pub example: Example, + /// Preset reused by this complete example variant. + pub variant: Preset, + /// Complete typed example configuration. + pub config: FabricConfig, + assets: StagedAssets, +} + +impl SelectedExample { + /// Return the base directory for resolving this example. + pub fn base_dir(&self) -> &Path { + self.assets.path() + } +} + +/// Return the maintained example catalog. +pub fn all() -> &'static [Example] { + &EXAMPLES +} + +/// Find an example by its stable CLI name. +pub fn find(name: &str) -> Option { + EXAMPLES + .iter() + .copied() + .find(|example| example.name == name) +} + +const EXAMPLES: [Example; 1] = [Example { + name: "code-review", + description: "Review a small Python workspace using a maintained skill.", + default_variant: "scripted", + variants: CODE_REVIEW_VARIANTS, +}]; + +fn code_review_config(preset: Preset) -> FabricConfig { + let mut config = preset.config(); + config.metadata = MetadataConfig { + name: "code-review-agent".to_string(), + description: Some("Maintained example for reviewing a small Python workspace.".to_string()), + extensions: BTreeMap::new(), + }; + let environment = config + .environment + .as_mut() + .expect("CLI presets always define an execution environment"); + environment.workspace = Some(PathBuf::from("repo")); + config.skills = Some(SkillConfig { + paths: vec![PathBuf::from("skills/code-review.md")], + extensions: BTreeMap::new(), + }); + config +} + +#[cfg(test)] +mod tests { + use nemo_fabric_core::{ResolveContext, RunRequest, resolve_run_plan_from_config, run_plan}; + + use super::*; + + #[test] + fn variants_reuse_the_preset_catalog() { + let example = find("code-review").expect("code review example"); + for variant in example.variants { + assert!(presets::find(variant).is_some(), "missing preset {variant}"); + } + } + + #[test] + fn code_review_stages_one_shared_asset_tree_and_runs() { + let selected = find("code-review") + .expect("code review example") + .select(Some("scripted")) + .expect("select example"); + assert!(selected.base_dir().join("repo/calculator.py").is_file()); + assert!(selected.base_dir().join("skills/code-review.md").is_file()); + let plan = resolve_run_plan_from_config( + selected.config.clone(), + ResolveContext::new(selected.base_dir()), + ) + .expect("plan example"); + assert_eq!(plan.agent_name, "code-review-agent"); + assert_eq!( + plan.environment_plan + .as_ref() + .expect("environment") + .workspace + .as_ref(), + Some(&selected.base_dir().join("repo")) + ); + let result = + run_plan(&plan, RunRequest::text("review")).expect("run deterministic example variant"); + assert_eq!(result.output["response"], "review"); + } +} diff --git a/crates/fabric-cli/src/lib.rs b/crates/fabric-cli/src/lib.rs new file mode 100644 index 000000000..1ff9b6c8c --- /dev/null +++ b/crates/fabric-cli/src/lib.rs @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Catalog and asset staging for the NeMo Fabric experimentation CLI. + +pub mod app; +pub mod assets; +pub mod examples; +pub mod presets; +pub mod scaffold; diff --git a/crates/fabric-cli/src/main.rs b/crates/fabric-cli/src/main.rs index 4ee4bab9c..4fc11efcd 100644 --- a/crates/fabric-cli/src/main.rs +++ b/crates/fabric-cli/src/main.rs @@ -1,489 +1,16 @@ // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! NeMo Fabric command-line interface. +//! Standalone NeMo Fabric experimentation CLI binary. -use std::io::{self, BufRead, IsTerminal, Write}; -use std::path::PathBuf; use std::process::ExitCode; -use std::sync::{ - Arc, - atomic::{AtomicBool, Ordering}, - mpsc::{self, Receiver}, -}; -use std::thread; -use std::time::Duration; - -use clap::{Parser, Subcommand}; -use nemo_fabric_core::{ - AdapterKind, RunPlan, RunRequest, RunResult, RunStatus, RuntimeHandle, SchemaName, doctor_plan, - generate_all_schemas, generate_schema_json, invoke_runtime, - resolve_effective_config_with_profiles, resolve_run_plan_with_profiles, run_plan, - start_runtime, stop_runtime, validate_agent_directory, write_schema_snapshots, -}; -use serde_json::Value; - -#[derive(Debug, Parser)] -#[command(name = "fabric")] -#[command(about = "Harness-management CLI for NeMo Fabric")] -#[command(version)] -struct Cli { - #[command(subcommand)] - command: Option, -} - -#[derive(Debug, Subcommand)] -enum Command { - /// Validate an agent directory or YAML config. - Validate { - /// Path to an agent directory or YAML config. - path: PathBuf, - }, - /// Resolve and print the effective Fabric config as JSON. - Inspect { - /// Path to an agent directory or YAML config. - path: PathBuf, - /// Profile name from configured profile directories, or a YAML profile path. - #[arg(long = "profile")] - profile: Vec, - }, - /// Resolve an agent/profile into a runnable plan. - Plan { - /// Path to an agent directory or YAML config. - path: PathBuf, - /// Profile name from configured profile directories, or a YAML profile path. - #[arg(long = "profile")] - profile: Vec, - }, - /// Diagnose a resolved agent/profile without installing or running it. - Doctor { - /// Path to an agent directory or YAML config. - path: PathBuf, - /// Profile name from configured profile directories, or a YAML profile path. - #[arg(long = "profile")] - profile: Vec, - }, - /// Start an interactive multi-turn runtime. - Chat { - /// Path to an agent directory or YAML config. - path: PathBuf, - /// Profile name from configured profile directories, or a YAML profile path. - #[arg(long = "profile")] - profile: Vec, - /// Show per-turn runtime, invocation, artifact, and telemetry details. - #[arg(long)] - verbose: bool, - }, - /// Run an agent/profile through its Fabric adapter. - Run { - /// Path to an agent directory or YAML config. - path: PathBuf, - /// Profile name from configured profile directories, or a YAML profile path. - #[arg(long = "profile")] - profile: Vec, - /// Inline request payload. - #[arg(long, default_value = "")] - input: String, - /// Request payload file. - #[arg(long)] - input_file: Option, - /// Full Fabric RunRequest JSON payload. - #[arg(long)] - request_json: Option, - /// Full Fabric RunRequest JSON file. - #[arg(long)] - request_file: Option, - /// Show adapter output. - #[arg(long = "show-output")] - show_output: bool, - }, - /// Generate JSON Schema for Fabric config and runtime types. - Schema { - /// Schema name to print or write. Omit to include all schemas. - #[arg(long)] - name: Option, - /// Directory to write schema snapshot files to. Omit to print JSON. - #[arg(long)] - output_dir: Option, - }, - /// Print the Fabric core version. - Version, -} fn main() -> ExitCode { - match run() { + match nemo_fabric_cli::app::execute_from(std::env::args_os()) { Ok(()) => ExitCode::SUCCESS, Err(error) => { - eprintln!("{error}"); + eprintln!("error: {error}"); ExitCode::FAILURE } } } - -fn run() -> Result<(), Box> { - let cli = Cli::parse(); - match cli.command { - Some(Command::Validate { path }) => { - validate_agent_directory(&path)?; - println!("validated {}", path.display()); - } - Some(Command::Inspect { path, profile }) => { - let effective_config = resolve_effective_config_with_profiles(path, &profile)?; - println!("{}", serde_json::to_string_pretty(&effective_config)?); - } - Some(Command::Plan { path, profile }) => { - let plan = resolve_run_plan_with_profiles(path, &profile)?; - println!("{}", serde_json::to_string_pretty(&plan)?); - } - Some(Command::Doctor { path, profile }) => { - let plan = resolve_run_plan_with_profiles(path, &profile)?; - let report = doctor_plan(&plan); - println!("{}", serde_json::to_string_pretty(&report)?); - } - Some(Command::Chat { - path, - profile, - verbose, - }) => { - run_chat(path, &profile, verbose)?; - } - Some(Command::Run { - path, - profile, - input, - input_file, - request_json, - request_file, - show_output, - }) => { - let plan = resolve_run_plan_with_profiles(path, &profile)?; - let request = match (request_file, request_json, input_file) { - (Some(path), None, None) => { - serde_json::from_str::(&std::fs::read_to_string(path)?)? - } - (None, Some(json), None) => serde_json::from_str::(&json)?, - (None, None, Some(path)) => RunRequest::text(std::fs::read_to_string(path)?), - (None, None, None) => RunRequest::text(input), - _ => { - return Err( - "--request-file, --request-json, and --input-file are mutually exclusive" - .into(), - ); - } - }; - let result = run_plan(&plan, request)?; - println!("{}", serde_json::to_string_pretty(&result)?); - if show_output { - if let Some(response) = result.output.get("response") { - println!("\nResponse:"); - if let Some(response) = response.as_str() { - println!("{response}"); - } else { - println!("{}", serde_json::to_string_pretty(response)?); - } - } - } - - let _exit_code = result - .metadata - .get("exit_code") - .and_then(serde_json::Value::as_i64) - .unwrap_or(0); - if _exit_code != 0 { - let message = result - .error - .as_ref() - .map(|error| error.message.clone()) - .unwrap_or_else(|| format!("harness exited with an exit code of {_exit_code}")); - return Err(message.into()); - } - } - Some(Command::Schema { name, output_dir }) => { - if let Some(output_dir) = output_dir { - if let Some(name) = name { - let schema = SchemaName::parse(&name)?; - let path = output_dir.join(schema.filename()); - std::fs::create_dir_all(&output_dir)?; - std::fs::write(&path, generate_schema_json(schema)?)?; - println!("wrote {}", path.display()); - } else { - for path in write_schema_snapshots(&output_dir)? { - println!("wrote {}", path.display()); - } - } - } else if let Some(name) = name { - println!("{}", generate_schema_json(SchemaName::parse(&name)?)?); - } else { - println!( - "{}", - serde_json::to_string_pretty(&generate_all_schemas()?)? - ); - } - } - Some(Command::Version) | None => { - println!("fabric {}", nemo_fabric_core::version()); - } - } - Ok(()) -} - -fn run_chat( - path: PathBuf, - profile: &[String], - verbose: bool, -) -> Result<(), Box> { - let plan = resolve_run_plan_with_profiles(path, profile)?; - let runtime = start_runtime(&plan)?; - let chat_result = chat_loop(&plan, &runtime, verbose); - let stop_result = stop_runtime(&plan, &runtime); - if let Err(error) = chat_result { - return Err(error); - } - stop_result?; - Ok(()) -} - -fn chat_loop( - plan: &RunPlan, - runtime: &RuntimeHandle, - mut verbose: bool, -) -> Result<(), Box> { - let prompt = chat_prompt(plan, &runtime.runtime_id); - let interrupted = Arc::new(AtomicBool::new(false)); - { - let interrupted = Arc::clone(&interrupted); - ctrlc::set_handler(move || { - interrupted.store(true, Ordering::SeqCst); - })?; - } - let input_is_terminal = io::stdin().is_terminal(); - let lines = stdin_lines(); - print_chat_info(plan, runtime); - eprintln!(); - let mut turn_count = 0_u64; - - loop { - eprint!("{prompt}> "); - io::stderr().flush()?; - - let Some(line) = next_chat_line(&lines, &interrupted)? else { - break; - }; - let input = line; - let command = input.trim(); - match command { - "/exit" | "/quit" => break, - "/help" => { - print_chat_help(); - continue; - } - "/info" => { - print_chat_info(plan, runtime); - continue; - } - "/clear" => { - eprint!("\x1b[2J\x1b[H"); - continue; - } - "/verbose" => { - verbose = !verbose; - eprintln!("verbose: {}", if verbose { "on" } else { "off" }); - continue; - } - "" => continue, - _ => {} - } - if let Some(value) = command.strip_prefix("/verbose ") { - match value.trim() { - "on" => { - verbose = true; - eprintln!("verbose: on"); - continue; - } - "off" => { - verbose = false; - eprintln!("verbose: off"); - continue; - } - _ => { - eprintln!("usage: /verbose on|off"); - continue; - } - } - } - if command.starts_with('/') { - eprintln!("unknown command: {command}"); - eprintln!("type /help for available commands"); - continue; - } - - let request = RunRequest::text(input); - let result = invoke_runtime(plan, runtime, request)?; - turn_count += 1; - if !input_is_terminal { - eprintln!(); - } - print_chat_response(&result.output)?; - if verbose { - eprintln!(); - print_turn_verbose(turn_count, &result); - } - - let exit_code = result - .metadata - .get("exit_code") - .and_then(Value::as_i64) - .unwrap_or(0); - if exit_code != 0 { - let message = result - .error - .as_ref() - .map(|error| error.message.clone()) - .unwrap_or_else(|| format!("harness exited with an exit code of {exit_code}")); - return Err(message.into()); - } - } - Ok(()) -} - -fn print_chat_info(plan: &RunPlan, runtime: &RuntimeHandle) { - eprintln!("+================================================================+"); - eprintln!("| NEMO FABRIC |"); - eprintln!("| interactive runtime |"); - eprintln!("+----------------------------------------------------------------+"); - eprintln!("| agent: {}", plan.agent_name); - eprintln!("| profile: {}", profile_label(plan)); - eprintln!("| harness: {}", runtime.harness); - eprintln!("| adapter: {}", adapter_kind_label(runtime.adapter_kind)); - eprintln!("| runtime_id: {}", runtime.runtime_id); - eprintln!("| commands: /help, /info, /verbose on|off, /clear, /exit, /quit"); - eprintln!("+----------------------------------------------------------------"); -} - -fn print_chat_help() { - eprintln!("Commands:"); - eprintln!(" /help show this help"); - eprintln!(" /info show runtime info"); - eprintln!(" /verbose on|off toggle per-turn metadata"); - eprintln!(" /clear clear the terminal"); - eprintln!(" /exit, /quit stop the runtime and exit"); - eprintln!("Type a non-empty message to invoke the same runtime."); -} - -fn print_turn_verbose(turn: u64, result: &RunResult) { - eprintln!("+-- turn {turn} metadata ---------------------------------------------"); - eprintln!("| status: {}", status_label(result.status)); - eprintln!("| request_id: {}", result.request_id); - eprintln!("| invocation_id: {}", result.invocation_id); - eprintln!("| runtime_id: {}", result.runtime_id); - eprintln!("| artifact_count: {}", result.artifacts.artifacts.len()); - if let Some(telemetry) = result.telemetry.as_ref() { - eprintln!("| telemetry: relay_enabled={}", telemetry.relay_enabled); - if let Some(path) = telemetry - .metadata - .get("relay_config_path") - .and_then(Value::as_str) - { - eprintln!("| telemetry_config: {path}"); - } - } - if let Some(error) = result.error.as_ref() { - eprintln!("| error: {} {}", error.code, error.message); - } - eprintln!("+----------------------------------------------------------------"); -} - -fn chat_prompt(plan: &RunPlan, runtime_id: &str) -> String { - format!( - "you[{}:{}]", - profile_label(plan), - short_prompt_label(runtime_id) - ) -} - -fn short_prompt_label(value: &str) -> String { - let mut chars = value.chars(); - let short: String = chars.by_ref().take(24).collect(); - if chars.next().is_none() { - short - } else { - format!("{short}...") - } -} - -fn profile_label(plan: &RunPlan) -> String { - if !plan.profiles.is_empty() { - return plan.profiles.join(", "); - } - "default".to_string() -} - -fn adapter_kind_label(adapter_kind: AdapterKind) -> &'static str { - match adapter_kind { - AdapterKind::Process => "process", - AdapterKind::Http => "http", - AdapterKind::Python => "python", - AdapterKind::NativePlugin => "native_plugin", - } -} - -fn status_label(status: RunStatus) -> &'static str { - match status { - RunStatus::Succeeded => "succeeded", - RunStatus::Failed => "failed", - RunStatus::Cancelled => "cancelled", - } -} - -fn stdin_lines() -> Receiver> { - let (sender, receiver) = mpsc::channel(); - thread::spawn(move || { - let stdin = io::stdin(); - for line in stdin.lock().lines() { - if sender.send(line).is_err() { - break; - } - } - }); - receiver -} - -fn next_chat_line( - lines: &Receiver>, - interrupted: &AtomicBool, -) -> Result, Box> { - loop { - if interrupted.load(Ordering::SeqCst) { - eprintln!(); - return Ok(None); - } - match lines.recv_timeout(Duration::from_millis(100)) { - Ok(line) => return Ok(Some(line?)), - Err(mpsc::RecvTimeoutError::Timeout) => {} - Err(mpsc::RecvTimeoutError::Disconnected) => return Ok(None), - } - } -} - -fn print_chat_response(output: &Value) -> Result<(), Box> { - let response = output.get("response").unwrap_or(output); - if let Some(response) = response.as_str() { - print_chat_text("agent", response); - } else { - let response = serde_json::to_string_pretty(response)?; - print_chat_text("agent", &response); - } - Ok(()) -} - -fn print_chat_text(role: &str, text: &str) { - let mut lines = text.lines(); - if let Some(first) = lines.next() { - eprintln!("{role}> {first}"); - for line in lines { - eprintln!("{:width$}{line}", "", width = role.len() + 2); - } - } else { - eprintln!("{role}>"); - } -} diff --git a/crates/fabric-cli/src/presets.rs b/crates/fabric-cli/src/presets.rs new file mode 100644 index 000000000..4eabcfccf --- /dev/null +++ b/crates/fabric-cli/src/presets.rs @@ -0,0 +1,388 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Complete typed preset configurations maintained by the CLI. + +use std::collections::BTreeMap; + +use nemo_fabric_core::{ + ControlLocation, EnvironmentConfig, EnvironmentOwnership, FabricConfig, HarnessConfig, + MetadataConfig, ModelConfig, ResolutionStrategy, RuntimeConfig, +}; +use serde_json::{Map, Value, json}; + +use crate::assets::{EmbeddedFile, StagedAssets}; + +const SCRIPTED_DESCRIPTOR: &str = include_str!("../assets/adapters/scripted/fabric-adapter.json"); +const SCRIPTED_RUNNER: &str = include_str!("../assets/adapters/scripted/run.py"); +const HERMES_DESCRIPTOR: &str = include_str!("../assets/adapters/hermes/fabric-adapter.json"); +const CLAUDE_DESCRIPTOR: &str = include_str!("../assets/adapters/claude/fabric-adapter.json"); +const CODEX_DESCRIPTOR: &str = include_str!("../assets/adapters/codex/fabric-adapter.json"); +const DEEPAGENTS_DESCRIPTOR: &str = + include_str!("../assets/adapters/deepagents/fabric-adapter.json"); +const NVIDIA_API_CATALOG_BASE_URL: &str = "https://integrate.api.nvidia.com/v1"; + +const SCRIPTED_ASSETS: &[EmbeddedFile] = &[ + EmbeddedFile { + path: "adapters/scripted/fabric-adapter.json", + contents: SCRIPTED_DESCRIPTOR, + }, + EmbeddedFile { + path: "adapters/scripted/run.py", + contents: SCRIPTED_RUNNER, + }, +]; +const HERMES_ASSETS: &[EmbeddedFile] = &[EmbeddedFile { + path: "adapters/hermes/fabric-adapter.json", + contents: HERMES_DESCRIPTOR, +}]; +const CLAUDE_ASSETS: &[EmbeddedFile] = &[EmbeddedFile { + path: "adapters/claude/fabric-adapter.json", + contents: CLAUDE_DESCRIPTOR, +}]; +const CODEX_ASSETS: &[EmbeddedFile] = &[EmbeddedFile { + path: "adapters/codex/fabric-adapter.json", + contents: CODEX_DESCRIPTOR, +}]; +const DEEPAGENTS_ASSETS: &[EmbeddedFile] = &[EmbeddedFile { + path: "adapters/deepagents/fabric-adapter.json", + contents: DEEPAGENTS_DESCRIPTOR, +}]; + +/// Metadata and constructor for one complete CLI preset. +#[derive(Debug, Clone, Copy)] +pub struct Preset { + /// Stable command-line name. + pub name: &'static str, + /// Short experimentation-oriented description. + pub description: &'static str, + /// Environment variables required by the harness/model combination. + pub required_env: &'static [&'static str], + build: fn() -> FabricConfig, + assets: &'static [EmbeddedFile], +} + +impl Preset { + /// Construct a fresh complete typed config. + pub fn config(self) -> FabricConfig { + (self.build)() + } + + /// Stage the adapter assets required to plan or run this preset. + pub fn stage(self) -> std::io::Result { + Ok(SelectedPreset { + preset: self, + config: self.config(), + assets: StagedAssets::create(self.assets)?, + }) + } + + pub(crate) fn embedded_files(self) -> &'static [EmbeddedFile] { + self.assets + } +} + +/// Selected preset and the staged base directory that must outlive its run. +#[derive(Debug)] +pub struct SelectedPreset { + /// Preset metadata. + pub preset: Preset, + /// Complete typed configuration. + pub config: FabricConfig, + assets: StagedAssets, +} + +impl SelectedPreset { + /// Return the base directory for resolving this preset. + pub fn base_dir(&self) -> &std::path::Path { + self.assets.path() + } +} + +/// Return the maintained preset catalog. +pub fn all() -> &'static [Preset] { + &PRESETS +} + +/// Find a preset by its stable CLI name. +pub fn find(name: &str) -> Option { + PRESETS.iter().copied().find(|preset| preset.name == name) +} + +const PRESETS: [Preset; 5] = [ + Preset { + name: "scripted", + description: "Credential-free deterministic smoke preset.", + required_env: &[], + build: scripted, + assets: SCRIPTED_ASSETS, + }, + Preset { + name: "hermes", + description: "Hermes Agent with an NVIDIA-hosted model.", + required_env: &["NVIDIA_API_KEY"], + build: hermes, + assets: HERMES_ASSETS, + }, + Preset { + name: "claude", + description: "Claude Code with an NVIDIA-hosted Claude model.", + required_env: &["NVIDIA_API_KEY", "NVIDIA_FRONTIER_BASE_URL"], + build: claude, + assets: CLAUDE_ASSETS, + }, + Preset { + name: "codex", + description: "Codex with an NVIDIA-hosted OpenAI model.", + required_env: &["NVIDIA_API_KEY", "NVIDIA_FRONTIER_BASE_URL"], + build: codex, + assets: CODEX_ASSETS, + }, + Preset { + name: "deepagents", + description: "LangChain Deep Agents with an NVIDIA-hosted model.", + required_env: &["NVIDIA_API_KEY"], + build: deepagents, + assets: DEEPAGENTS_ASSETS, + }, +]; + +fn scripted() -> FabricConfig { + config( + "scripted-agent", + "Credential-free NeMo Fabric CLI smoke preset.", + "nvidia.fabric.scripted", + None, + Map::new(), + ) +} + +fn hermes() -> FabricConfig { + config( + "hermes-agent", + "NeMo Fabric Hermes CLI preset.", + "nvidia.fabric.hermes", + Some(model( + "nvidia", + "nvidia/nemotron-3-nano-30b-a3b", + Some("NVIDIA_API_KEY"), + Some(NVIDIA_API_CATALOG_BASE_URL), + )), + Map::new(), + ) +} + +fn claude() -> FabricConfig { + config( + "claude-agent", + "NeMo Fabric Claude CLI preset.", + "nvidia.fabric.claude", + Some(model( + "nvidia", + "aws/anthropic/claude-opus-4-5", + Some("NVIDIA_API_KEY"), + std::env::var("NVIDIA_FRONTIER_BASE_URL").ok().as_deref(), + )), + Map::from_iter([("permission_mode".to_string(), json!("dontAsk"))]), + ) +} + +fn codex() -> FabricConfig { + config( + "codex-agent", + "NeMo Fabric Codex CLI preset.", + "nvidia.fabric.codex", + Some(model( + "nvidia", + "azure/openai/gpt-5.4", + Some("NVIDIA_API_KEY"), + std::env::var("NVIDIA_FRONTIER_BASE_URL").ok().as_deref(), + )), + Map::from_iter([ + ("sandbox".to_string(), json!("workspace-write")), + ( + "config_overrides".to_string(), + json!({ + "features.apps": false, + "features.multi_agent": false, + "features.plugins": false, + "web_search": "disabled", + }), + ), + ]), + ) +} + +fn deepagents() -> FabricConfig { + config( + "deepagents-agent", + "NeMo Fabric Deep Agents CLI preset.", + "nvidia.fabric.langchain.deepagents", + Some(model( + "nvidia", + "nvidia/nemotron-3-nano-30b-a3b", + Some("NVIDIA_API_KEY"), + Some(NVIDIA_API_CATALOG_BASE_URL), + )), + Map::new(), + ) +} + +fn config( + name: &str, + description: &str, + adapter_id: &str, + default_model: Option, + settings: Map, +) -> FabricConfig { + FabricConfig { + schema_version: "fabric.agent/v1alpha1".to_string(), + metadata: MetadataConfig { + name: name.to_string(), + description: Some(description.to_string()), + extensions: BTreeMap::new(), + }, + harness: HarnessConfig { + adapter_id: adapter_id.to_string(), + resolution: Some(ResolutionStrategy::Preinstalled), + settings, + extensions: BTreeMap::new(), + }, + models: default_model + .map(|model| BTreeMap::from_iter([("default".to_string(), model)])) + .unwrap_or_default(), + runtime: RuntimeConfig { + input_schema: "text".to_string(), + output_schema: "message".to_string(), + artifacts: None, + extensions: BTreeMap::new(), + }, + environment: Some(EnvironmentConfig { + provider: "local".to_string(), + control_location: ControlLocation::InEnvControl, + ownership: EnvironmentOwnership::FabricOwned, + workspace: None, + artifacts: None, + connection: Map::new(), + metadata: Map::new(), + settings: Map::new(), + extensions: BTreeMap::new(), + }), + tools: None, + skills: None, + mcp: None, + telemetry: None, + relay: None, + extensions: BTreeMap::new(), + } +} + +fn model( + provider: &str, + name: &str, + api_key_env: Option<&str>, + base_url: Option<&str>, +) -> ModelConfig { + ModelConfig { + provider: provider.to_string(), + model: name.to_string(), + temperature: None, + api_key_env: api_key_env.map(str::to_string), + settings: base_url + .map(|value| Map::from_iter([("base_url".to_string(), json!(value))])) + .unwrap_or_default(), + extensions: BTreeMap::new(), + } +} + +#[cfg(test)] +mod tests { + use nemo_fabric_core::{ResolveContext, resolve_run_plan_from_config}; + + use super::*; + + #[test] + fn catalog_names_are_unique_and_configs_are_complete() { + let mut names = std::collections::BTreeSet::new(); + for preset in all() { + assert!(names.insert(preset.name)); + let config = preset.config(); + assert_eq!(config.metadata.name, format!("{}-agent", preset.name)); + assert!(!config.harness.adapter_id.is_empty()); + } + } + + #[test] + fn scripted_preset_plans_from_staged_assets() { + let selected = find("scripted") + .expect("scripted preset") + .stage() + .expect("stage preset"); + let plan = resolve_run_plan_from_config( + selected.config.clone(), + ResolveContext::new(selected.base_dir()), + ) + .expect("plan scripted preset"); + + assert_eq!(plan.agent_name, "scripted-agent"); + assert_eq!( + plan.adapter_descriptor + .expect("adapter") + .descriptor + .adapter_id, + "nvidia.fabric.scripted" + ); + } + + #[test] + fn adapter_presets_use_nvidia_credentials() { + for name in ["hermes", "claude", "codex", "deepagents"] { + let preset = find(name).expect("adapter preset"); + let config = preset.config(); + let model = config.models.get("default").expect("default model"); + + assert_eq!(model.provider, "nvidia"); + assert_eq!(model.api_key_env.as_deref(), Some("NVIDIA_API_KEY")); + assert!(preset.required_env.contains(&"NVIDIA_API_KEY")); + } + + for name in ["hermes", "deepagents"] { + let config = find(name).expect("catalog preset").config(); + let model = config.models.get("default").expect("default model"); + assert_eq!( + model.settings.get("base_url").and_then(Value::as_str), + Some(NVIDIA_API_CATALOG_BASE_URL) + ); + } + + for name in ["claude", "codex"] { + assert!( + find(name) + .expect("frontier preset") + .required_env + .contains(&"NVIDIA_FRONTIER_BASE_URL") + ); + } + } + + #[test] + fn packaged_descriptors_match_repository_adapters() { + let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")); + let repository_adapters = manifest_dir.join("../../adapters"); + if !repository_adapters.is_dir() { + return; + } + + for (name, embedded) in [ + ("hermes", HERMES_DESCRIPTOR), + ("claude", CLAUDE_DESCRIPTOR), + ("codex", CODEX_DESCRIPTOR), + ("deepagents", DEEPAGENTS_DESCRIPTOR), + ] { + let canonical = + std::fs::read_to_string(repository_adapters.join(name).join("fabric-adapter.json")) + .expect("read repository adapter descriptor"); + assert_eq!(embedded, canonical, "{name} descriptor drifted"); + } + } +} diff --git a/crates/fabric-cli/src/scaffold.rs b/crates/fabric-cli/src/scaffold.rs new file mode 100644 index 000000000..2d5cfbcef --- /dev/null +++ b/crates/fabric-cli/src/scaffold.rs @@ -0,0 +1,354 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Editable applications generated from the maintained example catalog. + +use std::fs; +use std::path::{Path, PathBuf}; + +use clap::ValueEnum; +use nemo_fabric_core::{FabricConfig, ModelConfig}; +use serde_json::Value; + +use crate::examples::Example; +use crate::presets; + +const PYTHON_MAIN: &str = include_str!("../templates/python/main.py.tmpl"); +const PYTHON_PROJECT: &str = include_str!("../templates/python/pyproject.toml.tmpl"); +const RUST_MAIN: &str = include_str!("../templates/rust/main.rs.tmpl"); +const RUST_PROJECT: &str = include_str!("../templates/rust/Cargo.toml.tmpl"); +const README: &str = include_str!("../templates/README.md.tmpl"); + +#[derive(Debug)] +struct ScaffoldFile { + path: String, + contents: String, +} + +/// Language API used by a generated editable application. +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub enum Language { + /// Generate a Python SDK application. + Python, + /// Generate a direct Rust core application. + Rust, +} + +impl Language { + /// Return the command-line spelling. + pub fn as_str(self) -> &'static str { + match self { + Self::Python => "python", + Self::Rust => "rust", + } + } +} + +/// Generate an ordinary editable application and return its destination. +pub fn init( + example: Example, + variant: Option<&str>, + language: Language, + destination: impl AsRef, +) -> Result { + let destination = destination.as_ref(); + if destination.exists() { + return Err(format!( + "destination already exists: {}", + destination.display() + )); + } + let variant = variant.unwrap_or(example.default_variant); + let preset = + presets::find(variant).ok_or_else(|| format!("unknown preset variant {variant:?}"))?; + let config = example.config(Some(variant))?; + let mut files = example + .embedded_files(preset) + .into_iter() + .map(|file| ScaffoldFile { + path: file.path.to_string(), + contents: file.contents.to_string(), + }) + .collect::>(); + files.extend(language_files(language, &config, example.name)); + files.push(ScaffoldFile { + path: "README.md".to_string(), + contents: README + .replace("{{EXAMPLE}}", example.name) + .replace("{{VARIANT}}", variant) + .replace("{{LANGUAGE}}", language.as_str()), + }); + write_files(destination, &files)?; + Ok(destination.to_path_buf()) +} + +fn language_files(language: Language, config: &FabricConfig, example: &str) -> Vec { + let (project_path, project, main_path, main) = match language { + Language::Python => ( + "pyproject.toml", + PYTHON_PROJECT.replace("{{PACKAGE}}", &package_name(example)), + "main.py", + render_python(config), + ), + Language::Rust => ( + "Cargo.toml", + RUST_PROJECT + .replace("{{PACKAGE}}", &package_name(example)) + .replace("{{NEMO_FABRIC_CORE_DEPENDENCY}}", &rust_core_dependency()), + "src/main.rs", + render_rust(config), + ), + }; + vec![ + ScaffoldFile { + path: project_path.to_string(), + contents: project, + }, + ScaffoldFile { + path: main_path.to_string(), + contents: main, + }, + ] +} + +fn rust_core_dependency() -> String { + rust_string(env!("CARGO_PKG_VERSION")) +} + +fn write_files(destination: &Path, files: &[ScaffoldFile]) -> Result<(), String> { + fs::create_dir(destination).map_err(|error| { + format!( + "failed to create destination {}: {error}", + destination.display() + ) + })?; + for file in files { + let path = destination.join(&file.path); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent) + .map_err(|error| format!("failed to create {}: {error}", parent.display()))?; + } + fs::write(&path, &file.contents) + .map_err(|error| format!("failed to write {}: {error}", path.display()))?; + } + Ok(()) +} + +fn render_python(config: &FabricConfig) -> String { + PYTHON_MAIN + .replace("{{AGENT_NAME}}", &python_string(&config.metadata.name)) + .replace( + "{{DESCRIPTION}}", + &python_string(config.metadata.description.as_deref().unwrap_or("")), + ) + .replace("{{ADAPTER_ID}}", &python_string(&config.harness.adapter_id)) + .replace( + "{{HARNESS_SETTINGS}}", + &python_value(&Value::Object(config.harness.settings.clone())), + ) + .replace("{{MODELS}}", &python_models(config.models.get("default"))) +} + +fn python_models(model: Option<&ModelConfig>) -> String { + let Some(model) = model else { + return "{}".to_string(); + }; + let temperature = model + .temperature + .map(|value| value.to_string()) + .unwrap_or_else(|| "None".to_string()); + format!( + "{{\"default\": ModelConfig(provider={}, model={}, temperature={temperature}, api_key_env={}, settings={})}}", + python_string(&model.provider), + python_string(&model.model), + model + .api_key_env + .as_deref() + .map(python_string) + .unwrap_or_else(|| "None".to_string()), + python_value(&Value::Object(model.settings.clone())), + ) +} + +fn python_value(value: &Value) -> String { + match value { + Value::Null => "None".to_string(), + Value::Bool(value) => if *value { "True" } else { "False" }.to_string(), + Value::Number(value) => value.to_string(), + Value::String(value) => python_string(value), + Value::Array(values) => format!( + "[{}]", + values + .iter() + .map(python_value) + .collect::>() + .join(", ") + ), + Value::Object(values) => format!( + "{{{}}}", + values + .iter() + .map(|(key, value)| format!("{}: {}", python_string(key), python_value(value))) + .collect::>() + .join(", ") + ), + } +} + +fn python_string(value: &str) -> String { + serde_json::to_string(value).expect("strings serialize") +} + +fn render_rust(config: &FabricConfig) -> String { + RUST_MAIN + .replace("{{AGENT_NAME}}", &rust_string(&config.metadata.name)) + .replace( + "{{DESCRIPTION}}", + &rust_string(config.metadata.description.as_deref().unwrap_or("")), + ) + .replace("{{ADAPTER_ID}}", &rust_string(&config.harness.adapter_id)) + .replace( + "{{HARNESS_SETTINGS}}", + &rust_settings(&config.harness.settings), + ) + .replace("{{MODELS}}", &rust_models(config.models.get("default"))) +} + +fn rust_settings(settings: &serde_json::Map) -> String { + if settings.is_empty() { + return "Map::new()".to_string(); + } + format!( + "Map::from_iter([{}])", + settings + .iter() + .map(|(key, value)| { + format!( + "({}.to_string(), serde_json::json!({}))", + rust_string(key), + value + ) + }) + .collect::>() + .join(", ") + ) +} + +fn rust_models(model: Option<&ModelConfig>) -> String { + let Some(model) = model else { + return "BTreeMap::new()".to_string(); + }; + let api_key = model + .api_key_env + .as_deref() + .map(|value| format!("Some({}.to_string())", rust_string(value))) + .unwrap_or_else(|| "None".to_string()); + let temperature = model + .temperature + .map(|value| format!("Some({value})")) + .unwrap_or_else(|| "None".to_string()); + format!( + "BTreeMap::from_iter([(\"default\".to_string(), nemo_fabric_core::ModelConfig {{ provider: {}.to_string(), model: {}.to_string(), temperature: {temperature}, api_key_env: {api_key}, settings: {}, extensions: BTreeMap::new() }})])", + rust_string(&model.provider), + rust_string(&model.model), + rust_settings(&model.settings), + ) +} + +fn rust_string(value: &str) -> String { + format!("{value:?}") +} + +fn package_name(example: &str) -> String { + example.replace('_', "-") +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::examples; + + fn destination(test: &str, language: Language) -> PathBuf { + std::env::temp_dir().join(format!( + "nemo-fabric-scaffold-test-{}-{test}-{}", + std::process::id(), + language.as_str() + )) + } + + #[test] + fn generates_both_languages_from_the_same_example_assets_and_config() { + let example = examples::find("code-review").expect("example"); + for language in [Language::Python, Language::Rust] { + let destination = destination("generate", language); + let _ = fs::remove_dir_all(&destination); + init(example, Some("hermes"), language, &destination).expect("generate scaffold"); + assert!(destination.join("repo/calculator.py").is_file()); + assert!(destination.join("skills/code-review.md").is_file()); + assert!( + destination + .join("adapters/hermes/fabric-adapter.json") + .is_file() + ); + assert_eq!( + fs::read_to_string(destination.join("repo/calculator.py")).expect("read workspace"), + crate::examples::CODE_REVIEW_WORKSPACE + ); + let launcher = match language { + Language::Python => destination.join("main.py"), + Language::Rust => destination.join("src/main.rs"), + }; + let source = fs::read_to_string(launcher).expect("read launcher"); + assert!(source.contains("nvidia.fabric.hermes")); + assert!(source.contains("nvidia/nemotron-3-nano-30b-a3b")); + assert!(source.contains("https://integrate.api.nvidia.com/v1")); + if language == Language::Rust { + let manifest = + fs::read_to_string(destination.join("Cargo.toml")).expect("read manifest"); + assert!( + manifest.contains(&format!("nemo-fabric-core = {}", rust_core_dependency())) + ); + assert!(!manifest.contains("path =")); + } + fs::remove_dir_all(destination).expect("remove scaffold"); + } + } + + #[test] + fn renderers_preserve_model_settings_and_temperature() { + let mut config = presets::find("hermes").expect("hermes preset").config(); + config + .models + .get_mut("default") + .expect("default model") + .temperature = Some(0.2); + + let python = render_python(&config); + assert!(python.contains("temperature=0.2")); + assert!( + python.contains("settings={\"base_url\": \"https://integrate.api.nvidia.com/v1\"}") + ); + + let rust = render_rust(&config); + assert!(rust.contains("temperature: Some(0.2)")); + assert!(rust.contains( + "(\"base_url\".to_string(), serde_json::json!(\"https://integrate.api.nvidia.com/v1\"))" + )); + } + + #[test] + fn refuses_to_overwrite_a_destination() { + let destination = destination("overwrite", Language::Python); + let _ = fs::remove_dir_all(&destination); + fs::create_dir(&destination).expect("create destination"); + let error = init( + examples::find("code-review").expect("example"), + None, + Language::Python, + &destination, + ) + .expect_err("must refuse overwrite"); + assert!(error.contains("already exists")); + fs::remove_dir_all(destination).expect("remove destination"); + } +} diff --git a/crates/fabric-cli/templates/README.md.tmpl b/crates/fabric-cli/templates/README.md.tmpl new file mode 100644 index 000000000..4918f2a84 --- /dev/null +++ b/crates/fabric-cli/templates/README.md.tmpl @@ -0,0 +1,11 @@ + + +# {{EXAMPLE}} + +Editable {{LANGUAGE}} application generated from the maintained `{{EXAMPLE}}` +example using its complete `{{VARIANT}}` variant. Edit the configuration in the +launcher and run this as its own application; it is not loaded by the central +`nemo-fabric` CLI. diff --git a/crates/fabric-cli/templates/python/main.py.tmpl b/crates/fabric-cli/templates/python/main.py.tmpl new file mode 100644 index 000000000..76c039d1b --- /dev/null +++ b/crates/fabric-cli/templates/python/main.py.tmpl @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Editable NeMo Fabric code-review application.""" + +import argparse +import asyncio +import json +from pathlib import Path + +from nemo_fabric import EnvironmentConfig +from nemo_fabric import Fabric +from nemo_fabric import FabricConfig +from nemo_fabric import HarnessConfig +from nemo_fabric import MetadataConfig +from nemo_fabric import ModelConfig +from nemo_fabric import RuntimeConfig + +BASE_DIR = Path(__file__).parent + + +def build_config() -> FabricConfig: + """Build the complete editable configuration.""" + + config = FabricConfig( + metadata=MetadataConfig(name={{AGENT_NAME}}, description={{DESCRIPTION}}), + harness=HarnessConfig( + adapter_id={{ADAPTER_ID}}, + resolution="preinstalled", + settings={{HARNESS_SETTINGS}}, + ), + models={{MODELS}}, + runtime=RuntimeConfig(input_schema="text", output_schema="message"), + environment=EnvironmentConfig(provider="local", workspace="repo"), + ) + config.add_skill_path("skills/code-review.md") + return config + + +async def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("input", nargs="?", default="Review the workspace") + args = parser.parse_args() + result = await Fabric().run(build_config(), base_dir=BASE_DIR, input=args.input) + print(json.dumps(result.to_mapping(), indent=2)) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/crates/fabric-cli/templates/python/pyproject.toml.tmpl b/crates/fabric-cli/templates/python/pyproject.toml.tmpl new file mode 100644 index 000000000..3030ead7e --- /dev/null +++ b/crates/fabric-cli/templates/python/pyproject.toml.tmpl @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +[build-system] +requires = ["setuptools>=77"] +build-backend = "setuptools.build_meta" + +[project] +name = "{{PACKAGE}}-python" +version = "0.1.0" +requires-python = ">=3.11" +dependencies = ["nemo-fabric-runtime"] + +[tool.setuptools] +py-modules = ["main"] diff --git a/crates/fabric-cli/templates/rust/Cargo.toml.tmpl b/crates/fabric-cli/templates/rust/Cargo.toml.tmpl new file mode 100644 index 000000000..ecd8ea477 --- /dev/null +++ b/crates/fabric-cli/templates/rust/Cargo.toml.tmpl @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +[package] +name = "{{PACKAGE}}-rust" +version = "0.1.0" +edition = "2024" + +[dependencies] +nemo-fabric-core = {{NEMO_FABRIC_CORE_DEPENDENCY}} +serde_json = "1" diff --git a/crates/fabric-cli/templates/rust/main.rs.tmpl b/crates/fabric-cli/templates/rust/main.rs.tmpl new file mode 100644 index 000000000..edbffadb4 --- /dev/null +++ b/crates/fabric-cli/templates/rust/main.rs.tmpl @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::BTreeMap; +use std::path::PathBuf; + +use nemo_fabric_core::{ + ControlLocation, EnvironmentConfig, EnvironmentOwnership, FabricConfig, HarnessConfig, + MetadataConfig, ResolutionStrategy, ResolveContext, RunRequest, RuntimeConfig, SkillConfig, + resolve_run_plan_from_config, run_plan, +}; +use serde_json::Map; + +fn build_config() -> FabricConfig { + FabricConfig { + schema_version: "fabric.agent/v1alpha1".to_string(), + metadata: MetadataConfig { + name: {{AGENT_NAME}}.to_string(), + description: Some({{DESCRIPTION}}.to_string()), + extensions: BTreeMap::new(), + }, + harness: HarnessConfig { + adapter_id: {{ADAPTER_ID}}.to_string(), + resolution: Some(ResolutionStrategy::Preinstalled), + settings: {{HARNESS_SETTINGS}}, + extensions: BTreeMap::new(), + }, + models: {{MODELS}}, + runtime: RuntimeConfig { + input_schema: "text".to_string(), + output_schema: "message".to_string(), + artifacts: None, + extensions: BTreeMap::new(), + }, + environment: Some(EnvironmentConfig { + provider: "local".to_string(), + control_location: ControlLocation::InEnvControl, + ownership: EnvironmentOwnership::FabricOwned, + workspace: Some(PathBuf::from("repo")), + artifacts: None, + connection: Map::new(), + metadata: Map::new(), + settings: Map::new(), + extensions: BTreeMap::new(), + }), + skills: Some(SkillConfig { + paths: vec![PathBuf::from("skills/code-review.md")], + extensions: BTreeMap::new(), + }), + tools: None, + mcp: None, + telemetry: None, + relay: None, + extensions: BTreeMap::new(), + } +} + +fn main() -> Result<(), Box> { + let base_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let input = std::env::args() + .nth(1) + .unwrap_or_else(|| "Review the workspace".to_string()); + let plan = resolve_run_plan_from_config(build_config(), ResolveContext::new(base_dir))?; + let result = run_plan(&plan, RunRequest::text(input))?; + println!("{}", serde_json::to_string_pretty(&result)?); + Ok(()) +} diff --git a/crates/fabric-core/Cargo.toml b/crates/fabric-core/Cargo.toml index ede4e25b6..41cc29ae6 100644 --- a/crates/fabric-core/Cargo.toml +++ b/crates/fabric-core/Cargo.toml @@ -17,5 +17,4 @@ workspace = true schemars.workspace = true serde.workspace = true serde_json.workspace = true -serde_yaml.workspace = true thiserror.workspace = true diff --git a/crates/fabric-core/README.md b/crates/fabric-core/README.md index e8b3c3b28..d369b9bf4 100644 --- a/crates/fabric-core/README.md +++ b/crates/fabric-core/README.md @@ -14,9 +14,9 @@ Add the crate to a Rust project: cargo add nemo-fabric-core ``` -This crate provides typed agent configuration, profile resolution, validation, -run planning, runtime lifecycle operations, normalized results and artifact -manifests, telemetry references, diagnostics, and JSON Schema generation. +This crate provides typed agent configuration, validation, run planning, +runtime lifecycle operations, normalized results and artifact manifests, +telemetry references, diagnostics, and JSON Schema generation. For architecture, configuration concepts, adapters, and examples, refer to the [NVIDIA NeMo Fabric repository](https://github.com/NVIDIA/nemo-fabric). diff --git a/crates/fabric-core/examples/generate-schemas.rs b/crates/fabric-core/examples/generate-schemas.rs new file mode 100644 index 000000000..ec18b8ac5 --- /dev/null +++ b/crates/fabric-core/examples/generate-schemas.rs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Regenerate committed NeMo Fabric JSON Schema snapshots. + +use std::path::PathBuf; + +fn main() { + let output = std::env::args_os() + .nth(1) + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from("schemas")); + nemo_fabric_core::write_schema_snapshots(output).expect("write schema snapshots"); +} diff --git a/crates/fabric-core/src/config.rs b/crates/fabric-core/src/config.rs index 37d83d06c..49b5592da 100644 --- a/crates/fabric-core/src/config.rs +++ b/crates/fabric-core/src/config.rs @@ -3,36 +3,19 @@ //! Fabric config models and loading helpers. -use std::borrow::Cow; use std::collections::{BTreeMap, BTreeSet}; use std::fs; use std::path::{Path, PathBuf}; -use schemars::{JsonSchema, Schema, SchemaGenerator}; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::error::{FabricError, Result}; -const AGENT_YAML: &str = "agent.yaml"; /// Adapter descriptor contract version supported by this core. pub const ADAPTER_CONTRACT_VERSION: &str = "fabric.adapter/v1alpha1"; -/// A loaded Fabric document with resolved source path and agent root. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum FabricDocument { - /// Unified Fabric agent config. - FabricConfig { - /// Path to the config file. - path: PathBuf, - /// Root used for resolving relative paths. - root: PathBuf, - /// Parsed config. - config: FabricConfig, - }, -} - /// Versioned Fabric agent config. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct FabricConfig { @@ -65,31 +48,11 @@ pub struct FabricConfig { /// First-class NeMo Relay integration configuration. #[serde(default, skip_serializing_if = "Option::is_none")] pub relay: Option, - /// Optional profile discovery config. - #[serde(default, skip_serializing_if = "ProfileRegistryConfig::is_empty")] - pub profiles: ProfileRegistryConfig, /// Additive fields not yet recognized by this core version. #[serde(default, flatten)] pub extensions: BTreeMap, } -/// Profile discovery config for curated package profiles. -#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)] -pub struct ProfileRegistryConfig { - /// Directories searched when a caller selects a profile by name. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub directories: Vec, - /// Additive profile-discovery fields. - #[serde(default, flatten)] - pub extensions: BTreeMap, -} - -impl ProfileRegistryConfig { - fn is_empty(&self) -> bool { - self.directories.is_empty() && self.extensions.is_empty() - } -} - /// Harness-neutral tool capability configuration. #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct ToolsConfig { @@ -201,10 +164,10 @@ struct AdapterRegistry { } impl AdapterRegistry { - fn from_config(_config: &FabricConfig, config_root: &Path) -> Result { + fn from_config(_config: &FabricConfig, base_dir: &Path) -> Result { let mut registry = Self::default(); registry.register_repository_directory(&repository_adapter_dir())?; - registry.register_local_directory(&config_root.join("adapters"))?; + registry.register_local_directory(&base_dir.join("adapters"))?; Ok(registry) } @@ -394,94 +357,18 @@ pub struct AdapterTelemetryProviderSupport { pub extensions: BTreeMap, } -/// Profile config applied on top of a Fabric config. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] -pub struct ProfileConfig { - /// Optional profile schema version. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub schema_version: Option, - /// Optional profile name used for directory discovery. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub name: Option, - /// Optional profile description. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub description: Option, - /// Raw config fields recursively merged over the base config. - #[serde(default, flatten)] - pub overlay: BTreeMap, -} - -#[derive(JsonSchema)] -#[allow(dead_code)] -struct ProfileConfigSchema { - /// Optional profile schema version. - schema_version: Option, - /// Optional profile name used for directory discovery. - name: Option, - /// Optional profile description. - description: Option, - /// Partial harness overlay. - harness: Option>, - /// Partial model overlays by alias. - models: Option>, - /// Partial runtime overlay. - runtime: Option>, - /// Partial environment overlay. - environment: Option>, - /// Tool capability overlay. - tools: Option, - /// Partial skill overlay. - skills: Option>, - /// Partial MCP overlay. - mcp: Option>, - /// Partial telemetry overlay. - telemetry: Option>, - /// Partial Relay integration overlay. - relay: Option>, - /// Additive config overlays. - #[serde(flatten)] - extensions: BTreeMap, -} - -impl JsonSchema for ProfileConfig { - fn schema_name() -> Cow<'static, str> { - "ProfileConfig".into() - } - - fn json_schema(generator: &mut SchemaGenerator) -> Schema { - ProfileConfigSchema::json_schema(generator) - } -} - /// Source context used when resolving an in-memory Fabric config. #[derive(Debug, Clone, PartialEq)] pub struct ResolveContext { - /// Root used to resolve agent package paths. - pub agent_root: PathBuf, - /// Path recorded as config provenance in the run plan. - pub config_path: PathBuf, - /// Root used to resolve config-local paths. - pub config_root: PathBuf, + /// Base directory used to resolve relative Fabric paths. + pub base_dir: PathBuf, } impl ResolveContext { - /// Build a context for an agent package root. - pub fn from_agent_root(root: impl Into) -> Self { - let root = root.into(); + /// Build a context with an explicit base directory. + pub fn new(base_dir: impl Into) -> Self { Self { - agent_root: root.clone(), - config_path: root.join(AGENT_YAML), - config_root: root, - } - } - - /// Build a context for a config file and its config root. - pub fn from_config_path(path: impl Into, root: impl Into) -> Self { - let root = root.into(); - Self { - agent_root: root.clone(), - config_path: path.into(), - config_root: root, + base_dir: base_dir.into(), } } } @@ -588,7 +475,7 @@ fn default_environment_ownership() -> EnvironmentOwnership { /// Skill capability configuration. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Default)] pub struct SkillConfig { - /// Skill paths relative to the agent root. + /// Skill paths resolved relative to the config base directory. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub paths: Vec, /// Additive skill fields. @@ -1077,29 +964,6 @@ fn default_relay_unsupported_value_behavior() -> RelayUnsupportedBehavior { RelayUnsupportedBehavior::Error } -/// Load a Fabric document from an agent directory or single agent config. -pub fn load_fabric_document(path: impl AsRef) -> Result { - let path = path.as_ref(); - if !path.exists() { - return Err(FabricError::PathNotFound(path.to_path_buf())); - } - if path.is_dir() { - return load_directory(path); - } - load_file(path) -} - -/// Validate an agent directory or config, including discoverable profile YAMLs. -pub fn validate_agent_directory(path: impl AsRef) -> Result<()> { - match load_fabric_document(path)? { - FabricDocument::FabricConfig { root, config, .. } => { - discover_profiles(&config, &root)?; - } - } - - Ok(()) -} - /// Load an adapter descriptor from JSON package metadata. pub fn load_adapter_descriptor(path: impl AsRef) -> Result { let path = path.as_ref(); @@ -1108,127 +972,33 @@ pub fn load_adapter_descriptor(path: impl AsRef) -> Result, - profile: Option<&str>, -) -> Result { - let profiles: Vec = profile.into_iter().map(str::to_string).collect(); - resolve_effective_config_with_profiles(path, &profiles) -} - -/// Resolve an agent directory or single agent config with ordered profiles into -/// merged effective config. -pub fn resolve_effective_config_with_profiles( - path: impl AsRef, - profiles: &[String], -) -> Result { - match load_fabric_document(path)? { - FabricDocument::FabricConfig { path, root, config } => { - let agent_name = config.metadata.name.clone(); - let (profile_configs, selected_profiles) = - load_profile_configs(&agent_name, &config, &root, profiles)?; - resolve_effective_config_from_config_with_profile_names( - config, - &profile_configs, - selected_profiles, - ResolveContext::from_config_path(path, root), - ) - } - } -} - -/// Resolve typed config/profile overlays into merged effective config. -pub fn resolve_effective_config_from_config( - config: FabricConfig, - profiles: &[ProfileConfig], - context: ResolveContext, -) -> Result { - let selected_profiles = profiles - .iter() - .enumerate() - .map(|(index, profile)| { - profile - .name - .clone() - .unwrap_or_else(|| format!("profile_{}", index + 1)) - }) - .collect(); - resolve_effective_config_from_config_with_profile_names( - config, - profiles, - selected_profiles, - context, - ) -} - -fn load_directory(path: &Path) -> Result { - let agent = path.join(AGENT_YAML); - if agent.exists() { - return load_fabric_config(&agent); - } - Err(FabricError::MissingEntrypoint(path.to_path_buf())) -} - -fn load_file(path: &Path) -> Result { - match path.file_name().and_then(|name| name.to_str()) { - Some(AGENT_YAML) => load_fabric_config(path), - Some(name) if name.ends_with(".yaml") || name.ends_with(".yml") => load_fabric_config(path), - _ => Err(FabricError::UnsupportedExtension(path.to_path_buf())), +fn validate_config(config: &FabricConfig) -> Result<()> { + if config.harness.adapter_id.trim().is_empty() { + return Err(FabricError::UnknownAdapter { + adapter_id: config.harness.adapter_id.clone(), + available: Vec::new(), + }); } + Ok(()) } -/// Resolve an agent directory or single agent config into a runnable plan. -pub fn resolve_run_plan(path: impl AsRef, profile: Option<&str>) -> Result { - let profiles: Vec = profile.into_iter().map(str::to_string).collect(); - resolve_run_plan_with_profiles(path, &profiles) -} - -/// Resolve an agent directory or single agent config with ordered profile application. -pub fn resolve_run_plan_with_profiles( - path: impl AsRef, - profiles: &[String], -) -> Result { - resolve_run_plan_from_effective_config(resolve_effective_config_with_profiles(path, profiles)?) -} - -/// Resolve a typed Fabric config and typed profile overlays into a runnable plan. +/// Resolve a typed Fabric config into a runnable plan. /// -/// This is the SDK-facing entrypoint. File and YAML loading stays outside this -/// function; callers provide already-typed configs and the path context used for -/// resolving relative paths. +/// Callers provide an already-composed typed config and the explicit base +/// directory used for resolving relative paths. pub fn resolve_run_plan_from_config( config: FabricConfig, - profiles: &[ProfileConfig], context: ResolveContext, ) -> Result { - resolve_run_plan_from_effective_config(resolve_effective_config_from_config( - config, profiles, context, - )?) -} - -fn load_fabric_config(path: &Path) -> Result { - let config = read_yaml::(path)?; - let root = parent_or_current(path); - Ok(FabricDocument::FabricConfig { - path: path.to_path_buf(), - root, - config, - }) -} - -fn read_yaml(path: &Path) -> Result -where - T: for<'de> Deserialize<'de>, -{ - let raw = std::fs::read_to_string(path).map_err(|source| FabricError::Read { - path: path.to_path_buf(), - source, - })?; - serde_yaml::from_str(&raw).map_err(|source| FabricError::ParseYaml { - path: path.to_path_buf(), - source, - }) + validate_config(&config)?; + let supplied_base_dir = context.base_dir; + let base_dir = std::path::absolute(&supplied_base_dir) + .map(normalize_path) + .map_err(|source| FabricError::ResolveBaseDirectory { + path: supplied_base_dir, + source, + })?; + resolve_run_plan(config, base_dir) } fn read_json(path: &Path) -> Result @@ -1245,201 +1015,36 @@ where }) } -fn parent_or_current(path: &Path) -> PathBuf { - path.parent() - .map(Path::to_path_buf) - .unwrap_or_else(|| PathBuf::from(".")) -} - -fn load_profile_configs( - agent_name: &str, - config: &FabricConfig, - config_root: &Path, - profiles: &[String], -) -> Result<(Vec, Vec)> { - if profiles.is_empty() { - return Ok((Vec::new(), Vec::new())); - } - let discovered = discover_profiles(&config, config_root)?; - let mut profile_configs = Vec::new(); - let mut selected_profiles = Vec::new(); - for profile_name in profiles { - let profile_path = - if let Some(path) = resolve_profile_file_reference(config_root, &profile_name) { - path - } else if let Some(path) = discovered.get(profile_name.as_str()) { - path.clone() - } else { - return Err(FabricError::UnknownProfile { - profile: profile_name.clone(), - agent: agent_name.to_string(), - available: discovered.keys().cloned().collect(), - }); - }; - let profile_config = read_yaml::(&profile_path)?; - profile_configs.push(profile_config); - selected_profiles.push(profile_name.clone()); - } - Ok((profile_configs, selected_profiles)) -} - -fn resolve_effective_config_from_config_with_profile_names( - config: FabricConfig, - profiles: &[ProfileConfig], - selected_profiles: Vec, - context: ResolveContext, -) -> Result { - let mut effective = config; - for profile in profiles { - apply_profile_config(&mut effective, profile)?; - } - let config = into_effective_config(effective); - Ok(EffectiveConfig { - agent_name: config.metadata.name.clone(), - profiles: selected_profiles, - agent_root: context.agent_root, - config_path: context.config_path, - config_root: context.config_root, - config, - }) -} - -/// Resolve execution planning metadata from merged effective config. -pub fn resolve_run_plan_from_effective_config( - effective_config: EffectiveConfig, -) -> Result { - let config = effective_config.config.clone(); - let config_root = effective_config.config_root.clone(); - let adapter_descriptor = resolve_adapter_descriptor(&config, &config_root)?; +fn resolve_run_plan(config: FabricConfig, base_dir: PathBuf) -> Result { + let adapter_descriptor = resolve_adapter_descriptor(&config, &base_dir)?; let descriptor = adapter_descriptor .as_ref() .map(|adapter| &adapter.descriptor); let resolution = resolve_resolution(&config, descriptor)?; - let environment_plan = resolve_environment_plan(&config, &config_root); + let environment_plan = resolve_environment_plan(&config, &base_dir); validate_control_location(descriptor, environment_plan.as_ref())?; - let capability_plan = - resolve_capability_plan(&config, &config_root, adapter_descriptor.as_ref()); + let capability_plan = resolve_capability_plan(&config, &base_dir, adapter_descriptor.as_ref()); let capabilities = resolve_runtime_capabilities(&config, descriptor); let telemetry_plan = resolve_telemetry_plan(&config, descriptor)?; Ok(RunPlan { - agent_name: effective_config.agent_name.clone(), - profiles: effective_config.profiles.clone(), + agent_name: config.metadata.name.clone(), + base_dir, + config, adapter_descriptor, resolution, environment_plan, capability_plan, capabilities, telemetry_plan, - agent_root: effective_config.agent_root.clone(), - config_path: effective_config.config_path.clone(), - config_root, - config, - effective_config, }) } -fn into_effective_config(mut config: FabricConfig) -> FabricConfig { - config.profiles = ProfileRegistryConfig::default(); - config -} - -fn resolve_profile_file_reference(config_root: &Path, profile: &str) -> Option { - let path = Path::new(profile); - let cwd_relative = normalize_path(path.to_path_buf()); - if cwd_relative.is_file() { - return Some(cwd_relative); - } - let config_relative = resolve_path(config_root, path); - if config_relative.is_file() { - return Some(config_relative); - } - None -} - -fn discover_profiles( - config: &FabricConfig, - config_root: &Path, -) -> Result> { - let mut profiles: BTreeMap = BTreeMap::new(); - for directory in &config.profiles.directories { - let directory = resolve_path(config_root, directory); - if !directory.exists() { - println!( - "warning: profile directory does not exist: {}", - directory.display() - ); - continue; - } - let entries = std::fs::read_dir(&directory).map_err(|source| FabricError::Read { - path: directory.clone(), - source, - })?; - for entry in entries { - let path = entry - .map_err(|source| FabricError::Read { - path: directory.clone(), - source, - })? - .path(); - if !is_yaml_file(&path) { - continue; - } - let profile_config = read_yaml::(&path)?; - let Some(name) = profile_config.name.clone().or_else(|| { - path.file_stem() - .and_then(|stem| stem.to_str()) - .map(str::to_string) - }) else { - continue; - }; - let profile_path = normalize_path(path); - if profiles.contains_key(&name) { - return Err(FabricError::ProfileError { - path: profile_path, - message: format!("duplicate profile `{name}`"), - }); - } - profiles.insert(name, profile_path); - } - } - Ok(profiles) -} - -fn is_yaml_file(path: &Path) -> bool { - path.extension() - .and_then(|extension| extension.to_str()) - .is_some_and(|extension| matches!(extension, "yaml" | "yml")) -} - -fn apply_profile_config(config: &mut FabricConfig, profile: &ProfileConfig) -> Result<()> { - let mut merged = serde_json::to_value(&*config).map_err(FabricError::SerializeJson)?; - let overlay = Value::Object(profile.overlay.clone().into_iter().collect()); - merge_json(&mut merged, overlay); - *config = serde_json::from_value(merged).map_err(FabricError::SerializeJson)?; - Ok(()) -} - -fn merge_json(base: &mut Value, overlay: Value) { - match (base, overlay) { - (Value::Object(base), Value::Object(overlay)) => { - for (key, value) in overlay { - if let Some(current) = base.get_mut(&key) { - merge_json(current, value); - } else { - base.insert(key, value); - } - } - } - (base, overlay) => *base = overlay, - } -} - fn resolve_adapter_descriptor( config: &FabricConfig, - config_root: &Path, + base_dir: &Path, ) -> Result> { let adapter_id = &config.harness.adapter_id; - let registry = AdapterRegistry::from_config(config, config_root)?; + let registry = AdapterRegistry::from_config(config, base_dir)?; let Some(entry) = registry.get(adapter_id) else { return Err(FabricError::UnknownAdapter { adapter_id: adapter_id.clone(), @@ -1535,7 +1140,7 @@ fn resolve_resolution( Ok(config.harness.resolution) } -fn resolve_environment_plan(config: &FabricConfig, config_root: &Path) -> Option { +fn resolve_environment_plan(config: &FabricConfig, base_dir: &Path) -> Option { let environment = config.environment.as_ref()?; Some(EnvironmentPlan { provider: environment.provider.clone(), @@ -1544,12 +1149,12 @@ fn resolve_environment_plan(config: &FabricConfig, config_root: &Path) -> Option workspace: environment .workspace .as_ref() - .map(|workspace| resolve_path(config_root, workspace)), + .map(|workspace| resolve_path(base_dir, workspace)), artifacts: environment .artifacts .as_ref() .or(config.runtime.artifacts.as_ref()) - .map(|artifacts| resolve_path(config_root, artifacts)), + .map(|artifacts| resolve_path(base_dir, artifacts)), connection: environment.connection.clone(), metadata: environment.metadata.clone(), settings: environment.settings.clone(), @@ -1558,7 +1163,7 @@ fn resolve_environment_plan(config: &FabricConfig, config_root: &Path) -> Option fn resolve_capability_plan( config: &FabricConfig, - config_root: &Path, + base_dir: &Path, adapter_descriptor: Option<&ResolvedAdapterDescriptor>, ) -> CapabilityPlan { let accepts = |area: &str| { @@ -1580,7 +1185,7 @@ fn resolve_capability_plan( skills .paths .iter() - .map(|path| resolve_path(config_root, path)) + .map(|path| resolve_path(base_dir, path)) .collect() }) .unwrap_or_default(); @@ -1815,32 +1420,15 @@ fn normalize_path(path: PathBuf) -> PathBuf { .collect() } -/// Merged Fabric config after applying selected profiles. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] -pub struct EffectiveConfig { - /// Stable agent name. - pub agent_name: String, - /// Ordered selected profiles. - pub profiles: Vec, - /// Root used to resolve agent package paths. - pub agent_root: PathBuf, - /// Resolved Fabric config path. - pub config_path: PathBuf, - /// Root used to resolve config-local paths. - pub config_root: PathBuf, - /// Merged Fabric config with authoring-time profile discovery removed. - pub config: FabricConfig, -} - /// Resolved Fabric run plan. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct RunPlan { - /// Merged config and provenance used as the base for this plan. - pub effective_config: EffectiveConfig, /// Stable agent name. pub agent_name: String, - /// Ordered selected profiles. - pub profiles: Vec, + /// Base directory used to resolve relative Fabric paths. + pub base_dir: PathBuf, + /// Complete typed Fabric config. + pub config: FabricConfig, /// Adapter descriptor resolved for this plan, when configured. #[serde(default, skip_serializing_if = "Option::is_none")] pub adapter_descriptor: Option, @@ -1858,14 +1446,6 @@ pub struct RunPlan { /// Resolved telemetry pass-through plan. #[serde(default, skip_serializing_if = "Option::is_none")] pub telemetry_plan: Option, - /// Root used to resolve agent package paths. - pub agent_root: PathBuf, - /// Resolved Fabric config path. - pub config_path: PathBuf, - /// Root used to resolve config-local paths. - pub config_root: PathBuf, - /// Resolved Fabric profile config. - pub config: FabricConfig, } /// Lifecycle behavior implemented by a resolved runtime path. @@ -1938,7 +1518,7 @@ pub struct CapabilityPlan { /// Capabilities that are configured but not executable by this Fabric build. #[serde(default)] pub unsupported: CapabilityTargetPlan, - /// Routing decisions made while resolving the effective config. + /// Routing decisions made while planning the configured capabilities. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub routes: Vec, } @@ -2041,976 +1621,95 @@ pub struct TelemetryPlan { mod tests { use super::*; - fn file_config_agent_dir() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../tests/fixtures/file-config-agent") - } - - fn example_adapter_descriptor_path() -> PathBuf { - repository_adapter_dir().join("hermes/fabric-adapter.json") - } - - #[test] - fn typed_profiles_merge_partial_objects_and_preserve_extensions() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.hermes - settings: - workspace: ./workspace -runtime: - input_schema: chat - output_schema: message -tools: - blocked: [base] - future: - value: true -future_top_level: - base: true - nested: - first: 1 -"#, - ) - .expect("base config"); - let profile: ProfileConfig = serde_yaml::from_str( - r#" -schema_version: fabric.profile/v1alpha1 -name: overlay -harness: - settings: - timeout_seconds: 30 -runtime: - input_schema: prompt -tools: - blocked: [profile] - future: null -future_top_level: - profile: true - nested: - second: 2 -"#, - ) - .expect("partial profile"); - - let effective = resolve_effective_config_from_config( - config, - &[profile], - ResolveContext::from_agent_root("."), - ) - .expect("effective config"); - let value = serde_json::to_value(&effective.config).expect("config json"); - - assert_eq!(effective.profiles, ["overlay"]); - assert_eq!(value["runtime"]["input_schema"], "prompt"); - assert_eq!(value["harness"]["settings"]["workspace"], "./workspace"); - assert_eq!(value["harness"]["settings"]["timeout_seconds"], 30); - assert_eq!(value["tools"]["blocked"], serde_json::json!(["profile"])); - assert!(value["tools"]["future"].is_null()); - assert_eq!(value["future_top_level"]["base"], true); - assert_eq!(value["future_top_level"]["profile"], true); - assert_eq!(value["future_top_level"]["nested"]["first"], 1); - assert_eq!(value["future_top_level"]["nested"]["second"], 2); - } - - #[test] - fn runtime_uses_stable_defaults_for_omitted_optional_fields() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.hermes -runtime: -"#, - ) - .expect("minimal config"); - - assert_eq!(config.runtime.input_schema, "text"); - assert_eq!(config.runtime.output_schema, "text"); - } - - #[test] - fn relay_telemetry_provider_is_enabled_by_presence() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.hermes -runtime: -telemetry: - providers: - relay: {} -"#, - ) - .expect("config with relay telemetry provider"); - - let telemetry = config.telemetry.as_ref().expect("telemetry config"); - let plan = resolve_telemetry_plan(&config, None) - .expect("resolve telemetry plan") - .expect("telemetry plan"); - - assert!(telemetry.providers.contains_key(&TelemetryProvider::Relay)); - assert_eq!(plan.providers, vec![TelemetryProvider::Relay]); - assert!(plan.relay_enabled); - assert_eq!(plan.relay_config, None); - } - - #[test] - fn native_telemetry_provider_skips_relay_config() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.hermes -runtime: -telemetry: - providers: - native: - config: - exporter: test -relay: - project: relay-project - output_dir: ./relay-output -"#, - ) - .expect("config with native telemetry provider"); - - let plan = resolve_telemetry_plan(&config, None) - .expect("resolve telemetry plan") - .expect("telemetry plan"); - - assert_eq!(plan.providers, vec![TelemetryProvider::Native]); - assert!(!plan.relay_enabled); - assert_eq!(plan.relay_project, None); - assert_eq!(plan.relay_output_dir, None); - assert_eq!(plan.relay_config, None); - assert_eq!( - plan.native_config, - Some(serde_json::json!({"exporter": "test"})) - ); - } - - #[test] - fn relay_telemetry_config_generates_relay_plugin_config() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.hermes -runtime: -telemetry: - providers: - relay: {} -relay: - project: typed-project - output_dir: ./typed-relay - observability: - atof: - enabled: true - output_directory: ./typed-relay - filename: events.atof.jsonl - mode: overwrite - atif: - enabled: true - output_directory: ./typed-relay - filename_template: trajectory-{session_id}.atif.json - agent_name: code-review-agent - opentelemetry: - enabled: true - endpoint: http://localhost:4318/v1/traces - components: - - kind: switchyard - enabled: true - config: - route: canary - policy: - unknown_component: error -"#, - ) - .expect("config with typed relay telemetry"); - - let plan = resolve_telemetry_plan(&config, None) - .expect("resolve telemetry plan") - .expect("telemetry plan"); - let relay_config = plan.relay_config.expect("relay plugin config"); - - assert_eq!(plan.relay_project.as_deref(), Some("typed-project")); - assert_eq!(plan.relay_output_dir, Some(PathBuf::from("./typed-relay"))); - assert_eq!(relay_config["version"], serde_json::json!(1)); - assert_eq!( - relay_config["components"][0]["kind"], - serde_json::json!("observability") - ); - assert_eq!( - relay_config["components"][0]["config"]["atof"]["mode"], - serde_json::json!("overwrite") - ); - assert_eq!( - relay_config["components"][0]["config"]["atif"]["agent_name"], - serde_json::json!("code-review-agent") - ); - assert_eq!( - relay_config["components"][0]["config"]["opentelemetry"]["endpoint"], - serde_json::json!("http://localhost:4318/v1/traces") - ); - assert_eq!( - relay_config["components"][1], - serde_json::json!({ - "kind": "switchyard", - "enabled": true, - "config": {"route": "canary"} - }) - ); - assert_eq!( - relay_config["policy"]["unknown_component"], - serde_json::json!("error") - ); - } - - #[test] - fn telemetry_provider_rejects_unknown_provider_keys() { - let result = serde_yaml::from_str::( - r#" -providers: - unsupported: {} -"#, - ); - - assert!(result.is_err()); - } - - #[test] - fn telemetry_plan_rejects_provider_not_declared_by_adapter() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.claude -runtime: -telemetry: - providers: - relay: {} -"#, - ) - .expect("config with relay telemetry provider"); - let descriptor: AdapterDescriptor = serde_json::from_value(serde_json::json!({ - "contract_version": ADAPTER_CONTRACT_VERSION, - "adapter_id": "nvidia.fabric.claude", - "harness": "claude", - "adapter_kind": "python" + fn typed_config(adapter_id: &str) -> FabricConfig { + serde_json::from_value(serde_json::json!({ + "schema_version": "fabric.agent/v1alpha1", + "metadata": {"name": "typed-agent"}, + "harness": { + "adapter_id": adapter_id, + "resolution": "preinstalled" + }, + "runtime": {}, + "environment": { + "provider": "local", + "workspace": "workspace" + }, + "skills": {"paths": ["skills/review"]} })) - .expect("adapter descriptor"); - - let error = resolve_telemetry_plan(&config, Some(&descriptor)) - .expect_err("unsupported relay provider"); - - assert!(matches!( - error, - FabricError::AdapterDescriptorUnsupported { - adapter_id, - field: "telemetry.providers", - value, - } if adapter_id == "nvidia.fabric.claude" && value == "relay" - )); + .expect("typed config") } - #[test] - fn telemetry_plan_uses_outputs_for_selected_adapter_providers() { - let config: FabricConfig = serde_yaml::from_str( - r#" -schema_version: fabric.agent/v1alpha1 -metadata: - name: demo -harness: - adapter_id: nvidia.fabric.codex -runtime: -telemetry: - providers: - relay: {} - native: {} -"#, - ) - .expect("config with relay and native telemetry providers"); - let descriptor: AdapterDescriptor = serde_json::from_value(serde_json::json!({ - "contract_version": ADAPTER_CONTRACT_VERSION, - "adapter_id": "nvidia.fabric.codex", - "harness": "codex", - "adapter_kind": "python", - "telemetry": { - "providers": { - "relay": { - "outputs": ["atif", "otel"], - "integration_modes": ["hooks", "gateway"] - }, - "native": { - "outputs": ["otel"] - } - } - } - })) - .expect("adapter descriptor"); - - let plan = resolve_telemetry_plan(&config, Some(&descriptor)) - .expect("resolve telemetry plan") - .expect("telemetry plan"); - - assert_eq!( - plan.providers, - vec![TelemetryProvider::Relay, TelemetryProvider::Native] - ); - assert_eq!(plan.adapter_outputs, vec!["atif", "otel"]); + fn repository_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..") } #[test] - fn loads_adapter_descriptor() { - let descriptor = - load_adapter_descriptor(example_adapter_descriptor_path()).expect("adapter descriptor"); - - assert_eq!(descriptor.contract_version, ADAPTER_CONTRACT_VERSION); - assert_eq!(descriptor.adapter_id, "nvidia.fabric.hermes"); - assert_eq!(descriptor.harness, "hermes"); - assert_eq!(descriptor.adapter_kind, AdapterKind::Python); - let descriptor_json = serde_json::to_value(&descriptor).expect("descriptor json"); - assert_eq!( - descriptor_json.get("harness").and_then(Value::as_str), - Some("hermes") - ); - assert!(descriptor_json.get("harness_type").is_none()); - assert_eq!( - descriptor.runner.get("module").and_then(Value::as_str), - Some("nemo_fabric_adapters.hermes.adapter") - ); - assert_eq!( - descriptor.runner.get("callable").and_then(Value::as_str), - Some("run") - ); - assert!(descriptor.config.accepts.contains(&"telemetry".to_string())); - let relay = descriptor - .telemetry - .providers - .get(&TelemetryProvider::Relay) - .expect("relay telemetry support"); - assert!(relay.outputs.contains(&"atif".to_string())); - } - - #[test] - fn resolves_base_config_from_agent_directory() { - let plan = resolve_run_plan(file_config_agent_dir(), None).expect("run plan"); + fn resolves_complete_typed_config_with_explicit_base_dir() { + let base_dir = repository_root(); + let plan = resolve_run_plan_from_config( + typed_config("nvidia.fabric.hermes"), + ResolveContext::new(&base_dir), + ) + .expect("typed plan"); + let base_dir = std::path::absolute(base_dir).expect("absolute base directory"); - assert_eq!(plan.agent_name, "code-review-agent"); - assert!(plan.profiles.is_empty()); - let plan_json = serde_json::to_value(&plan).expect("plan json"); - assert_eq!(plan_json["profiles"], serde_json::json!([])); + assert_eq!(plan.agent_name, "typed-agent"); + assert_eq!(plan.base_dir, base_dir); assert_eq!( - plan_json["capabilities"], - serde_json::json!({ - "service": false, - "streaming": false, - "updates": false, - "cancellation": false - }) + plan.capability_plan.skill_paths, + vec![plan.base_dir.join("skills/review")] ); - assert_eq!(plan.config.harness.adapter_id, "nvidia.fabric.hermes"); assert_eq!( plan.adapter_descriptor .as_ref() .map(|adapter| adapter.descriptor.adapter_id.as_str()), Some("nvidia.fabric.hermes") ); - assert_eq!( - plan.adapter_descriptor - .as_ref() - .map(|adapter| adapter.descriptor.adapter_kind), - Some(AdapterKind::Python) - ); - assert_eq!( - plan.adapter_descriptor - .as_ref() - .map(|adapter| adapter.source), - Some(AdapterDescriptorSource::Repository) - ); - assert_eq!(plan.resolution, Some(ResolutionStrategy::Preinstalled)); - assert_eq!( - plan.environment_plan - .as_ref() - .map(|environment| environment.provider.as_str()), - Some("local") - ); - assert_eq!(plan.capability_plan.skill_paths.len(), 1); - assert!(plan.capability_plan.mcp_servers.contains_key("github")); - assert_eq!(plan.capability_plan.native.skill_paths.len(), 1); - assert!( - plan.capability_plan - .native - .mcp_servers - .contains_key("github") - ); - assert!(plan.capability_plan.managed.skill_paths.is_empty()); - assert!(plan.capability_plan.managed.mcp_servers.is_empty()); - assert!(plan.config.profiles.directories.is_empty()); - assert_eq!( - plan.config - .telemetry - .as_ref() - .map(|telemetry| telemetry.providers.is_empty()), - None - ); - } - - #[test] - fn resolves_hermes_adapter_descriptor() { - let plan = resolve_run_plan(file_config_agent_dir(), Some("hermes")).expect("run plan"); - let adapter = plan - .adapter_descriptor - .as_ref() - .expect("configured adapter"); - - assert_eq!(adapter.source, AdapterDescriptorSource::Repository); - assert_eq!(adapter.descriptor.adapter_id, "nvidia.fabric.hermes"); - assert_eq!(adapter.descriptor.adapter_kind, AdapterKind::Python); - assert!(adapter.root.ends_with("adapters/hermes")); } #[test] - fn resolves_package_local_custom_adapter_descriptor() { - let root = - std::env::temp_dir().join(format!("fabric-local-adapter-test-{}", std::process::id())); - let _ = std::fs::remove_dir_all(&root); - std::fs::create_dir_all(root.join("adapters/reviewer-process")).expect("create adapters"); - std::fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: reviewer-agent -harness: - adapter_id: acme.fabric.reviewer.process -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: message -environment: - provider: local -"#, - ) - .expect("write agent config"); - std::fs::write( - root.join("adapters/reviewer-process/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.reviewer.process", - "harness": "reviewer", - "adapter_kind": "process" -}"#, + fn relative_base_dir_becomes_absolute_before_deriving_paths() { + let plan = resolve_run_plan_from_config( + typed_config("nvidia.fabric.hermes"), + ResolveContext::new("."), ) - .expect("write adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - let adapter = plan - .adapter_descriptor - .as_ref() - .expect("configured adapter"); + .expect("typed plan"); + let expected_base = std::env::current_dir().expect("current directory"); - assert_eq!(adapter.source, AdapterDescriptorSource::Local); - assert_eq!( - adapter.descriptor.adapter_id, - "acme.fabric.reviewer.process" - ); - assert_eq!(adapter.descriptor.adapter_kind, AdapterKind::Process); - - let _ = std::fs::remove_dir_all(root); - } - - #[test] - fn resolves_env_profile_from_agent_directory() { - let plan = - resolve_run_plan(file_config_agent_dir(), Some("env_opensandbox")).expect("run plan"); - - assert_eq!(plan.profiles, vec!["env_opensandbox"]); - assert!(plan.config_path.ends_with("agent.yaml")); - assert_eq!( - plan.config - .environment - .as_ref() - .map(|environment| environment.provider.as_str()), - Some("opensandbox") - ); - } - - #[test] - fn resolves_mcp_profile_from_agent_directory() { - let plan = resolve_run_plan(file_config_agent_dir(), Some("mcp_github")).expect("run plan"); - - assert_eq!(plan.profiles, vec!["mcp_github"]); - let plan_json = serde_json::to_value(&plan).expect("plan json"); - assert!(plan_json.get("profile").is_none()); - assert_eq!( - plan.config.mcp.as_ref().map(|mcp| mcp.servers.len()), - Some(1) - ); - assert!(plan.capability_plan.native.mcp_servers.is_empty()); - assert!(plan.capability_plan.managed.mcp_servers.is_empty()); - assert!( - plan.capability_plan.routes.iter().any( - |route| route.name == "github" && route.target == CapabilityTarget::Unsupported - ) - ); - assert!( - plan.capability_plan - .unsupported - .mcp_servers - .contains_key("github") - ); - } - - #[test] - fn resolves_ordered_profiles_from_agent_directory() { - let profiles = vec!["env_local".to_string(), "mcp_github".to_string()]; - let plan = - resolve_run_plan_with_profiles(file_config_agent_dir(), &profiles).expect("run plan"); - - assert_eq!(plan.profiles, profiles); + assert_eq!(plan.base_dir, expected_base); assert_eq!( plan.environment_plan .as_ref() - .map(|environment| environment.provider.as_str()), - Some("local") + .and_then(|environment| environment.workspace.as_ref()), + Some(&expected_base.join("workspace")) ); assert_eq!( - plan.telemetry_plan - .as_ref() - .map(|telemetry| telemetry.relay_enabled), - Some(true) - ); - assert!(plan.capability_plan.managed.mcp_servers.is_empty()); - assert!( - plan.capability_plan - .unsupported - .mcp_servers - .contains_key("github") + plan.capability_plan.skill_paths, + vec![expected_base.join("skills/review")] ); } #[test] - fn resolves_in_memory_config_with_typed_profiles() { - let FabricDocument::FabricConfig { config, root, .. } = - load_fabric_document(file_config_agent_dir()).expect("agent config"); - let profile = read_yaml::(&root.join("profiles/mcp-github.yaml")) - .expect("profile config"); - + fn typed_config_round_trip_has_no_file_provenance() { let plan = resolve_run_plan_from_config( - config, - &[profile], - ResolveContext::from_agent_root(root.clone()), + typed_config("nvidia.fabric.hermes"), + ResolveContext::new("/tmp/fabric-base"), ) .expect("run plan"); + let value = serde_json::to_value(plan).expect("run plan JSON"); - assert_eq!(plan.profiles, vec!["mcp_github"]); - assert!(plan.config_path.ends_with("agent.yaml")); - assert!(plan.config.profiles.directories.is_empty()); - assert!(plan.capability_plan.managed.mcp_servers.is_empty()); - assert!( - plan.capability_plan - .unsupported - .mcp_servers - .contains_key("github") - ); - assert_eq!(plan.config_root, root); - } - - #[test] - fn unsupported_capabilities_do_not_claim_fabric_managed_execution() { - let root = std::env::temp_dir().join(format!( - "fabric-unsupported-capability-test-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&root); - std::fs::create_dir_all(root.join("adapters/minimal")).expect("create adapters"); - std::fs::create_dir_all(root.join("skills/review")).expect("create skills"); - std::fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: unsupported-capability-agent -harness: - adapter_id: acme.fabric.minimal -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: text -tools: - blocked: - - shell -skills: - paths: - - ./skills/review -mcp: - servers: - github: - transport: streamable-http - url: http://example.invalid/mcp - exposure: fabric_managed -"#, - ) - .expect("write agent config"); - std::fs::write( - root.join("adapters/minimal/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.minimal", - "harness": "minimal", - "adapter_kind": "process" -}"#, - ) - .expect("write adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - - assert!(!plan.capability_plan.managed.tools_configured); - assert!(plan.capability_plan.managed.skill_paths.is_empty()); - assert!(plan.capability_plan.managed.mcp_servers.is_empty()); - assert_eq!(plan.capability_plan.tools.blocked, vec!["shell"]); - assert!(plan.capability_plan.unsupported.tools_configured); - assert_eq!(plan.capability_plan.unsupported.skill_paths.len(), 1); - assert!( - plan.capability_plan - .unsupported - .mcp_servers - .contains_key("github") - ); - assert!( - plan.capability_plan - .routes - .iter() - .all(|route| route.target == CapabilityTarget::Unsupported), - "{:?}", - plan.capability_plan.routes - ); - - let _ = std::fs::remove_dir_all(root); + assert_eq!(value["base_dir"], "/tmp/fabric-base"); + assert_eq!(value["config"]["metadata"]["name"], "typed-agent"); + assert!(value.get("effective_config").is_none()); } #[test] - fn blocked_tools_require_policy_specific_adapter_support() { - let root = std::env::temp_dir().join(format!( - "fabric-blocked-tools-capability-test-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&root); - std::fs::create_dir_all(root.join("adapters/tools")).expect("create adapters"); - std::fs::write( - root.join("adapters/tools/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.tools", - "harness": "tools", - "adapter_kind": "process", - "config": {"accepts": ["tools"]} -}"#, - ) - .expect("write adapter descriptor"); - std::fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: blocked-tools-agent -harness: - adapter_id: acme.fabric.tools -runtime: -tools: - blocked: - - browser -"#, - ) - .expect("write agent config"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - - assert_eq!(plan.capability_plan.tools.blocked, vec!["browser"]); - assert!(plan.capability_plan.tools_configured); - assert!(!plan.capability_plan.native.tools_configured); - assert!(plan.capability_plan.unsupported.tools_configured); - assert!(plan.capability_plan.routes.iter().any(|route| { - route.name == "tools.blocked" && route.target == CapabilityTarget::Unsupported - })); - - std::fs::write( - root.join("adapters/tools/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.tools", - "harness": "tools", - "adapter_kind": "process", - "config": {"accepts": ["tools", "tools.blocked"]} -}"#, - ) - .expect("write policy-aware adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("policy-aware run plan"); - - assert!(plan.capability_plan.native.tools_configured); - assert!(!plan.capability_plan.unsupported.tools_configured); - assert!(plan.capability_plan.routes.iter().any(|route| { - route.name == "tools.blocked" && route.target == CapabilityTarget::HarnessNative - })); - - std::fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: blocked-tools-agent -harness: - adapter_id: acme.fabric.tools -runtime: -tools: - blocked: [] -"#, - ) - .expect("write empty tools config"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - - assert!(plan.capability_plan.tools.blocked.is_empty()); - assert!(!plan.capability_plan.tools_configured); - assert!(!plan.capability_plan.native.tools_configured); - assert!(plan.capability_plan.routes.is_empty()); - - let _ = std::fs::remove_dir_all(root); - } - - #[test] - fn later_profiles_override_earlier_profiles() { - let profiles = vec!["env_opensandbox".to_string(), "env_local".to_string()]; - let plan = - resolve_run_plan_with_profiles(file_config_agent_dir(), &profiles).expect("run plan"); - - assert_eq!(plan.profiles, profiles); - assert_eq!( - plan.environment_plan - .as_ref() - .map(|environment| environment.provider.as_str()), - Some("local") - ); - assert_eq!( - plan.environment_plan - .as_ref() - .and_then(|environment| environment.workspace.as_ref()) - .map(|path| path.ends_with("repos/my-service")), - Some(true) - ); - assert_eq!( - plan.telemetry_plan - .as_ref() - .map(|telemetry| telemetry.relay_enabled), - None - ); - - let profiles = vec!["env_local".to_string(), "env_opensandbox".to_string()]; - let plan = - resolve_run_plan_with_profiles(file_config_agent_dir(), &profiles).expect("run plan"); - - assert_eq!( - plan.environment_plan - .as_ref() - .map(|environment| environment.provider.as_str()), - Some("opensandbox") - ); - assert_eq!( - plan.telemetry_plan - .as_ref() - .map(|telemetry| telemetry.relay_enabled), - Some(true) - ); - } - - #[test] - fn resolves_hermes_profile_from_agent_directory() { - let plan = resolve_run_plan(file_config_agent_dir(), Some("hermes")).expect("run plan"); - - assert_eq!(plan.profiles, vec!["hermes"]); - assert_eq!(plan.config.harness.adapter_id, "nvidia.fabric.hermes"); - assert_eq!( - plan.adapter_descriptor - .as_ref() - .map(|adapter| adapter.descriptor.adapter_id.as_str()), - Some("nvidia.fabric.hermes") - ); - assert_eq!( - plan.adapter_descriptor - .as_ref() - .map(|adapter| adapter.descriptor.adapter_kind), - Some(AdapterKind::Python) - ); - assert_eq!( - plan.adapter_descriptor - .as_ref() - .map(|adapter| adapter.source), - Some(AdapterDescriptorSource::Repository) - ); - assert_eq!(plan.resolution, Some(ResolutionStrategy::Preinstalled)); - assert_eq!( - plan.telemetry_plan - .as_ref() - .map(|telemetry| telemetry.relay_enabled), - None - ); - assert!( - plan.capability_plan - .native - .mcp_servers - .contains_key("github") - ); - assert!(plan.capability_plan.managed.mcp_servers.is_empty()); - assert_eq!(plan.capability_plan.native.skill_paths.len(), 1); - assert!(plan.capability_plan.managed.skill_paths.is_empty()); - } - - #[test] - fn resolves_direct_profile_path_from_agent_directory() { - let plan = resolve_run_plan(file_config_agent_dir(), Some("./profiles/hermes.yaml")) - .expect("run plan"); - - assert_eq!(plan.profiles, vec!["./profiles/hermes.yaml"]); - assert_eq!(plan.config.harness.adapter_id, "nvidia.fabric.hermes"); - assert_eq!( - plan.adapter_descriptor - .as_ref() - .map(|adapter| adapter.descriptor.adapter_id.as_str()), - Some("nvidia.fabric.hermes") - ); - } - - #[test] - fn errors_for_unknown_manifest_profile() { - let error = resolve_run_plan(file_config_agent_dir(), Some("missing")).expect_err("error"); - - assert!(matches!(error, FabricError::UnknownProfile { .. })); - } - - #[test] - fn rejects_malformed_adapter_descriptor() { - let root = std::env::temp_dir().join(format!( - "fabric-invalid-adapter-test-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&root); - std::fs::create_dir_all(root.join("adapters/invalid-process")).expect("create adapters"); - std::fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: invalid-adapter-agent -harness: - adapter_id: acme.fabric.invalid.process -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: message -environment: - provider: local -"#, - ) - .expect("write agent config"); - std::fs::write( - root.join("adapters/invalid-process/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": " ", - "harness": "invalid", - "adapter_kind": "process" -}"#, - ) - .expect("write adapter descriptor"); - - let error = resolve_run_plan(&root, None).expect_err("invalid descriptor"); - assert!(matches!( - error, - FabricError::InvalidAdapterDescriptor { message, .. } - if message.contains("adapter_id") - )); - - let _ = std::fs::remove_dir_all(root); - } - - #[test] - fn rejects_empty_adapter_id_when_loading_descriptor_directly() { - let root = std::env::temp_dir().join(format!( - "fabric-invalid-adapter-shape-test-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&root); - std::fs::create_dir_all(&root).expect("create temp root"); - let descriptor_path = root.join("fabric-adapter.json"); - std::fs::write( - &descriptor_path, - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "", - "harness": "invalid", - "adapter_kind": "process" -}"#, - ) - .expect("write adapter descriptor"); - - let error = load_adapter_descriptor(&descriptor_path).expect_err("invalid descriptor"); - assert!(matches!( - error, - FabricError::InvalidAdapterDescriptor { message, .. } - if message.contains("adapter_id") - )); - - let _ = std::fs::remove_dir_all(root); - } + fn loads_and_validates_json_adapter_descriptor() { + let descriptor = + load_adapter_descriptor(repository_root().join("adapters/hermes/fabric-adapter.json")) + .expect("adapter descriptor"); - #[test] - fn rejects_unsupported_adapter_contract_version() { - let root = std::env::temp_dir().join(format!( - "fabric-invalid-adapter-contract-test-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&root); - std::fs::create_dir_all(&root).expect("create temp root"); - let descriptor_path = root.join("fabric-adapter.json"); - std::fs::write( - &descriptor_path, - r#"{ - "contract_version": "fabric.adapter/v9", - "adapter_id": "acme.fabric.future", - "harness": "future", - "adapter_kind": "process" -}"#, - ) - .expect("write adapter descriptor"); - - let error = load_adapter_descriptor(&descriptor_path).expect_err("invalid descriptor"); - assert!(matches!( - error, - FabricError::AdapterDescriptorUnsupported { - field, - value, - .. - } if field == "contract_version" && value == "fabric.adapter/v9" - )); - - let _ = std::fs::remove_dir_all(root); + assert_eq!(descriptor.contract_version, ADAPTER_CONTRACT_VERSION); + assert_eq!(descriptor.adapter_kind, AdapterKind::Python); } } diff --git a/crates/fabric-core/src/doctor.rs b/crates/fabric-core/src/doctor.rs index c4a397677..10f3117d1 100644 --- a/crates/fabric-core/src/doctor.rs +++ b/crates/fabric-core/src/doctor.rs @@ -46,8 +46,6 @@ pub struct DoctorCheck { pub struct DoctorReport { /// Agent name. pub agent_name: String, - /// Ordered profiles applied to the inspected plan. - pub profiles: Vec, /// Overall status. pub status: DoctorStatus, /// Checks. @@ -68,7 +66,6 @@ pub fn doctor_plan(plan: &RunPlan) -> DoctorReport { }); DoctorReport { agent_name: plan.agent_name.clone(), - profiles: plan.profiles.clone(), status, checks, } @@ -388,7 +385,7 @@ struct BinaryRequirement { fn binary_requirement(plan: &RunPlan, binary: &str) -> BinaryRequirement { let setting_key = binary_command_setting_key(binary); if let Some(Value::String(command)) = plan.config.harness.settings.get(&setting_key) { - let command_path = resolve_command(&plan.config_root, command); + let command_path = resolve_command(&plan.base_dir, command); let display = command_path.to_string_lossy().into_owned(); return BinaryRequirement { available: command_available(&display), @@ -469,146 +466,42 @@ fn worst(left: DoctorStatus, right: DoctorStatus) -> DoctorStatus { #[cfg(test)] mod tests { - use std::path::PathBuf; - - use serde_json::Value; - use super::*; - use crate::config::{ - AdapterKind, CapabilityKind, CapabilityRoute, CapabilityTarget, ResolutionStrategy, - resolve_run_plan, - }; - - fn file_config_agent_dir() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../tests/fixtures/file-config-agent") - } + use crate::config::{FabricConfig, ResolveContext, resolve_run_plan_from_config}; #[test] - fn image_provided_uses_environment_image_instead_of_host_requirements() { - let mut plan = resolve_run_plan(file_config_agent_dir(), None).expect("run plan"); - plan.resolution = Some(ResolutionStrategy::ImageProvided); - plan.environment_plan - .as_mut() - .expect("environment") - .settings - .insert( - "image".to_string(), - Value::String("fabric-hermes:latest".to_string()), - ); + fn diagnoses_a_typed_plan_without_file_source_fields() { + let config: FabricConfig = serde_json::from_value(serde_json::json!({ + "schema_version": "fabric.agent/v1alpha1", + "metadata": {"name": "doctor-agent"}, + "harness": { + "adapter_id": "test.fabric.hermes_shim", + "resolution": "preinstalled", + "settings": {"python3_command": "bin/tool"} + }, + "runtime": {}, + "environment": {"provider": "local"} + })) + .expect("typed config"); + let base_dir = PathBuf::from("../../tests/fixtures/hermes-shim-agent"); + let plan = resolve_run_plan_from_config(config, ResolveContext::new(base_dir)) + .expect("typed plan"); let report = doctor_plan(&plan); - - assert_eq!(report.status, DoctorStatus::Pass); - assert!(report.checks.iter().any(|check| { - check.name == "requirements.image" && check.message.contains("fabric-hermes:latest") - })); + let value = serde_json::to_value(&report).expect("doctor JSON"); + assert_eq!(report.agent_name, "doctor-agent"); + assert!(!report.checks.is_empty()); + assert_eq!(value["agent_name"], "doctor-agent"); + let expected_command = + std::path::absolute("../../tests/fixtures/hermes-shim-agent/bin/tool") + .expect("absolute command path") + .to_string_lossy() + .into_owned(); assert!( - !report + report .checks .iter() - .any(|check| check.name == "requirement.binary") - ); - } - - #[test] - fn preinstalled_non_local_environment_does_not_probe_host_requirements() { - let plan = - resolve_run_plan(file_config_agent_dir(), Some("env_opensandbox")).expect("run plan"); - - let report = doctor_plan(&plan); - - assert_eq!(report.status, DoctorStatus::Warn); - let report_json = serde_json::to_value(&report).expect("doctor report json"); - assert!(report_json.get("profile").is_none()); - assert_eq!( - report_json["profiles"], - serde_json::json!(["env_opensandbox"]) - ); - assert!(report.checks.iter().any(|check| { - check.name == "requirements.environment" && check.message.contains("opensandbox") - })); - assert!( - !report - .checks - .iter() - .any(|check| check.name == "requirement.binary") - ); - } - - #[test] - fn binary_requirement_can_use_harness_command_setting() { - let mut plan = resolve_run_plan(file_config_agent_dir(), Some("codex")).expect("run plan"); - plan.adapter_descriptor - .as_mut() - .expect("adapter descriptor") - .descriptor - .requirements - .binaries = vec!["fabric-doctor-test".to_string()]; - plan.config.harness.settings.insert( - "fabric_doctor_test_command".to_string(), - Value::String( - std::env::current_exe() - .expect("current executable") - .to_string_lossy() - .into_owned(), - ), + .any(|check| check.message.contains(&expected_command)) ); - - let report = doctor_plan(&plan); - - assert!(report.checks.iter().any(|check| { - check.name == "requirement.binary" - && check.status == DoctorStatus::Pass - && check.message.contains("fabric_doctor_test_command") - })); - } - - #[test] - fn doctor_reports_http_execution_as_modeled_not_implemented() { - let mut plan = resolve_run_plan(file_config_agent_dir(), None).expect("run plan"); - plan.resolution = Some(ResolutionStrategy::Service); - plan.adapter_descriptor - .as_mut() - .expect("adapter descriptor") - .descriptor - .adapter_kind = AdapterKind::Http; - - let report = doctor_plan(&plan); - - assert_eq!(report.status, DoctorStatus::Warn); - assert!(report.checks.iter().any(|check| { - check.name == "runtime.adapter" - && check.status == DoctorStatus::Warn - && check - .message - .contains("runtime dispatch is not implemented") - && check.message.contains("http") - })); - assert!(report.checks.iter().any(|check| { - check.name == "resolution" - && check.status == DoctorStatus::Warn - && check.message.contains("modeled but not implemented") - && check.message.contains("service") - })); - } - - #[test] - fn unsupported_blocked_tools_fail_doctor() { - let mut plan = resolve_run_plan(file_config_agent_dir(), None).expect("run plan"); - plan.capability_plan.routes.push(CapabilityRoute { - kind: CapabilityKind::Tools, - name: "blocked".to_string(), - target: CapabilityTarget::Unsupported, - reason: "adapter does not accept tools".to_string(), - }); - - let report = doctor_plan(&plan); - - assert_eq!(report.status, DoctorStatus::Fail); - assert!(report.checks.iter().any(|check| { - check.name == "capability.unsupported" - && check.status == DoctorStatus::Fail - && check.message.contains("adapter does not accept tools") - })); } } diff --git a/crates/fabric-core/src/error.rs b/crates/fabric-core/src/error.rs index dbed6db8f..411409598 100644 --- a/crates/fabric-core/src/error.rs +++ b/crates/fabric-core/src/error.rs @@ -13,33 +13,17 @@ pub type Result = std::result::Result; /// Errors raised by Fabric config loading and validation. #[derive(Debug, thiserror::Error)] pub enum FabricError { + /// The base directory could not be resolved to an absolute path. + #[error("failed to resolve base directory {path}: {source}")] + ResolveBaseDirectory { + /// Base directory supplied by the caller. + path: PathBuf, + /// Underlying path-resolution error. + source: std::io::Error, + }, /// The requested path does not exist. #[error("path does not exist: {0}")] PathNotFound(PathBuf), - /// A directory did not contain the expected Fabric entrypoint. - #[error("directory does not contain agent.yaml: {0}")] - MissingEntrypoint(PathBuf), - /// A file extension is not recognized for Fabric config loading. - #[error("unsupported config file extension for {0}")] - UnsupportedExtension(PathBuf), - /// A requested profile is not present in an agent manifest. - #[error("unknown profile `{profile}` for agent `{agent}`; available profiles: {available:?}")] - UnknownProfile { - /// Requested profile. - profile: String, - /// Agent name. - agent: String, - /// Available profile names. - available: Vec, - }, - /// A profile config failed validation. - #[error("profile error in {path}: {message}")] - ProfileError { - /// Profile path. - path: PathBuf, - /// Validation message. - message: String, - }, /// A requested adapter id is not present in the agent config. #[error("unknown adapter `{adapter_id}`; available adapters: {available:?}")] UnknownAdapter { @@ -88,17 +72,6 @@ pub enum FabricError { /// Available schema names. available: Vec, }, - /// A profile path resolved to an agent manifest instead of a profile config. - #[error("profile `{profile}` did not resolve to a Fabric config: {path}")] - ProfileTargetNotConfig { - /// Profile name. - profile: String, - /// Resolved path. - path: PathBuf, - }, - /// A profile was requested for a single profile config. - #[error("profile selection is only supported for agent manifests: {0}")] - ProfileSelectionNotSupported(PathBuf), /// Runtime invocation is not supported for the selected adapter. #[error( "runtime invocation is not implemented for harness `{harness}` with adapter `{adapter_kind:?}`" @@ -196,14 +169,6 @@ pub enum FabricError { /// Underlying IO error. source: std::io::Error, }, - /// YAML parse failed. - #[error("failed to parse YAML in {path}: {source}")] - ParseYaml { - /// File path. - path: PathBuf, - /// Underlying YAML error. - source: serde_yaml::Error, - }, /// JSON parse failed. #[error("failed to parse JSON in {path}: {source}")] ParseJson { diff --git a/crates/fabric-core/src/lib.rs b/crates/fabric-core/src/lib.rs index 80e78f511..2d55cc98d 100644 --- a/crates/fabric-core/src/lib.rs +++ b/crates/fabric-core/src/lib.rs @@ -12,15 +12,12 @@ pub mod schema; pub use config::{ ADAPTER_CONTRACT_VERSION, AdapterConfigSupport, AdapterDescriptor, AdapterDescriptorSource, AdapterKind, AdapterRequirements, AdapterTelemetryProviderSupport, AdapterTelemetrySupport, - CapabilityPlan, ControlLocation, EffectiveConfig, EnvironmentConfig, EnvironmentOwnership, - EnvironmentPlan, FabricConfig, FabricDocument, HarnessConfig, McpConfig, McpExposure, - McpServerPlan, MetadataConfig, ModelConfig, ProfileConfig, ResolutionStrategy, ResolveContext, - ResolvedAdapterDescriptor, RunPlan, RuntimeCapabilities, RuntimeConfig, SkillConfig, - TelemetryConfig, TelemetryPlan, TelemetryProvider, TelemetryProviderConfig, - load_adapter_descriptor, load_fabric_document, resolve_effective_config, - resolve_effective_config_from_config, resolve_effective_config_with_profiles, resolve_run_plan, - resolve_run_plan_from_config, resolve_run_plan_from_effective_config, - resolve_run_plan_with_profiles, validate_agent_directory, + CapabilityPlan, ControlLocation, EnvironmentConfig, EnvironmentOwnership, EnvironmentPlan, + FabricConfig, HarnessConfig, McpConfig, McpExposure, McpServerPlan, MetadataConfig, + ModelConfig, ResolutionStrategy, ResolveContext, ResolvedAdapterDescriptor, RunPlan, + RuntimeCapabilities, RuntimeConfig, SkillConfig, TelemetryConfig, TelemetryPlan, + TelemetryProvider, TelemetryProviderConfig, load_adapter_descriptor, + resolve_run_plan_from_config, }; pub use doctor::{DoctorCheck, DoctorReport, DoctorStatus, doctor_plan}; pub use error::{FabricError, Result}; diff --git a/crates/fabric-core/src/runtime.rs b/crates/fabric-core/src/runtime.rs index 4443c75e7..8c07fd406 100644 --- a/crates/fabric-core/src/runtime.rs +++ b/crates/fabric-core/src/runtime.rs @@ -19,7 +19,7 @@ use serde_json::{Map, Value}; use crate::config::{ AdapterKind, CapabilityKind, CapabilityPlan, CapabilityTarget, ControlLocation, - EffectiveConfig, EnvironmentOwnership, RunPlan, TelemetryPlan, + EnvironmentOwnership, FabricConfig, RunPlan, TelemetryPlan, }; use crate::error::{FabricError, Result}; @@ -57,7 +57,7 @@ pub struct RunRequest { /// Runtime context such as task, rollout, workflow, or caller metadata. #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub context: BTreeMap, - /// Per-invocation overrides allowed by the resolved profile. + /// Per-invocation overrides allowed by the resolved config. #[serde(default, skip_serializing_if = "Option::is_none")] pub overrides: Option, } @@ -79,8 +79,6 @@ impl RunRequest { pub struct RunResult { /// Stable agent name. pub agent_name: String, - /// Ordered profiles applied to this run. - pub profiles: Vec, /// Stable machine-readable harness identifier used for this run. pub harness: String, /// Adapter used for this run. @@ -149,7 +147,7 @@ pub struct ErrorInfo { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ErrorStage { - /// Configuration or profile loading failed. + /// Configuration resolution failed. Config, /// Effective config planning failed. Plan, @@ -311,8 +309,12 @@ pub struct RuntimeTelemetryContext { /// Adapter-facing invocation payload. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct AdapterInvocation { - /// Merged agent config and provenance. - pub effective_config: EffectiveConfig, + /// Stable agent name. + pub agent_name: String, + /// Absolute base directory used to resolve relative Fabric paths. + pub base_dir: PathBuf, + /// Complete typed Fabric config. + pub config: FabricConfig, /// Per-runtime/per-invocation execution context. pub runtime_context: RuntimeContext, /// Per-invocation request. @@ -388,12 +390,12 @@ pub fn prepare_environment(plan: &RunPlan) -> Result { "local".to_string(), ControlLocation::ExternalControl, EnvironmentOwnership::CallerOwned, - Some(plan.agent_root.clone()), + Some(plan.base_dir.clone()), plan.config .runtime .artifacts .as_ref() - .map(|artifacts| resolve_path(&plan.config_root, artifacts)), + .map(|artifacts| resolve_path(&plan.base_dir, artifacts)), serde_json::Map::new(), serde_json::Map::new(), serde_json::Map::new(), @@ -777,9 +779,9 @@ fn run_process_adapter( let cwd = settings .cwd .as_ref() - .map(|path| resolve_path(&plan.config_root, path)) + .map(|path| resolve_path(&plan.base_dir, path)) .or_else(|| runtime.environment.workspace.clone()) - .unwrap_or_else(|| plan.agent_root.clone()); + .unwrap_or_else(|| plan.base_dir.clone()); let mut artifacts = artifact_manifest(plan)?; let fabric_home = prepare_fabric_home(&artifacts, runtime, &invocation)?; let relay_config = prepare_relay_runtime_config( @@ -964,7 +966,6 @@ fn run_process_adapter( Ok(RunResult { agent_name: plan.agent_name.clone(), - profiles: plan.profiles.clone(), harness: harness(plan), adapter_kind: adapter_kind(plan), adapter_id: adapter_id(plan), @@ -998,11 +999,11 @@ fn run_python_adapter( let cwd = settings .cwd .as_ref() - .map(|path| resolve_path(&plan.config_root, path)) + .map(|path| resolve_path(&plan.base_dir, path)) .or_else(|| runtime.environment.workspace.clone()) - .unwrap_or_else(|| plan.agent_root.clone()); + .unwrap_or_else(|| plan.base_dir.clone()); - let python = resolve_python_command(&plan.config_root, &settings).path; + let python = resolve_python_command(&plan.base_dir, &settings).path; let mut artifacts = artifact_manifest(plan)?; let fabric_home = prepare_fabric_home(&artifacts, runtime, &invocation)?; let relay_config = prepare_relay_runtime_config( @@ -1175,7 +1176,6 @@ fn run_python_adapter( Ok(RunResult { agent_name: plan.agent_name.clone(), - profiles: plan.profiles.clone(), harness: harness(plan), adapter_kind: adapter_kind(plan), adapter_id: adapter_id(plan), @@ -1260,7 +1260,7 @@ fn adapter_exit_error( fn parse_python_settings(plan: &RunPlan) -> Result { let value = Value::Object(merged_adapter_settings(plan)); serde_json::from_value(value).map_err(|source| FabricError::InvalidPythonSettings { - path: plan.config_path.clone(), + path: plan.base_dir.clone(), source, }) } @@ -1268,7 +1268,7 @@ fn parse_python_settings(plan: &RunPlan) -> Result { fn parse_process_settings(plan: &RunPlan) -> Result { let value = Value::Object(merged_adapter_settings(plan)); serde_json::from_value(value).map_err(|source| FabricError::InvalidProcessSettings { - path: plan.config_path.clone(), + path: plan.base_dir.clone(), source, }) } @@ -1285,12 +1285,12 @@ fn merged_adapter_settings(plan: &RunPlan) -> Map { fn adapter_setting_root<'a>(plan: &'a RunPlan, key: &str) -> &'a Path { if plan.config.harness.settings.contains_key(key) { - return &plan.config_root; + return &plan.base_dir; } plan.adapter_descriptor .as_ref() .map(|adapter| adapter.root.as_path()) - .unwrap_or(&plan.config_root) + .unwrap_or(&plan.base_dir) } fn fabric_adapter_payload( @@ -1320,12 +1320,10 @@ fn adapter_invocation( artifacts: &ArtifactManifest, relay_config: Option<&RelayRuntimeConfig>, ) -> Result { - let mut effective_config = plan.effective_config.clone(); - effective_config.agent_root = absolute_path(effective_config.agent_root)?; - effective_config.config_path = absolute_path(effective_config.config_path)?; - effective_config.config_root = absolute_path(effective_config.config_root)?; Ok(AdapterInvocation { - effective_config, + agent_name: plan.agent_name.clone(), + base_dir: absolute_path(plan.base_dir.clone())?, + config: plan.config.clone(), runtime_context: RuntimeContext { runtime_id: runtime.runtime_id.clone(), invocation_id: invocation.invocation_id.clone(), @@ -1403,7 +1401,7 @@ fn resolve_command_path(root: &Path, path: &Path) -> PathBuf { fn preflight_python_adapter(plan: &RunPlan) -> Result<()> { let settings = parse_python_settings(plan)?; - let command = resolve_python_command(&plan.config_root, &settings); + let command = resolve_python_command(&plan.base_dir, &settings); validate_python_command(&command) } @@ -1658,7 +1656,7 @@ fn artifact_manifest(plan: &RunPlan) -> Result { .runtime .artifacts .as_ref() - .map(|path| resolve_path(&plan.config_root, path)) + .map(|path| resolve_path(&plan.base_dir, path)) .or_else(|| { plan.environment_plan .as_ref() @@ -1891,7 +1889,6 @@ fn prepare_relay_runtime_config( }, "fabric": { "agent_name": plan.agent_name.clone(), - "profiles": plan.profiles.clone(), "harness": harness(plan), "adapter_id": adapter_id(plan), "runtime_id": runtime.runtime_id.clone(), @@ -2012,1075 +2009,3 @@ fn now_millis() -> u128 { .map(|duration| duration.as_millis()) .unwrap_or_default() } - -#[cfg(test)] -mod tests { - use std::fs; - - use super::*; - use crate::config::resolve_run_plan; - - fn fixture_agent_dir() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../tests/fixtures/hermes-shim-agent") - } - - fn temp_process_agent_dir() -> PathBuf { - let root = std::env::temp_dir().join(new_id("fabric-process-adapter-test")); - process_agent_dir(root) - } - - fn process_agent_dir(root: PathBuf) -> PathBuf { - let _ = fs::remove_dir_all(&root); - fs::create_dir_all(&root).expect("create agent dir"); - fs::create_dir_all(root.join("adapters/process")).expect("create adapters dir"); - fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: process-test-agent -harness: - adapter_id: acme.fabric.process - settings: - command: cat -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: text - artifacts: ./artifacts -"#, - ) - .expect("write config"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - process_adapter_descriptor(), - ) - .expect("write adapter descriptor"); - root - } - - fn process_adapter_descriptor() -> &'static str { - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.process", - "harness": "process", - "adapter_kind": "process" -}"# - } - - fn stopped_agents() -> Vec { - TEST_STOPPED_AGENTS.lock().expect("stop tracker").clone() - } - - #[test] - fn prepare_environment_absolutizes_workspace() { - let root = - std::env::temp_dir().join(format!("fabric-workspace-abs-{}", std::process::id())); - let _ = fs::remove_dir_all(&root); - fs::create_dir_all(root.join("adapters/process")).expect("create agent dir"); - fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: workspace-abs-agent -harness: - adapter_id: acme.fabric.process - settings: - command: cat -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: text - artifacts: ./artifacts -environment: - provider: local - workspace: ./repos/my-service -"#, - ) - .expect("write config"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - process_adapter_descriptor(), - ) - .expect("write adapter descriptor"); - - let mut plan = resolve_run_plan(&root, None).expect("run plan"); - // Force a relative workspace to reproduce the pre-fix condition where an - // adapter would re-join it onto the absolute config_root and double the path. - plan.environment_plan - .as_mut() - .expect("environment plan") - .workspace = Some(PathBuf::from("repos/my-service")); - - let environment = prepare_environment(&plan).expect("prepare environment"); - let workspace = environment.workspace.expect("workspace"); - assert!( - workspace.is_absolute(), - "prepared workspace must be absolute so adapters do not re-resolve it: {workspace:?}" - ); - assert!(workspace.ends_with("repos/my-service"), "{workspace:?}"); - - let _ = fs::remove_dir_all(&root); - } - - fn artifact_content(result: &RunResult, name: &str) -> String { - let artifact = result - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == name) - .unwrap_or_else(|| panic!("missing artifact {name}")); - fs::read_to_string(&artifact.path).expect("read artifact") - } - - fn run_command(cwd: &Path, command: &str, args: &[&str]) { - let output = Command::new(command) - .args(args) - .current_dir(cwd) - .output() - .expect("run command"); - assert!( - output.status.success(), - "command failed: {command} {args:?}\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - } - - #[test] - fn process_adapter_passes_input_to_stdin() { - let root = temp_process_agent_dir(); - let mut plan = resolve_run_plan(&root, None).expect("run plan"); - plan.profiles = vec!["runtime".to_string(), "telemetry".to_string()]; - let result = run_plan(&plan, RunRequest::text("hello fabric")).expect("run result"); - - assert_eq!(result.status, RunStatus::Succeeded); - assert_eq!(result.output, Value::String("hello fabric".to_string())); - assert_eq!(result.metadata.get("exit_code"), Some(&Value::from(0))); - let result_json = serde_json::to_value(&result).expect("result json"); - assert!(result_json.get("profile").is_none()); - assert_eq!( - result_json["profiles"], - serde_json::json!(["runtime", "telemetry"]) - ); - assert_eq!(artifact_content(&result, "stdout"), "hello fabric"); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn runtime_rejects_blocked_tools_when_adapter_cannot_enforce_them() { - let root = temp_process_agent_dir(); - let config_path = root.join("agent.yaml"); - let mut config = fs::read_to_string(&config_path).expect("read config"); - config.push_str("tools:\n blocked:\n - shell\n"); - fs::write(&config_path, config).expect("write blocked tools config"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.process", - "harness": "process", - "adapter_kind": "process", - "config": {"accepts": ["tools"]} -}"#, - ) - .expect("write generic tools descriptor"); - let plan = resolve_run_plan(&root, None).expect("run plan"); - - let error = start_runtime(&plan).expect_err("unsupported tools policy must fail closed"); - - assert!(matches!(error, FabricError::UnsupportedToolsPolicy { .. })); - assert!( - error - .to_string() - .contains("cannot enforce configured blocked tools") - ); - let _ = fs::remove_dir_all(root); - } - - #[test] - fn independent_runtimes_use_distinct_artifact_paths() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let first_runtime = start_runtime(&plan).expect("first runtime"); - let second_runtime = start_runtime(&plan).expect("second runtime"); - - let first = invoke_runtime(&plan, &first_runtime, RunRequest::text("first runtime")) - .expect("first invocation"); - let second = invoke_runtime(&plan, &second_runtime, RunRequest::text("second runtime")) - .expect("second invocation"); - let first_stdout = first - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == "stdout") - .expect("first stdout artifact"); - let second_stdout = second - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == "stdout") - .expect("second stdout artifact"); - - assert_eq!(first.artifacts.root, second.artifacts.root); - assert_ne!(first_stdout.path, second_stdout.path); - assert!( - first_stdout.path.starts_with( - root.join("artifacts") - .join(".fabric") - .join(&first_runtime.runtime_id) - .join(&first.invocation_id) - ) - ); - assert!( - second_stdout.path.starts_with( - root.join("artifacts") - .join(".fabric") - .join(&second_runtime.runtime_id) - .join(&second.invocation_id) - ) - ); - assert_eq!(artifact_content(&first, "stdout"), "first runtime"); - assert_eq!(artifact_content(&second, "stdout"), "second runtime"); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn native_telemetry_skips_relay_and_reaches_adapter_payload() { - let root = temp_process_agent_dir(); - let config_path = root.join("agent.yaml"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - r#"{ - "contract_version": "fabric.adapter/v1alpha1", - "adapter_id": "acme.fabric.process", - "harness": "process", - "adapter_kind": "process", - "telemetry": { - "providers": { - "native": { - "outputs": ["otel"] - } - } - } -}"#, - ) - .expect("write adapter telemetry support"); - let mut config = fs::read_to_string(&config_path).expect("read agent config"); - config.push_str( - r#" -telemetry: - providers: - native: - config: - exporter: test -relay: - project: relay-project - output_dir: ./relay-output -"#, - ); - fs::write(&config_path, config).expect("write native telemetry config"); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - let request = RunRequest::text("hello fabric"); - let invocation = InvocationHandle { - invocation_id: "invocation-native-telemetry".to_string(), - request_id: request.request_id.clone(), - runtime_id: runtime.runtime_id.clone(), - }; - let mut artifacts = artifact_manifest(&plan).expect("artifact manifest"); - let artifact_directory = - prepare_fabric_home(&artifacts, &runtime, &invocation).expect("fabric home"); - - let relay = prepare_relay_runtime_config( - &plan, - &runtime, - &invocation, - &request, - &artifact_directory, - &mut artifacts, - ) - .expect("prepare telemetry"); - let payload = adapter_invocation( - &plan, - &runtime, - &invocation, - &request, - &artifacts, - relay.as_ref(), - ) - .expect("adapter invocation"); - let payload = serde_json::to_value(payload).expect("adapter payload json"); - - assert!(relay.is_none()); - assert!( - !artifacts - .artifacts - .iter() - .any(|artifact| artifact.name == "relay_config") - ); - assert_eq!( - payload["telemetry_plan"]["providers"], - serde_json::json!(["native"]) - ); - assert_eq!(payload["telemetry_plan"]["relay_enabled"], false); - assert_eq!( - payload["effective_config"]["config"]["telemetry"]["providers"]["native"]["config"], - serde_json::json!({"exporter": "test"}) - ); - assert!(payload["runtime_context"]["telemetry"].get("env").is_none()); - assert_eq!( - payload["runtime_context"]["telemetry"]["metadata"]["telemetry_providers"], - serde_json::json!(["native"]) - ); - assert!( - payload["runtime_context"]["telemetry"]["metadata"] - .get("relay_project") - .is_none() - ); - assert!( - payload["runtime_context"]["telemetry"]["metadata"] - .get("relay_output_dir") - .is_none() - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn run_plan_stops_runtime_after_invoke_error() { - let root = temp_process_agent_dir(); - let mut plan = resolve_run_plan(&root, None).expect("run plan"); - plan.agent_name = new_id("invoke-error-agent"); - plan.effective_config.agent_name = plan.agent_name.clone(); - plan.config.harness.settings.remove("command"); - let agent_name = plan.agent_name.clone(); - - let error = run_plan(&plan, RunRequest::text("hello fabric")).expect_err("invoke error"); - - assert!( - error - .to_string() - .contains("invalid process adapter settings"), - "{error}" - ); - assert!( - stopped_agents().contains(&agent_name), - "run_plan must stop the started runtime for {agent_name}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn runtime_handle_exposes_single_opaque_binding() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - - let value = serde_json::to_value(&runtime).expect("runtime json"); - assert!(value.get("runtime_binding").is_some()); - assert!(value.get("plan_fingerprint").is_none()); - assert!(value.get("environment_fingerprint").is_none()); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn runtime_handle_without_binding_is_rejected_during_deserialization() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - let mut value = serde_json::to_value(&runtime).expect("runtime json"); - value - .as_object_mut() - .expect("runtime object") - .remove("runtime_binding"); - let error = serde_json::from_value::(value) - .expect_err("runtime binding must be required"); - - assert!( - error - .to_string() - .contains("missing field `runtime_binding`"), - "{error}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn runtime_handle_validation_is_independent_of_current_directory() { - const CHILD_ENV: &str = "FABRIC_TEST_RUNTIME_HANDLE_CWD_CHILD"; - if std::env::var_os(CHILD_ENV).is_none() { - let output = Command::new(std::env::current_exe().expect("current test executable")) - .arg("runtime_handle_validation_is_independent_of_current_directory") - .arg("--nocapture") - .env(CHILD_ENV, "1") - .output() - .expect("run isolated cwd test"); - assert!( - output.status.success(), - "isolated cwd test failed\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - return; - } - - let parent = std::env::temp_dir().join(new_id("fabric-runtime-cwd-test")); - let root = process_agent_dir(parent.join("agent")); - fs::create_dir_all(parent.join("elsewhere")).expect("create alternate cwd"); - std::env::set_current_dir(&parent).expect("enter fixture parent"); - let plan = resolve_run_plan(Path::new("agent"), None).expect("relative run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - - std::env::set_current_dir(parent.join("elsewhere")).expect("change cwd"); - validate_runtime_handle(&plan, &runtime).expect("valid runtime handle"); - - std::env::set_current_dir(std::env::temp_dir()).expect("leave fixture"); - let _ = fs::remove_dir_all(root.parent().expect("fixture parent")); - } - - #[test] - fn invoke_runtime_rejects_runtime_handle_from_different_plan() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - let mut other_plan = plan.clone(); - other_plan.agent_name = "other-agent".to_string(); - other_plan.effective_config.agent_name = "other-agent".to_string(); - - let error = invoke_runtime(&other_plan, &runtime, RunRequest::text("hello fabric")) - .expect_err("runtime mismatch"); - - assert!( - error - .to_string() - .contains("runtime handle does not match run plan"), - "{error}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn invoke_runtime_rejects_runtime_handle_from_mutated_adapter_settings() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - let mut other_plan = plan.clone(); - other_plan - .config - .harness - .settings - .insert("command".to_string(), Value::String("printf".to_string())); - - let error = invoke_runtime(&other_plan, &runtime, RunRequest::text("hello fabric")) - .expect_err("runtime mismatch"); - - assert!( - error - .to_string() - .contains("runtime handle does not match run plan"), - "{error}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn invoke_runtime_rejects_mutated_runtime_environment() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let mut runtime = start_runtime(&plan).expect("runtime"); - runtime.environment.workspace = Some(root.join("other-workspace")); - - let error = invoke_runtime(&plan, &runtime, RunRequest::text("hello fabric")) - .expect_err("runtime mismatch"); - - assert!( - error - .to_string() - .contains("runtime handle does not match run plan"), - "{error}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn invoke_runtime_rejects_mutated_runtime_identity() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let mut runtime = start_runtime(&plan).expect("runtime"); - runtime.harness = "other-harness".to_string(); - - let error = invoke_runtime(&plan, &runtime, RunRequest::text("hello fabric")) - .expect_err("runtime mismatch"); - - assert!( - error - .to_string() - .contains("runtime handle does not match run plan"), - "{error}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn stop_runtime_rejects_runtime_handle_from_different_plan() { - let root = temp_process_agent_dir(); - let plan = resolve_run_plan(&root, None).expect("run plan"); - let runtime = start_runtime(&plan).expect("runtime"); - let mut other_plan = plan.clone(); - other_plan.agent_name = "other-agent".to_string(); - other_plan.effective_config.agent_name = "other-agent".to_string(); - - let error = stop_runtime(&other_plan, &runtime).expect_err("runtime mismatch"); - - assert!( - error - .to_string() - .contains("runtime handle does not match run plan"), - "{error}" - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn run_promotes_relay_artifacts_into_artifact_manifest() { - let root = std::env::temp_dir().join(format!( - "fabric-relay-artifact-manifest-test-{}", - std::process::id() - )); - let _ = fs::remove_dir_all(&root); - fs::create_dir_all(root.join("adapters/process")).expect("create adapters dir"); - let adapter_script = r#" -from pathlib import Path -import json -relay_dir = Path("artifacts/relay").resolve() -relay_dir.mkdir(parents=True, exist_ok=True) -atof = relay_dir / "events.atof.jsonl" -atif = relay_dir / "trajectory-runtime.atif.json" -atif_extra = relay_dir / "trajectory-child.atif.json" -atof.write_text('{"kind":"scope"}\n', encoding="utf-8") -atif.write_text('{"trajectory":true}', encoding="utf-8") -atif_extra.write_text('{"trajectory":"child"}', encoding="utf-8") -print(json.dumps({ - "response": "ok", - "relay_artifacts": [ - {"kind": "atof", "path": str(atof)}, - {"kind": "atif", "path": str(atif)}, - {"kind": "atif", "path": str(atif_extra)} - ] -})) -"#; - let agent_config = serde_json::json!({ - "schema_version": "fabric.agent/v1alpha1", - "metadata": { - "name": "relay-artifact-test-agent", - }, - "harness": { - "adapter_id": "acme.fabric.process", - "settings": { - "command": "python3", - "args": ["-c", adapter_script], - }, - }, - "models": { - "default": { - "provider": "test", - "model": "test-model", - }, - }, - "runtime": { - "input_schema": "text", - "output_schema": "text", - "artifacts": "./artifacts", - }, - }); - fs::write( - root.join("agent.yaml"), - serde_yaml::to_string(&agent_config).expect("serialize agent config"), - ) - .expect("write config"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - process_adapter_descriptor(), - ) - .expect("write adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - let result = run_plan(&plan, RunRequest::text("collect relay")).expect("run result"); - - assert_eq!(result.status, RunStatus::Succeeded); - let atof = result - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == "relay_atof" && artifact.kind == "atof") - .expect("ATOF artifact promoted to manifest"); - let atif = result - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == "relay_atif" && artifact.kind == "atif") - .expect("ATIF artifact promoted to manifest"); - let atif_extra = result - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == "relay_atif_2" && artifact.kind == "atif") - .expect("second ATIF artifact promoted to manifest with unique name"); - assert!(atof.path.ends_with("events.atof.jsonl")); - assert_eq!(atof.media_type.as_deref(), Some("application/x-ndjson")); - assert!(atif.path.ends_with("trajectory-runtime.atif.json")); - assert_eq!(atif.media_type.as_deref(), Some("application/json")); - assert!(atif_extra.path.ends_with("trajectory-child.atif.json")); - assert_eq!(atif_extra.media_type.as_deref(), Some("application/json")); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn adapter_runtime_context_contains_runtime_and_invocation_ids() { - let root = std::env::temp_dir().join(format!( - "fabric-runtime-context-test-{}", - std::process::id() - )); - let _ = fs::remove_dir_all(&root); - fs::create_dir_all(root.join("adapters/process")).expect("create adapters dir"); - fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: runtime-context-agent -harness: - adapter_id: acme.fabric.process - settings: - command: python3 - args: - - -c - - | - import json - import sys - payload = json.load(sys.stdin) - print(json.dumps(payload["runtime_context"], sort_keys=True)) - stdin_payload: fabric_request -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: text - artifacts: ./artifacts -"#, - ) - .expect("write config"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - process_adapter_descriptor(), - ) - .expect("write adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - let request = RunRequest::text("hello fabric"); - let result = run_plan(&plan, request).expect("run result"); - - assert_eq!(result.status, RunStatus::Succeeded); - assert!(result.output.get("session_id").is_none()); - assert_eq!( - result.output["runtime_id"], - Value::String(result.runtime_id.clone()) - ); - assert_eq!( - result.output["invocation_id"], - Value::String(result.invocation_id.clone()) - ); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn process_adapter_failure_returns_structured_error() { - let root = std::env::temp_dir().join(format!( - "fabric-process-adapter-failure-test-{}", - std::process::id() - )); - let _ = fs::remove_dir_all(&root); - fs::create_dir_all(root.join("adapters/process")).expect("create adapters dir"); - fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: process-failure-agent -harness: - adapter_id: acme.fabric.process - settings: - command: sh - args: - - -c - - | - echo adapter exploded >&2 - exit 7 -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: text - artifacts: ./artifacts -"#, - ) - .expect("write config"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - process_adapter_descriptor(), - ) - .expect("write adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - let result = run_plan(&plan, RunRequest::text("hello fabric")).expect("run result"); - - assert_eq!(result.status, RunStatus::Failed); - let error = result.error.as_ref().expect("structured error"); - assert_eq!(error.stage, ErrorStage::Invoke); - assert_eq!(error.code, "process_exit_nonzero"); - assert!(!error.retryable); - assert!(error.message.contains("adapter exploded")); - assert_eq!( - error.metadata.get("adapter_runner"), - Some(&Value::String("process".to_string())) - ); - assert_eq!(error.metadata.get("exit_code"), Some(&Value::from(7))); - assert_eq!(artifact_content(&result, "stderr"), "adapter exploded\n"); - - let _ = fs::remove_dir_all(root); - } - - fn python_settings() -> PythonAdapterSettings { - PythonAdapterSettings { - module: "test.adapter".to_string(), - python: None, - python_env: None, - args: Vec::new(), - cwd: None, - env: BTreeMap::new(), - } - } - - #[test] - fn python_command_uses_adapter_python_as_default_python_env() { - let root = Path::new("/config"); - let settings = python_settings(); - let command = resolve_python_command_with_env( - root, - &settings, - |name| (name == ADAPTER_PYTHON_ENV).then(|| OsString::from("venv/bin/python")), - |_| false, - None, - ); - - assert_eq!(command.path, root.join("venv/bin/python")); - assert_eq!(command.source, PythonSource::AdapterPythonEnv); - - let command = resolve_python_command_with_env(root, &settings, |_| None, |_| false, None); - assert_eq!(command.path, PathBuf::from(DEFAULT_PYTHON)); - assert_eq!(command.source, PythonSource::DefaultPython3); - } - - #[test] - fn explicit_python_settings_override_adapter_python() { - let root = Path::new("/config"); - let mut settings = python_settings(); - settings.python_env = Some("CUSTOM_PYTHON".to_string()); - let command = resolve_python_command_with_env( - root, - &settings, - |name| match name { - "CUSTOM_PYTHON" => Some(OsString::from("/custom/python")), - ADAPTER_PYTHON_ENV => Some(OsString::from("/adapter/python")), - _ => None, - }, - |_| false, - None, - ); - assert_eq!(command.path, PathBuf::from("/custom/python")); - assert_eq!( - command.source, - PythonSource::SettingEnv("CUSTOM_PYTHON".to_string()) - ); - - let command = resolve_python_command_with_env( - root, - &settings, - |name| (name == ADAPTER_PYTHON_ENV).then(|| OsString::from("/adapter/python")), - |_| false, - None, - ); - assert_eq!(command.path, PathBuf::from(DEFAULT_PYTHON)); - assert_eq!(command.source, PythonSource::DefaultPython3); - - settings.python = Some(PathBuf::from("/configured/python")); - let command = resolve_python_command_with_env( - root, - &settings, - |_| Some(OsString::from("/environment/python")), - |_| false, - None, - ); - assert_eq!(command.path, PathBuf::from("/configured/python")); - assert_eq!(command.source, PythonSource::Setting); - } - - #[test] - fn fallback_targets_active_virtualenv_even_when_missing() { - // VIRTUAL_ENV wins over bare python3 and is returned even when its - // interpreter is absent, so preflight reports a clear error instead of - // silently falling back to an unrelated python3. - let root = Path::new("/config"); - let settings = python_settings(); - let venv_python = Path::new("/venv").join(VENV_BIN_DIR).join(VENV_PYTHON); - let command = resolve_python_command_with_env( - root, - &settings, - |name| (name == VIRTUAL_ENV_ENV).then(|| OsString::from("/venv")), - |_| false, - None, - ); - - assert_eq!(command.path, venv_python); - assert_eq!(command.source, PythonSource::Virtualenv); - - let error = validate_python_command(&command) - .expect_err("missing virtualenv interpreter must fail preflight"); - assert!(matches!( - error, - FabricError::PythonInterpreterUnavailable { .. } - )); - } - - #[test] - fn empty_environment_values_are_ignored() { - let root = Path::new("/config"); - - // ADAPTER_PYTHON set but empty -> ignored, falls through to python3. - let command = resolve_python_command_with_env( - root, - &python_settings(), - |name| (name == ADAPTER_PYTHON_ENV).then(OsString::new), - |_| false, - None, - ); - assert_eq!(command.path, PathBuf::from(DEFAULT_PYTHON)); - assert_eq!(command.source, PythonSource::DefaultPython3); - - // python_env names a variable that is set but empty -> ignored. - let mut settings = python_settings(); - settings.python_env = Some("CUSTOM_PYTHON".to_string()); - let command = resolve_python_command_with_env( - root, - &settings, - |name| (name == "CUSTOM_PYTHON").then(OsString::new), - |_| false, - None, - ); - assert_eq!(command.path, PathBuf::from(DEFAULT_PYTHON)); - assert_eq!(command.source, PythonSource::DefaultPython3); - } - - #[cfg(windows)] - #[test] - fn windows_default_python_is_python_exe() { - // find_on_path joins each PATH entry with the bare name and stats it, so - // on Windows the fallback must name python.exe to resolve on disk. - assert_eq!(DEFAULT_PYTHON, "python.exe"); - let command = resolve_python_command_with_env( - Path::new("C:/config"), - &python_settings(), - |_| None, - |_| false, - None, - ); - assert_eq!(command.path, PathBuf::from("python.exe")); - assert_eq!(command.source, PythonSource::DefaultPython3); - } - - #[test] - fn fallback_uses_host_interpreter_next_to_executable() { - let root = Path::new("/config"); - let settings = python_settings(); - let exe = PathBuf::from("/opt/fabric/bin/nemo-fabric"); - let sibling = PathBuf::from("/opt/fabric/bin").join(VENV_PYTHON); - let expected = sibling.clone(); - let command = resolve_python_command_with_env( - root, - &settings, - |_| None, - move |path| path == expected.as_path(), - Some(exe), - ); - - assert_eq!(command.path, sibling); - assert_eq!(command.source, PythonSource::HostInterpreter); - } - - #[test] - fn adapter_python_preflight_requires_a_file() { - let root = std::env::temp_dir().join(new_id("fabric-adapter-python-test")); - fs::create_dir_all(&root).expect("create test directory"); - let interpreter = root.join("python"); - fs::write(&interpreter, "").expect("create interpreter file"); - - validate_python_command(&PythonCommand { - path: interpreter, - source: PythonSource::AdapterPythonEnv, - }) - .expect("file path should pass preflight"); - - let error = validate_python_command(&PythonCommand { - path: root.join("missing-python"), - source: PythonSource::AdapterPythonEnv, - }) - .expect_err("missing path should fail preflight"); - assert!(matches!( - error, - FabricError::PythonInterpreterUnavailable { .. } - )); - - let error = validate_python_command(&PythonCommand { - path: root.clone(), - source: PythonSource::AdapterPythonEnv, - }) - .expect_err("directory path should fail preflight"); - assert!(matches!( - error, - FabricError::PythonInterpreterUnavailable { .. } - )); - - let _ = fs::remove_dir_all(root); - } - - #[test] - fn preflight_rejects_missing_virtualenv_interpreter() { - // A resolved absolute interpreter that does not exist must fail preflight - // with a clear error instead of surfacing as a mid-run subprocess crash. - let error = validate_python_command(&PythonCommand { - path: Path::new("/venv").join(VENV_BIN_DIR).join(VENV_PYTHON), - source: PythonSource::Virtualenv, - }) - .expect_err("missing virtualenv interpreter should fail preflight"); - assert!(matches!( - error, - FabricError::PythonInterpreterUnavailable { .. } - )); - } - - #[test] - fn python_adapter_runs_hermes_shim() { - let plan = resolve_run_plan(fixture_agent_dir(), Some("env_local")).expect("run plan"); - let result = run_plan(&plan, RunRequest::text("review this")).expect("run result"); - - assert_eq!(result.status, RunStatus::Succeeded); - assert_eq!(result.adapter_kind, AdapterKind::Python); - assert_eq!( - result.output["harness"], - Value::String("hermes".to_string()) - ); - assert_eq!( - result.output["received"], - Value::String("review this".to_string()) - ); - assert_eq!( - result.metadata.get("adapter_runner"), - Some(&Value::String("python".to_string())) - ); - assert_eq!( - result.metadata.get("module"), - Some(&Value::String( - "nemo_fabric_test_adapters.hermes_shim.adapter".to_string() - )) - ); - } - - #[test] - fn run_collects_workspace_patch_artifact() { - let root = - std::env::temp_dir().join(format!("fabric-patch-artifact-test-{}", std::process::id())); - let _ = fs::remove_dir_all(&root); - let workspace = root.join("workspace"); - fs::create_dir_all(&workspace).expect("create workspace"); - fs::write(workspace.join("bug.py"), "def answer():\n return 41\n") - .expect("write baseline"); - run_command(&workspace, "git", &["init", "-q"]); - run_command(&workspace, "git", &["add", "bug.py"]); - fs::write( - root.join("agent.yaml"), - r#"schema_version: fabric.agent/v1alpha1 -metadata: - name: patch-test-agent -harness: - adapter_id: acme.fabric.process - settings: - command: python3 - args: - - -c - - | - from pathlib import Path - Path("bug.py").write_text("def answer():\n return 42\n") - Path("notes.txt").write_text("fixed by fabric\n") - print('patched') -models: - default: - provider: test - model: test-model -runtime: - input_schema: text - output_schema: text - artifacts: ./artifacts -environment: - provider: local - workspace: ./workspace - artifacts: ./artifacts -"#, - ) - .expect("write config"); - fs::create_dir_all(root.join("adapters/process")).expect("create adapters dir"); - fs::write( - root.join("adapters/process/fabric-adapter.json"), - process_adapter_descriptor(), - ) - .expect("write adapter descriptor"); - - let plan = resolve_run_plan(&root, None).expect("run plan"); - let result = run_plan(&plan, RunRequest::text("fix the bug")).expect("run result"); - - assert_eq!(result.status, RunStatus::Succeeded); - let patch_artifact = result - .artifacts - .artifacts - .iter() - .find(|artifact| artifact.name == "workspace_patch") - .expect("workspace patch artifact"); - let patch = fs::read_to_string(&patch_artifact.path).expect("read patch"); - assert!(patch.contains("- return 41")); - assert!(patch.contains("+ return 42")); - assert!(patch.contains("new file mode")); - assert!(patch.contains("notes.txt")); - assert!(patch.contains("+fixed by fabric")); - - let _ = fs::remove_dir_all(root); - } -} diff --git a/crates/fabric-core/src/schema.rs b/crates/fabric-core/src/schema.rs index b5ea09354..f248466f5 100644 --- a/crates/fabric-core/src/schema.rs +++ b/crates/fabric-core/src/schema.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; use schemars::schema_for; use serde_json::Value; -use crate::config::{AdapterDescriptor, EffectiveConfig, FabricConfig, ProfileConfig, RunPlan}; +use crate::config::{AdapterDescriptor, FabricConfig, RunPlan}; use crate::error::{FabricError, Result}; use crate::runtime::{ AdapterInvocation, ArtifactManifest, EnvironmentHandle, ErrorInfo, FabricEvent, @@ -19,14 +19,10 @@ use crate::runtime::{ /// Public schema snapshots generated by Fabric. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SchemaName { - /// Base `agent.yaml` schema. + /// Complete typed Fabric config schema. Agent, - /// Profile overlay schema. - Profile, /// Adapter descriptor schema. AdapterDescriptor, - /// Effective merged config schema. - EffectiveConfig, /// Resolved run plan schema. RunPlan, /// Adapter-facing invocation payload schema. @@ -53,11 +49,9 @@ pub enum SchemaName { impl SchemaName { /// All public schemas in stable output order. - pub const ALL: [Self; 15] = [ + pub const ALL: [Self; 13] = [ Self::Agent, - Self::Profile, Self::AdapterDescriptor, - Self::EffectiveConfig, Self::RunPlan, Self::AdapterInvocation, Self::RuntimeContext, @@ -75,9 +69,7 @@ impl SchemaName { pub fn as_str(self) -> &'static str { match self { Self::Agent => "agent", - Self::Profile => "profile", Self::AdapterDescriptor => "adapter-descriptor", - Self::EffectiveConfig => "effective-config", Self::RunPlan => "run-plan", Self::AdapterInvocation => "adapter-invocation", Self::RuntimeContext => "runtime-context", @@ -101,9 +93,7 @@ impl SchemaName { pub fn parse(value: &str) -> Result { match value { "agent" => Ok(Self::Agent), - "profile" => Ok(Self::Profile), "adapter-descriptor" | "adapter_descriptor" => Ok(Self::AdapterDescriptor), - "effective-config" | "effective_config" => Ok(Self::EffectiveConfig), "run-plan" | "run_plan" => Ok(Self::RunPlan), "adapter-invocation" | "adapter_invocation" => Ok(Self::AdapterInvocation), "runtime-context" | "runtime_context" => Ok(Self::RuntimeContext), @@ -130,9 +120,7 @@ impl SchemaName { pub fn generate_schema(schema: SchemaName) -> Result { match schema { SchemaName::Agent => to_value(schema_for!(FabricConfig)), - SchemaName::Profile => to_value(schema_for!(ProfileConfig)), SchemaName::AdapterDescriptor => to_value(schema_for!(AdapterDescriptor)), - SchemaName::EffectiveConfig => to_value(schema_for!(EffectiveConfig)), SchemaName::RunPlan => to_value(schema_for!(RunPlan)), SchemaName::AdapterInvocation => to_value(schema_for!(AdapterInvocation)), SchemaName::RuntimeContext => to_value(schema_for!(RuntimeContext)), diff --git a/crates/fabric-python/src/lib.rs b/crates/fabric-python/src/lib.rs index bd8bb574a..1362f4803 100644 --- a/crates/fabric-python/src/lib.rs +++ b/crates/fabric-python/src/lib.rs @@ -6,10 +6,8 @@ use std::path::PathBuf; use nemo_fabric_core::{ - FabricConfig, ProfileConfig, ResolveContext, RunPlan, RunRequest, RuntimeHandle, doctor_plan, - load_fabric_document, resolve_effective_config_from_config, - resolve_effective_config_with_profiles, resolve_run_plan_from_config, - resolve_run_plan_with_profiles, run_plan, + FabricConfig, ResolveContext, RunPlan, RunRequest, RuntimeHandle, doctor_plan, + resolve_run_plan_from_config, run_plan, }; use pyo3::exceptions::PyRuntimeError; use pyo3::prelude::*; @@ -20,129 +18,38 @@ fn version() -> PyResult { Ok(nemo_fabric_core::version().to_string()) } -/// Validate an agent directory, manifest, or profile config. +/// Resolve typed config JSON into a runnable plan and return JSON. #[pyfunction] -fn validate(path: String) -> PyResult { - load_fabric_document(&path).map_err(to_py_error)?; - Ok(format!("validated {path}")) -} - -/// Resolve and return the effective Fabric config as JSON. -#[pyfunction] -#[pyo3(signature = (path, profile=None))] -fn inspect(py: Python<'_>, path: String, profile: Option>) -> PyResult { - let profiles = profile_values(py, profile)?; - let effective_config = - resolve_effective_config_with_profiles(path, &profiles).map_err(to_py_error)?; - to_json(&effective_config) -} - -/// Resolve typed config/profile JSON into effective config and return JSON. -#[pyfunction] -#[pyo3(signature = (config_json, profiles_json=None, base_dir=None))] -fn resolve_config( - config_json: String, - profiles_json: Option, - base_dir: Option, -) -> PyResult { +#[pyo3(signature = (config_json, base_dir=None))] +fn plan_config(py: Python<'_>, config_json: String, base_dir: Option) -> PyResult { let config = parse_config(config_json)?; - let profiles = parse_profiles(profiles_json)?; - let effective = - resolve_effective_config_from_config(config, &profiles, resolve_context(base_dir)) - .map_err(to_py_error)?; - to_json(&effective) -} - -/// Resolve an agent/profile into a runnable plan and return JSON. -#[pyfunction] -#[pyo3(signature = (path, profile=None))] -fn plan(py: Python<'_>, path: String, profile: Option>) -> PyResult { - let profiles = profile_values(py, profile)?; - let plan = resolve_run_plan_with_profiles(path, &profiles).map_err(to_py_error)?; - to_json(&plan) -} - -/// Resolve typed config/profile JSON into a runnable plan and return JSON. -#[pyfunction] -#[pyo3(signature = (config_json, profiles_json=None, base_dir=None))] -fn plan_config( - config_json: String, - profiles_json: Option, - base_dir: Option, -) -> PyResult { - let config = parse_config(config_json)?; - let profiles = parse_profiles(profiles_json)?; - let plan = resolve_run_plan_from_config(config, &profiles, resolve_context(base_dir)) + let plan = py + .detach(|| resolve_run_plan_from_config(config, resolve_context(base_dir))) .map_err(to_py_error)?; to_json(&plan) } -/// Diagnose a resolved agent/profile without installing or running it. -#[pyfunction] -#[pyo3(signature = (path, profile=None))] -fn doctor(py: Python<'_>, path: String, profile: Option>) -> PyResult { - let profiles = profile_values(py, profile)?; - let plan = resolve_run_plan_with_profiles(path, &profiles).map_err(to_py_error)?; - to_json(&doctor_plan(&plan)) -} - -/// Diagnose typed config/profile JSON without installing or running it. +/// Diagnose typed config JSON without installing or running it. #[pyfunction] -#[pyo3(signature = (config_json, profiles_json=None, base_dir=None))] +#[pyo3(signature = (config_json, base_dir=None))] fn doctor_config( + py: Python<'_>, config_json: String, - profiles_json: Option, base_dir: Option, ) -> PyResult { let config = parse_config(config_json)?; - let profiles = parse_profiles(profiles_json)?; - let plan = resolve_run_plan_from_config(config, &profiles, resolve_context(base_dir)) + let plan = py + .detach(|| resolve_run_plan_from_config(config, resolve_context(base_dir))) .map_err(to_py_error)?; to_json(&doctor_plan(&plan)) } -/// Run an agent/profile through its Fabric adapter and return JSON. +/// Run typed config JSON through its Fabric adapter and return JSON. #[pyfunction] -#[pyo3(signature = (path, profile=None, input_text=None, input_file=None, request_json=None, request_file=None))] -fn run( - py: Python<'_>, - path: String, - profile: Option>, - input_text: Option, - input_file: Option, - request_json: Option, - request_file: Option, -) -> PyResult { - let profiles = profile_values(py, profile)?; - let plan = resolve_run_plan_with_profiles(path, &profiles).map_err(to_py_error)?; - let request = match (request_file, request_json, input_file) { - (Some(path), None, None) => std::fs::read_to_string(PathBuf::from(&path)) - .map_err(|error| PyRuntimeError::new_err(format!("failed to read {path}: {error}"))) - .and_then(parse_run_request)?, - (None, Some(json), None) => parse_run_request(json)?, - (None, None, Some(path)) => { - let input = std::fs::read_to_string(PathBuf::from(&path)).map_err(|error| { - PyRuntimeError::new_err(format!("failed to read {path}: {error}")) - })?; - RunRequest::text(input) - } - (None, None, None) => RunRequest::text(input_text.unwrap_or_default()), - _ => { - return Err(PyRuntimeError::new_err( - "request_file, request_json, and input_file are mutually exclusive", - )); - } - }; - let result = run_plan(&plan, request).map_err(to_py_error)?; - to_json(&result) -} - -/// Run typed config/profile JSON through its Fabric adapter and return JSON. -#[pyfunction] -#[pyo3(signature = (config_json, profiles_json=None, base_dir=None, input_text=None, input_file=None, request_json=None, request_file=None))] +#[pyo3(signature = (config_json, base_dir=None, input_text=None, input_file=None, request_json=None, request_file=None))] fn run_config( + py: Python<'_>, config_json: String, - profiles_json: Option, base_dir: Option, input_text: Option, input_file: Option, @@ -150,28 +57,31 @@ fn run_config( request_file: Option, ) -> PyResult { let config = parse_config(config_json)?; - let profiles = parse_profiles(profiles_json)?; - let plan = resolve_run_plan_from_config(config, &profiles, resolve_context(base_dir)) + let plan = py + .detach(|| resolve_run_plan_from_config(config, resolve_context(base_dir))) .map_err(to_py_error)?; - let request = match (request_file, request_json, input_file) { - (Some(path), None, None) => std::fs::read_to_string(PathBuf::from(&path)) + let request = match (request_file, request_json, input_file, input_text) { + (Some(path), None, None, None) => std::fs::read_to_string(PathBuf::from(&path)) .map_err(|error| PyRuntimeError::new_err(format!("failed to read {path}: {error}"))) .and_then(parse_run_request)?, - (None, Some(json), None) => parse_run_request(json)?, - (None, None, Some(path)) => { + (None, Some(json), None, None) => parse_run_request(json)?, + (None, None, Some(path), None) => { let input = std::fs::read_to_string(PathBuf::from(&path)).map_err(|error| { PyRuntimeError::new_err(format!("failed to read {path}: {error}")) })?; RunRequest::text(input) } - (None, None, None) => RunRequest::text(input_text.unwrap_or_default()), + (None, None, None, Some(text)) => RunRequest::text(text), + (None, None, None, None) => RunRequest::text(""), _ => { return Err(PyRuntimeError::new_err( - "request_file, request_json, and input_file are mutually exclusive", + "input_text, input_file, request_json, and request_file are mutually exclusive", )); } }; - let result = run_plan(&plan, request).map_err(to_py_error)?; + let result = py + .detach(|| run_plan(&plan, request)) + .map_err(to_py_error)?; to_json(&result) } @@ -216,14 +126,8 @@ fn stop_runtime(py: Python<'_>, plan_json: String, runtime_json: String) -> PyRe #[pymodule] fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(version, m)?)?; - m.add_function(wrap_pyfunction!(validate, m)?)?; - m.add_function(wrap_pyfunction!(inspect, m)?)?; - m.add_function(wrap_pyfunction!(resolve_config, m)?)?; - m.add_function(wrap_pyfunction!(plan, m)?)?; m.add_function(wrap_pyfunction!(plan_config, m)?)?; - m.add_function(wrap_pyfunction!(doctor, m)?)?; m.add_function(wrap_pyfunction!(doctor_config, m)?)?; - m.add_function(wrap_pyfunction!(run, m)?)?; m.add_function(wrap_pyfunction!(run_config, m)?)?; m.add_function(wrap_pyfunction!(start_runtime, m)?)?; m.add_function(wrap_pyfunction!(invoke_runtime, m)?)?; @@ -242,40 +146,14 @@ fn to_py_error(error: nemo_fabric_core::FabricError) -> PyErr { PyRuntimeError::new_err(error.to_string()) } -fn profile_values(py: Python<'_>, profile: Option>) -> PyResult> { - let Some(profile) = profile else { - return Ok(Vec::new()); - }; - let profile = profile.bind(py); - if profile.is_none() { - return Ok(Vec::new()); - } - if let Ok(profile) = profile.extract::() { - return Ok(vec![profile]); - } - if let Ok(profiles) = profile.extract::>() { - return Ok(profiles); - } - Err(PyRuntimeError::new_err( - "profile must be None, a string, or a sequence of strings", - )) -} - fn resolve_context(base_dir: Option) -> ResolveContext { - ResolveContext::from_agent_root(base_dir.unwrap_or_else(|| ".".to_string())) + ResolveContext::new(base_dir.unwrap_or_else(|| ".".to_string())) } fn parse_config(contents: String) -> PyResult { serde_json::from_str(&contents).map_err(|error| PyRuntimeError::new_err(error.to_string())) } -fn parse_profiles(contents: Option) -> PyResult> { - let Some(contents) = contents else { - return Ok(Vec::new()); - }; - serde_json::from_str(&contents).map_err(|error| PyRuntimeError::new_err(error.to_string())) -} - fn parse_run_request(contents: String) -> PyResult { serde_json::from_str(&contents).map_err(|error| PyRuntimeError::new_err(error.to_string())) } diff --git a/docs/about-nemo-fabric/overview.mdx b/docs/about-nemo-fabric/overview.mdx index 11dfce02b..324dca0e2 100644 --- a/docs/about-nemo-fabric/overview.mdx +++ b/docs/about-nemo-fabric/overview.mdx @@ -16,13 +16,12 @@ configuration, selects an adapter, drives the runtime lifecycle, and returns normalized evidence without leaking harness-specific control code into the caller. -## What NeMo Fabric gives you +## What NeMo Fabric Gives You - - Use a versioned `agent.yaml` package or construct the same typed - `FabricConfig` in Python. Applications create variants from typed copies; - portable file packages can use ordered profiles. + + Construct a complete, versioned `FabricConfig` in Python. Applications + create variants with ordinary functions and typed copies. Plan and invoke different harnesses through one Rust core, CLI, and Python @@ -38,12 +37,12 @@ into the caller. -## How NeMo Fabric fits +## How NeMo Fabric Fits ```text Application or evaluation harness | - | Python SDK or `fabric` CLI + | Python SDK or nemo-fabric experimentation CLI v NeMo Fabric Rust core config -> plan -> lifecycle @@ -56,12 +55,13 @@ Hermes | Codex SDK | custom harness RunResult + artifacts + events + telemetry references ``` -The CLI and Python SDK are separate interfaces over the same core. File-backed -and typed configs converge on the same resolved config and run-plan contracts. -Adapters own harness-specific preparation and invocation; consumers own the -request and the use of returned evidence. +The experimentation CLI and its catalogs live in the Rust `fabric-cli` crate +and are installed separately from the Python SDK. Built-in presets and +maintained examples produce a complete `FabricConfig` before using the same +run-plan contract. Adapters own harness-specific preparation and invocation; +consumers own the request and returned evidence. -## Quick start +## Quick Start Install `just` 1.50.0+ if it is not already available. @@ -85,8 +85,7 @@ uv venv -p 3.13 --seed .venv source .venv/bin/activate ``` -Install the Python SDK with its native binding and the CLI from a source -checkout: +Build the Python SDK and install the Rust CLI from a source checkout: ```bash just build-all @@ -122,26 +121,24 @@ contains the complete Hermes environment recipe. Refer to the [Python SDK guide](/nemo/fabric/sdk/python-sdk) for planning, diagnostics, typed requests, and multi-turn runtime examples. -## Choose your interface +## Choose Your Interface | Interface | Use it when | Start with | | --- | --- | --- | | Python SDK | Your application owns job config, runtime lifecycle, or multi-turn state | [Client API](/reference/api/python-library-reference/client) | | Runtime API | You need multiple ordered turns over one live harness runtime | [Runtime](/reference/api/python-library-reference/runtime) | -| `fabric` CLI | You are validating packages, debugging profiles, or running reproducible local/CI jobs | `fabric validate`, `plan`, `doctor`, `run`, and `chat` | +| `nemo-fabric` CLI | You are experimenting with harnesses, running maintained examples, or troubleshooting configs | [Experimentation CLI](/experimentation/cli) | | JSON Schema | You are building editors, validation, code generation, or another language binding | Committed schemas in the [repository](https://github.com/NVIDIA/NeMo-Fabric/tree/main/schemas) | -Use `agent.yaml` when the agent package is the portable artifact. Use -`FabricConfig` when a platform already owns a larger job or deployment object -and wants to pass only its NeMo Fabric slice in memory. +Use `FabricConfig` as the canonical configuration contract. CLI selectors +obtain complete typed configs from built-in presets or maintained examples. -## Core workflow +## Core Workflow -1. **Configure** an agent package or typed `FabricConfig` with a harness adapter, +1. **Configure** a typed `FabricConfig` with a harness adapter, environment, models, tools, skills, MCP, and telemetry. 2. **Create variants** from deep copies to vary harness, model, environment, or - observability settings without mutating the base config. File-backed - packages may instead apply ordered profiles. + observability settings without mutating the base config. 3. **Plan and diagnose** to resolve the adapter and check capabilities and requirements before spending work on a runtime. 4. **Run or start a runtime** through the shared start, invoke, and stop @@ -149,7 +146,7 @@ and wants to pass only its NeMo Fabric slice in memory. 5. **Consume evidence** from `RunResult`: output, structured failure details, artifacts, events, and telemetry references. -## Next steps +## Next Steps + The `nemo-fabric` CLI is an experimentation surface. Use it for quick harness + probes, maintained examples, planning, and diagnostics. Applications and + services should construct `FabricConfig` through a language API directly. + + +The command implementation, built-in presets, and maintained example +definitions live in the Rust `fabric-cli` crate. +The `nemo-fabric` CLI is installed separately from the `nemo-fabric-runtime` +Python SDK. Installing the Python SDK does not install the CLI. + +## Install the CLI + +The CLI currently builds from a NeMo Fabric source checkout. Install it with +Cargo: + +```bash +cargo install --path crates/fabric-cli --locked +``` + +Set up the checkout's Python environment when you want to run presets backed +by Python adapters: + +```bash +uv sync --all-groups --all-extras +export ADAPTER_PYTHON="$PWD/.venv/bin/python" +``` + +`ADAPTER_PYTHON` tells the Rust runtime which interpreter contains the selected +adapter and harness. Use an absolute path if you run `nemo-fabric` outside the +checkout. + +Verify that the executable is available: + +```bash +nemo-fabric --version +``` + +If the command is not found, add Cargo's binary directory to your `PATH`: + +```bash +export PATH="$HOME/.cargo/bin:$PATH" +``` + +When developing the CLI, run the workspace binary without installing it: + +```bash +cargo run -p nemo-fabric-cli -- preset list +``` + +Installing the Python SDK does not install the CLI. Adapter packages and +credentials are also separate requirements for presets that launch an external +harness. Use the credential-free `scripted` preset to verify the CLI by itself. + +## Experiment With Presets + +Presets are complete, embedded `FabricConfig` values intended for quick +experiments: + +| Preset | Harness | Default model | Endpoint | +| --- | --- | --- | --- | +| `scripted` | Deterministic test adapter | None | None | +| `hermes` | Hermes Agent | `nvidia/nemotron-3-nano-30b-a3b` | NVIDIA API Catalog | +| `claude` | Claude Code | `aws/anthropic/claude-opus-4-5` | `NVIDIA_FRONTIER_BASE_URL` | +| `codex` | Codex | `azure/openai/gpt-5.4` | `NVIDIA_FRONTIER_BASE_URL` | +| `deepagents` | LangChain Deep Agents | `nvidia/nemotron-3-nano-30b-a3b` | NVIDIA API Catalog | + +The `scripted` preset does not call a model. It returns a deterministic response +through the same Fabric runtime and adapter contract, which makes it useful for +checking CLI installation, request flow, and result formatting without network +access or credentials. + +The four external-harness presets use `NVIDIA_API_KEY`. Hermes and Deep Agents +target the public NVIDIA API Catalog at `https://integrate.api.nvidia.com/v1`. +Export the credential before running them: + +```bash +export NVIDIA_API_KEY="..." +``` + +Claude and Codex require the base URL for an NVIDIA endpoint that serves the +selected frontier model and supports the harness protocol. Set it explicitly: + +```bash +export NVIDIA_FRONTIER_BASE_URL="https://your-frontier-endpoint.example/v1" +``` + +Fabric does not provide a default frontier URL because the correct endpoint +depends on the model and the user's access. + +List the complete configurations maintained by the CLI: + +```bash +nemo-fabric preset list +``` + +Inspect a preset's purpose and required environment variables: + +```bash +nemo-fabric preset show hermes +``` + +Resolve the preset to inspect its complete run plan, including its typed +configuration and adapter descriptor: + +```bash +nemo-fabric plan --preset hermes +``` + +To display only the authored `FabricConfig`, filter the plan with `jq`: + +```bash +nemo-fabric plan --preset hermes | jq '.config' +``` + +Diagnose adapter availability, credentials, and other requirements before +running the preset: + +```bash +nemo-fabric doctor --preset hermes +``` + +Run the preset with an input: + +```bash +nemo-fabric run --preset hermes --input "Say hello" +``` + +Override the preset's default model and temperature for a quick experiment: + +```bash +nemo-fabric run --preset hermes \ + --model nvidia/meta/llama-3.3-70b-instruct \ + --temperature 0.2 \ + --input "Say hello" +``` + +These flags preserve the preset's provider, credential environment variable, +endpoint, and harness settings. Use a model that is available from the preset's +provider and compatible with the selected harness. For example, a Claude preset +still requires an Anthropic Messages-compatible model, while a Codex preset +requires a Responses-compatible model. The `plan` and `doctor` commands accept +the same overrides. + +## Experiment With Examples + +List the maintained workflows and inspect an example's available variants: + +```bash +nemo-fabric example list +nemo-fabric example show code-review +``` + +Run an example with its default variant: + +```bash +nemo-fabric run --example code-review --input "Review the workspace" +``` + +Select a different maintained harness variant when you want to compare its +behavior: + +```bash +nemo-fabric run --example code-review --variant hermes \ + --input "Review the workspace" +``` + +The `plan` and `doctor` commands accept the same `--example` and `--variant` +selectors. + +## Scaffold Examples + +Generate ordinary application code when you want to customize an example. The +default `scripted` variant is credential-free: + +```bash +nemo-fabric example init code-review my-agent --language python +nemo-fabric example init code-review my-agent-rs --language rust +``` + +Add a selector such as `--variant hermes` to scaffold a non-default variant. A +non-default variant requires its adapter package and credentials. + +### Run a Python Scaffold + +Create and activate a virtual environment, install the generated application, +and run its launcher: + +```bash +cd my-agent +python -m venv .venv +source .venv/bin/activate +python -m pip install -e . +python main.py "Review the workspace" +``` + +The Python scaffold constructs `FabricConfig` and calls the Python SDK +directly. + +### Run a Rust Scaffold + +Build and run the generated Rust application: + +```bash +cd my-agent-rs +cargo run -- "Review the workspace" +``` + +The Rust scaffold constructs `FabricConfig` and calls `fabric-core` directly. +Neither scaffold is loaded back into the central CLI. + +## CLI Boundaries + +The CLI has the following boundaries: + +- Every preset and example variant constructs a complete typed `FabricConfig`. +- Examples reuse preset constructors and one shared workspace and skill asset + tree; Python and Rust launchers do not duplicate those definitions. +- Fabric does not discover or persist YAML, TOML, or JSON agent configuration. +- JSON request payloads and harness-generated files are runtime inputs and + outputs, not Fabric configuration sources. +- The CLI is not an application API, scheduler, evaluation framework, or + production deployment interface. + +Current lifecycle commands are `plan`, `doctor`, and `run`. Use `preset list` +and `preset show` to discover presets. Use `example list` and `example show` to +discover examples. diff --git a/docs/getting-started/install.mdx b/docs/getting-started/install.mdx index 301569496..c821cb0c2 100644 --- a/docs/getting-started/install.mdx +++ b/docs/getting-started/install.mdx @@ -15,8 +15,8 @@ NeMo Fabric is separated into two distinct parts: ### Supported Python Versions - Python version 3.11 - 3.14 -NeMo Fabric supports Python versions 3.11-3.14, however some of the integrations and adapters may have -additional requirements. Specifically the Hermes adapter doesn't support Python 3.14 yet, and the Harbor +NeMo Fabric supports Python versions 3.11-3.14, however some of the integrations and adapters may have +additional requirements. Specifically the Hermes adapter doesn't support Python 3.14 yet, and the Harbor integration requires Python 3.12 or later. ### Installing NeMo Fabric Runtime @@ -24,7 +24,7 @@ integration requires Python 3.12 or later. Install the NeMo Fabric Runtime: ```bash -pip install "nemo-fabric[runtime]" +pip install nemo-fabric ``` ### Installing the NeMo Fabric Adapters diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx index 9175445e3..2e1470764 100644 --- a/docs/getting-started/quickstart.mdx +++ b/docs/getting-started/quickstart.mdx @@ -13,14 +13,14 @@ Create a Python virtual environment and install NeMo Fabric with Hermes Agent an ```bash python -m venv .venv source .venv/bin/activate -pip install "nemo-fabric[hermes, runtime]" +pip install "nemo-fabric[adapters-hermes]" ``` Refer to [the installation guide](https://github.com/NVIDIA/NeMo-Fabric#installation) for more details. ## Obtaining API Keys -The following code example uses an NVIDIA hosted model, and requires an NVIDIA API key defined with the `NVIDIA_API_KEY` +The following code example uses an NVIDIA-hosted model and requires an NVIDIA API key defined with the `NVIDIA_API_KEY` environment variable. An API key can be obtained by creating an account on [`build.nvidia.com`](https://build.nvidia.com/). ## Run a Simple Agent diff --git a/docs/index.yml b/docs/index.yml index 025d6bb2f..5db031d2e 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -14,6 +14,10 @@ navigation: path: ./getting-started/install.mdx - page: Quickstart path: ./getting-started/quickstart.mdx + - section: Experimentation + contents: + - page: CLI + path: ./experimentation/cli.mdx - section: SDK contents: - page: Python SDK diff --git a/docs/integrations/codex.mdx b/docs/integrations/codex.mdx index 30a5f9dcb..9162c7e48 100644 --- a/docs/integrations/codex.mdx +++ b/docs/integrations/codex.mdx @@ -75,6 +75,11 @@ starts the Relay gateway as a supervised sidecar and directs the Codex SDK's built-in OpenAI provider through that gateway. The SDK still obtains credentials from the selected Codex authentication mode. +Relay-enabled Codex runs require `models.default.provider` to be `openai`. +The custom `nvidia` provider uses its configured NVIDIA Responses endpoint and +does not support the built-in provider redirect that Relay requires. Use the +`nvidia` provider without Relay. + NeMo Fabric supplies Relay configuration to the SDK for only the current request. It does not copy the Codex credential store into Relay configuration or persist credentials in Relay artifacts. diff --git a/docs/reference/api/python-library-reference/index.md b/docs/reference/api/python-library-reference/index.md index a9194c666..8d580c39c 100644 --- a/docs/reference/api/python-library-reference/index.md +++ b/docs/reference/api/python-library-reference/index.md @@ -24,13 +24,11 @@ SPDX-License-Identifier: Apache-2.0 */} - [`models.EnvironmentConfig`](./nemo_fabric.models.md#class-environmentconfig): Execution environment configuration supplied by the consumer. - [`models.FabricBaseModel`](./nemo_fabric.models.md#class-fabricbasemodel): Base class for SDK-facing Pydantic models. - [`models.FabricConfig`](./nemo_fabric.models.md#class-fabricconfig): SDK-facing typed Fabric agent configuration. -- [`models.FabricProfileConfig`](./nemo_fabric.models.md#class-fabricprofileconfig): Typed profile overlay used when a Python caller wants file-style overlays. - [`models.HarnessConfig`](./nemo_fabric.models.md#class-harnessconfig): Harness adapter selection plus adapter-owned settings. - [`models.McpConfig`](./nemo_fabric.models.md#class-mcpconfig): MCP capability configuration. - [`models.McpServerConfig`](./nemo_fabric.models.md#class-mcpserverconfig): MCP server configuration. - [`models.MetadataConfig`](./nemo_fabric.models.md#class-metadataconfig): Human-readable agent identity. - [`models.ModelConfig`](./nemo_fabric.models.md#class-modelconfig): Model alias configuration. -- [`models.ProfileRegistryConfig`](./nemo_fabric.models.md#class-profileregistryconfig): Profile discovery config for portable file-backed agent packages. - [`models.RelayAtifConfig`](./nemo_fabric.models.md#class-relayatifconfig): NeMo Relay ATIF export configuration. - [`models.RelayAtofConfig`](./nemo_fabric.models.md#class-relayatofconfig): NeMo Relay ATOF export configuration. - [`models.RelayAtofEndpointConfig`](./nemo_fabric.models.md#class-relayatofendpointconfig): NeMo Relay ATOF remote endpoint configuration. @@ -52,7 +50,6 @@ SPDX-License-Identifier: Apache-2.0 */} - [`types.ArtifactRef`](./nemo_fabric.types.md#class-artifactref): Reference to one artifact produced by a run. - [`types.DoctorCheck`](./nemo_fabric.types.md#class-doctorcheck): One diagnostic check in a ``DoctorReport``. - [`types.DoctorReport`](./nemo_fabric.types.md#class-doctorreport): Aggregate preflight diagnostics for a resolved run plan. -- [`types.EffectiveConfig`](./nemo_fabric.types.md#class-effectiveconfig): Immutable result of config loading and ordered profile application. - [`types.ErrorInfo`](./nemo_fabric.types.md#class-errorinfo): Structured failure returned inside a normalized ``RunResult``. - [`types.FabricEvent`](./nemo_fabric.types.md#class-fabricevent): One normalized lifecycle or invocation event. - [`types.RunOutput`](./nemo_fabric.types.md#class-runoutput): Normalized adapter output. @@ -62,7 +59,7 @@ SPDX-License-Identifier: Apache-2.0 */} - [`types.RuntimeHandle`](./nemo_fabric.types.md#class-runtimehandle): Opaque identity and binding for one started runtime. - [`types.TelemetryRef`](./nemo_fabric.types.md#class-telemetryref): Reference to external or persisted telemetry for a run. - [`errors.FabricCapabilityError`](./nemo_fabric.errors.md#class-fabriccapabilityerror): Operation rejected by resolved runtime capabilities or implementation status. -- [`errors.FabricConfigError`](./nemo_fabric.errors.md#class-fabricconfigerror): Invalid SDK input, request shape, profile stack, or resolved config. +- [`errors.FabricConfigError`](./nemo_fabric.errors.md#class-fabricconfigerror): Invalid SDK input, request shape, factory, or resolved config. - [`errors.FabricError`](./nemo_fabric.errors.md#class-fabricerror): Base class for structured SDK-level Fabric errors. - [`errors.FabricNativeUnavailableError`](./nemo_fabric.errors.md#class-fabricnativeunavailableerror): SDK call requires the PyO3 extension, but it is not installed or importable. - [`errors.FabricRuntimeError`](./nemo_fabric.errors.md#class-fabricruntimeerror): Failure while starting, invoking, stopping, or otherwise driving a runtime. diff --git a/docs/reference/api/python-library-reference/nemo_fabric.client.md b/docs/reference/api/python-library-reference/nemo_fabric.client.md index 8ea962d20..59d911069 100644 --- a/docs/reference/api/python-library-reference/nemo_fabric.client.md +++ b/docs/reference/api/python-library-reference/nemo_fabric.client.md @@ -17,9 +17,9 @@ Native Python client for resolving and running NeMo Fabric agents. ## class `Fabric` Primary Python entrypoint for NeMo Fabric. -The client accepts either a path-backed agent package or a typed ``FabricConfig``. Path-backed sources select profiles by name; typed sources accept ordered ``FabricProfileConfig`` values and may use ``base_dir`` to resolve relative paths. All inspection and execution APIs return typed, read-only mapping models. +Every lifecycle method accepts a complete, typed ``FabricConfig`` plus an optional ``base_dir`` used to resolve relative paths. Compose variants in Python before calling the SDK. The ``doctor()``, ``plan()``, and ``run()`` results are typed, read-only mapping models. ``start_runtime()`` returns an active ``Runtime`` handle. -``Fabric`` is native-only. The ``fabric`` CLI is a separate public surface over the same Rust core; SDK calls raise ``FabricNativeUnavailableError`` when the native extension is not installed. +``Fabric`` uses the native Rust extension. SDK calls raise ``FabricNativeUnavailableError`` when the native extension is not installed. See the Getting Started overview for runnable one-shot, typed-config, and multi-turn examples. @@ -33,9 +33,8 @@ See the Getting Started overview for runnable one-shot, typed-config, and multi- ```python doctor( - agent: 'AgentSource', - profiles: 'PathProfiles | TypedProfiles | None' = None, - base_dir: 'PathSource | None' = None + config: 'FabricConfig', + base_dir: 'str | PathLike[str] | None' = None ) → DoctorReport ``` @@ -47,9 +46,8 @@ Doctor checks the resolved adapter, capability mappings, and declared environmen **Args:** - - `agent`: Agent-package directory or config-file path, or a typed ``FabricConfig``. - - `profiles`: One profile name or an ordered sequence of names for a path-backed source. For a typed source, an ordered sequence of ``FabricProfileConfig`` values. - - `base_dir`: Base directory for resolving relative paths in a typed config. Valid only when ``agent`` is a typed config source. + - `config`: Complete typed ``FabricConfig``. + - `base_dir`: Base directory for resolving relative paths. @@ -70,71 +68,32 @@ Doctor checks the resolved adapter, capability mappings, and declared environmen ```python plan( - agent: 'AgentSource', - profiles: 'PathProfiles | TypedProfiles | None' = None, - base_dir: 'PathSource | None' = None + config: 'FabricConfig', + base_dir: 'str | PathLike[str] | None' = None ) → RunPlan ``` -Resolve an agent source into an immutable execution plan. +Resolve a complete typed configuration into an immutable execution plan. -Planning applies profiles, resolves the selected adapter, and reports optional runtime capabilities such as streaming, updates, and cancellation. It does not start the runtime. +Planning resolves the selected adapter and reports optional runtime capabilities such as streaming, updates, and cancellation. Planning does not start the runtime. **Args:** - - `agent`: Agent-package directory or config-file path, or a typed ``FabricConfig``. Raw mappings are not accepted. - - `profiles`: One profile name or an ordered sequence of names for a path-backed source. For a typed source, an ordered sequence of ``FabricProfileConfig`` values. - - `base_dir`: Base directory for resolving relative paths in a typed config. Valid only when ``agent`` is a typed config source. + - `config`: Complete typed ``FabricConfig``. Raw mappings are not accepted. + - `base_dir`: Base directory for resolving relative paths. **Returns:** - A ``RunPlan`` containing the effective config, adapter, and declared runtime capabilities. + A ``RunPlan`` containing the canonical config, path context, adapter, and declared runtime capabilities. **Raises:** - - `FabricConfigError`: If the source, profile stack, config, or adapter resolution is invalid. - - `FabricNativeUnavailableError`: If the native extension is not installed. - ---- - - -### method `resolve` - -```python -resolve( - agent: 'AgentSource', - profiles: 'PathProfiles | TypedProfiles | None' = None, - base_dir: 'PathSource | None' = None -) → EffectiveConfig -``` - -Resolve an agent source and its ordered profile overlays. - -Resolution validates and normalizes configuration but does not resolve an adapter or compute runtime capabilities. Use ``plan()`` when those execution details are required. - - - -**Args:** - - - `agent`: Agent-package directory or config-file path, or a typed ``FabricConfig``. Raw mappings are not accepted; convert them with ``FabricConfig.from_mapping()``. - - `profiles`: One profile name or an ordered sequence of names for a path-backed source. For a typed source, an ordered sequence of ``FabricProfileConfig`` values. - - `base_dir`: Base directory for resolving relative paths in a typed config. Valid only when ``agent`` is a typed config source. - - - -**Returns:** - The normalized ``EffectiveConfig`` snapshot. - - - -**Raises:** - - - `FabricConfigError`: If the source, profile stack, or resolved config is invalid. + - `FabricConfigError`: If the config or adapter resolution is invalid. - `FabricNativeUnavailableError`: If the native extension is not installed. --- @@ -144,9 +103,8 @@ Resolution validates and normalizes configuration but does not resolve an adapte ```python run( - agent: 'AgentSource', - profiles: 'PathProfiles | TypedProfiles | None' = None, - base_dir: 'PathSource | None' = None, + config: 'FabricConfig', + base_dir: 'str | PathLike[str] | None' = None, input: 'Any' = None, request: 'RunRequest | None' = None ) → RunResult @@ -160,9 +118,8 @@ Execute one complete start, invoke, and stop lifecycle. **Args:** - - `agent`: Agent-package directory or config-file path, or a typed ``FabricConfig``. - - `profiles`: One profile name or an ordered sequence of names for a path-backed source. For a typed source, an ordered sequence of ``FabricProfileConfig`` values. - - `base_dir`: Base directory for resolving relative paths in a typed config. Valid only when ``agent`` is a typed config source. + - `config`: Complete typed ``FabricConfig``. + - `base_dir`: Base directory for resolving relative paths. - `input`: JSON-compatible invocation input. - `request`: Complete validated ``RunRequest``. @@ -186,9 +143,8 @@ Execute one complete start, invoke, and stop lifecycle. ```python start_runtime( - agent: 'AgentSource', - profiles: 'PathProfiles | TypedProfiles | None' = None, - base_dir: 'PathSource | None' = None, + config: 'FabricConfig', + base_dir: 'str | PathLike[str] | None' = None, overrides: 'Mapping[str, Any] | None' = None ) → Runtime ``` @@ -201,9 +157,8 @@ Each call starts a new logical runtime. Runtime-scoped overrides are recursively **Args:** - - `agent`: Agent-package directory or config-file path, or a typed ``FabricConfig``. - - `profiles`: One profile name or an ordered sequence of names for a path-backed source. For a typed source, an ordered sequence of ``FabricProfileConfig`` values. - - `base_dir`: Base directory for resolving relative paths in a typed config. Valid only when ``agent`` is a typed config source. + - `config`: Complete typed ``FabricConfig``. + - `base_dir`: Base directory for resolving relative paths. - `overrides`: JSON-compatible overrides applied to every invocation in the runtime unless superseded by invocation overrides. diff --git a/docs/reference/api/python-library-reference/nemo_fabric.errors.md b/docs/reference/api/python-library-reference/nemo_fabric.errors.md index 61fbf73e9..44bad6a22 100644 --- a/docs/reference/api/python-library-reference/nemo_fabric.errors.md +++ b/docs/reference/api/python-library-reference/nemo_fabric.errors.md @@ -61,7 +61,7 @@ Initialize a structured Fabric exception. ## class `FabricConfigError` -Invalid SDK input, request shape, profile stack, or resolved config. +Invalid SDK input, request shape, factory, or resolved config. ### method `__init__` diff --git a/docs/reference/api/python-library-reference/nemo_fabric.models.md b/docs/reference/api/python-library-reference/nemo_fabric.models.md index 540cb5820..2736be7ce 100644 --- a/docs/reference/api/python-library-reference/nemo_fabric.models.md +++ b/docs/reference/api/python-library-reference/nemo_fabric.models.md @@ -1361,66 +1361,6 @@ Return a detached JSON-compatible mapping for Rust/core calls. --- -## class `ProfileRegistryConfig` -Profile discovery config for portable file-backed agent packages. - - ---- - -### property extra_fields - -Return fields preserved by the extension point for this model. - ---- - -### property model_extra - -Get extra fields set during validation. - - - -**Returns:** - A dictionary of extra fields, or `None` if `config.extra` is not set to `"allow"`. - ---- - -### property model_fields_set - -Returns the set of fields that have been explicitly set on this model instance. - - - -**Returns:** - A set of strings representing the fields that have been set, i.e. that were not filled from defaults. - - - ---- - - -### classmethod `from_mapping` - -```python -from_mapping(value: 'Mapping[str, Any]') → Self -``` - -Validate a mapping using this Pydantic model. - ---- - - -### method `to_mapping` - -```python -to_mapping() → dict[str, Any] -``` - -Return a detached JSON-compatible mapping for Rust/core calls. - - ---- - - ## class `ToolsConfig` Harness-neutral tool capability configuration. @@ -1620,66 +1560,6 @@ Return a detached mapping matching the Rust ``FabricConfig`` schema. --- -## class `FabricProfileConfig` -Typed profile overlay used when a Python caller wants file-style overlays. - - ---- - -### property extra_fields - -Return fields preserved by the extension point for this model. - ---- - -### property model_extra - -Get extra fields set during validation. - - - -**Returns:** - A dictionary of extra fields, or `None` if `config.extra` is not set to `"allow"`. - ---- - -### property model_fields_set - -Returns the set of fields that have been explicitly set on this model instance. - - - -**Returns:** - A set of strings representing the fields that have been set, i.e. that were not filled from defaults. - - - ---- - - -### classmethod `from_mapping` - -```python -from_mapping(value: 'Mapping[str, Any]') → Self -``` - -Validate a mapping using this Pydantic model. - ---- - - -### method `to_mapping` - -```python -to_mapping() → dict[str, Any] -``` - -Return a detached JSON-compatible mapping for Rust/core calls. - - ---- - - ## class `RunRequest` One validated Fabric invocation request. diff --git a/docs/reference/api/python-library-reference/nemo_fabric.types.md b/docs/reference/api/python-library-reference/nemo_fabric.types.md index 6d70a2676..5de0e451d 100644 --- a/docs/reference/api/python-library-reference/nemo_fabric.types.md +++ b/docs/reference/api/python-library-reference/nemo_fabric.types.md @@ -110,77 +110,6 @@ __init__(mapping: 'Mapping[str, Any]') → None ---- - -### property extra_fields - -Return an immutable view of preserved extension fields. - - - ---- - - -### classmethod `from_mapping` - -```python -from_mapping(mapping: 'Mapping[str, Any]') → 'FabricMapping' -``` - -Validate and copy a mapping into the requested typed model. - ---- - - -### method `to_dict` - -```python -to_dict() → dict[str, Any] -``` - -Return the same detached representation as ``to_mapping()``. - ---- - - -### method `to_mapping` - -```python -to_mapping() → dict[str, Any] -``` - -Return a detached, JSON-compatible mapping for serialization. - - ---- - - -## class `EffectiveConfig` -Immutable result of config loading and ordered profile application. - - - -**Attributes:** - - - `agent_name`: Resolved agent name. - - `profiles`: Applied profile names in caller order. - - `agent_root`: Root directory of the path-backed agent source. - - `config_path`: Source config path, or ``None`` for typed configs. - - `config_root`: Base directory used to resolve relative paths. - - `config`: Fully resolved typed ``FabricConfig``. - - -### method `__init__` - -```python -__init__(mapping: 'Mapping[str, Any]') → None -``` - - - - - - --- ### property extra_fields @@ -233,9 +162,9 @@ Immutable execution plan produced before a runtime is started. **Attributes:** - - `effective_config`: Resolved configuration snapshot. - `agent_name`: Resolved agent name. - - `profiles`: Applied profile names in caller order. + - `base_dir`: Base directory used to resolve relative paths. + - `config`: Typed configuration snapshot. - `adapter`: Resolved adapter identity. - `capabilities`: Operations declared by the resolved runtime. @@ -373,7 +302,6 @@ Aggregate preflight diagnostics for a resolved run plan. **Attributes:** - `agent_name`: Resolved agent name. - - `profiles`: Applied profile names in caller order. - `status`: Aggregate outcome: ``pass``, ``warn``, or ``fail``. - `checks`: Ordered ``DoctorCheck`` results. @@ -933,7 +861,6 @@ The model is both attribute-accessible and mapping-compatible. A harness failure **Attributes:** - `agent_name`: Resolved agent name. - - `profiles`: Applied profile names. - `harness`: Stable harness identifier. - `adapter_kind`: Adapter execution mechanism. - `adapter_id`: Fabric adapter identifier. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitykind.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitykind.mdx index 9209ea0f1..b0d72b888 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitykind.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitykind.mdx @@ -2,7 +2,7 @@ title: "Enum Capability Kind" sidebar-title: "CapabilityKind" description: "Capability kind." -position: 42 +position: 39 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitytarget.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitytarget.mdx index 4727c3d29..2b82413a1 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitytarget.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitytarget.mdx @@ -2,7 +2,7 @@ title: "Enum Capability Target" sidebar-title: "CapabilityTarget" description: "Capability routing target." -position: 43 +position: 40 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-environmentownership.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-environmentownership.mdx index 56f121751..962a0afdc 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-environmentownership.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-environmentownership.mdx @@ -2,7 +2,7 @@ title: "Enum Environment Ownership" sidebar-title: "EnvironmentOwnership" description: "Whether Fabric owns the underlying environment resource." -position: 13 +position: 12 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-fabricdocument.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-fabricdocument.mdx deleted file mode 100644 index 9f52c7e1c..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-fabricdocument.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: "Enum Fabric Document" -sidebar-title: "FabricDocument" -description: "A loaded Fabric document with resolved source path and agent root." -position: 16 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
PathBuf,\n        root: PathBuf,\n        config: FabricConfig,\n    },\n}"}} />
- -A loaded Fabric document with resolved source path and agent root. - -## Variants - -### `FabricConfig` - -
- -Unified Fabric agent config. - -#### Fields - -### `path: PathBuf` - -Path to the config file. - -### `root: PathBuf` - -Root used for resolving relative paths. - -### `config: FabricConfig` - -Parsed config. - -## Trait Implementations - -### `impl Clone for FabricDocument` - -
Clone for FabricDocument"}} />
- -#### `clone` - -
clone(&self) -> FabricDocument"}} />
- -#### `clone_from` - -
clone_from(&mut self, source: &Self)"}} />
- -### `impl Debug for FabricDocument` - -
Debug for FabricDocument"}} />
- -#### `fmt` - -
fmt(&self, f: &mut Formatter<'_>) -> Result"}} />
- -### `impl<'de> Deserialize<'de> for FabricDocument` - -
Deserialize<'de> for FabricDocument"}} />
- -#### `deserialize` - -
deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where\n    __D: Deserializer<'de>,"}} />
- -### `impl JsonSchema for FabricDocument` - -
FabricDocument"}} />
- -#### `schema_name` - -
Cow<'static, str>"}} />
- -#### `schema_id` - -
Cow<'static, str>"}} />
- -#### `json_schema` - -
- -#### `inline_schema` - -
bool"}} />
- -### `impl PartialEq for FabricDocument` - -
PartialEq for FabricDocument"}} />
- -#### `eq` - -
eq(&self, other: &FabricDocument) -> bool"}} />
- -#### `ne` - -
ne(&self, other: &Rhs) -> bool"}} />
- -### `impl Serialize for FabricDocument` - -
Serialize for FabricDocument"}} />
- -#### `serialize` - -
serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>where\n    __S: Serializer,"}} />
- -### `impl StructuralPartialEq for FabricDocument` - -
StructuralPartialEq for FabricDocument"}} />
diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-mcpexposure.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-mcpexposure.mdx index dce2481c1..b06236033 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-mcpexposure.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-mcpexposure.mdx @@ -2,7 +2,7 @@ title: "Enum McpExposure" sidebar-title: "McpExposure" description: "MCP exposure strategy." -position: 19 +position: 17 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatifstorageconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatifstorageconfig.mdx index 6e1dd321f..1b2589f2c 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatifstorageconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatifstorageconfig.mdx @@ -2,7 +2,7 @@ title: "Enum Relay Atif Storage Config" sidebar-title: "RelayAtifStorageConfig" description: "Relay ATIF remote storage configuration." -position: 48 +position: 44 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointfieldnamepolicy.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointfieldnamepolicy.mdx index f145956be..e500f6aa1 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointfieldnamepolicy.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointfieldnamepolicy.mdx @@ -2,7 +2,7 @@ title: "Enum Relay Atof Endpoint Field Name Policy" sidebar-title: "RelayAtofEndpointFieldNamePolicy" description: "Relay ATOF endpoint field-name policy." -position: 49 +position: 45 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointtransport.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointtransport.mdx index ab2682f91..089169e4e 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointtransport.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointtransport.mdx @@ -2,7 +2,7 @@ title: "Enum Relay Atof Endpoint Transport" sidebar-title: "RelayAtofEndpointTransport" description: "Relay ATOF endpoint transport." -position: 50 +position: 46 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofmode.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofmode.mdx index ee3ac693a..010b88501 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofmode.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofmode.mdx @@ -2,7 +2,7 @@ title: "Enum Relay Atof Mode" sidebar-title: "RelayAtofMode" description: "Relay ATOF file mode." -position: 51 +position: 47 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayotlptransport.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayotlptransport.mdx index 2fd040adb..fae226e2b 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayotlptransport.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayotlptransport.mdx @@ -2,7 +2,7 @@ title: "Enum Relay Otlp Transport" sidebar-title: "RelayOtlpTransport" description: "Relay OTLP transport." -position: 52 +position: 48 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayunsupportedbehavior.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayunsupportedbehavior.mdx index 4669a0453..34db2ad99 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayunsupportedbehavior.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayunsupportedbehavior.mdx @@ -2,7 +2,7 @@ title: "Enum Relay Unsupported Behavior" sidebar-title: "RelayUnsupportedBehavior" description: "Relay unsupported/unknown config handling." -position: 53 +position: 49 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-resolutionstrategy.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-resolutionstrategy.mdx index 2f06bcd9e..86197cf30 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-resolutionstrategy.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-resolutionstrategy.mdx @@ -2,7 +2,7 @@ title: "Enum Resolution Strategy" sidebar-title: "ResolutionStrategy" description: "Adapter install or availability strategy." -position: 24 +position: 21 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-telemetryprovider.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-telemetryprovider.mdx index 851ae8829..9cab3af61 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-telemetryprovider.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/enum-telemetryprovider.mdx @@ -2,7 +2,7 @@ title: "Enum Telemetry Provider" sidebar-title: "TelemetryProvider" description: "Telemetry runtime provider." -position: 33 +position: 30 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-adapter-descriptor.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-adapter-descriptor.mdx index 058809419..93dff2ba9 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-adapter-descriptor.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-adapter-descriptor.mdx @@ -2,7 +2,7 @@ title: "Function load_adapter_descriptor" sidebar-title: "load_adapter_descriptor" description: "Load an adapter descriptor from JSON package metadata." -position: 35 +position: 32 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-fabric-document.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-fabric-document.mdx deleted file mode 100644 index 64820dfa6..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-fabric-document.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function load_fabric_document" -sidebar-title: "load_fabric_document" -description: "Load a Fabric document from an agent directory or single agent config." -position: 36 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
AsRef<Path>) -> Result<FabricDocument>"}} />
- -Load a Fabric document from an agent directory or single agent config. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-from-config.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-from-config.mdx deleted file mode 100644 index fe82db846..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-from-config.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function resolve_effective_config_from_config" -sidebar-title: "resolve_effective_config_from_config" -description: "Resolve typed config/profile overlays into merged effective config." -position: 38 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
FabricConfig,\n    profiles: &[ProfileConfig],\n    context: ResolveContext,\n) -> Result<EffectiveConfig>"}} />
- -Resolve typed config/profile overlays into merged effective config. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-with-profiles.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-with-profiles.mdx deleted file mode 100644 index 52fc900eb..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-with-profiles.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function resolve_effective_config_with_profiles" -sidebar-title: "resolve_effective_config_with_profiles" -description: "Resolve an agent directory or single agent config with ordered profiles into merged effective config." -position: 39 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
AsRef<Path>,\n    profiles: &[String],\n) -> Result<EffectiveConfig>"}} />
- -Resolve an agent directory or single agent config with ordered profiles into merged effective config. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config.mdx deleted file mode 100644 index 8665e8029..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function resolve_effective_config" -sidebar-title: "resolve_effective_config" -description: "Resolve an agent directory or single agent config into merged effective config." -position: 37 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
AsRef<Path>,\n    profile: Option<&str>,\n) -> Result<EffectiveConfig>"}} />
- -Resolve an agent directory or single agent config into merged effective config. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-config.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-config.mdx index 494cb76f1..830eb41f2 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-config.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-config.mdx @@ -1,16 +1,16 @@ --- title: "Function resolve_run_plan_from_config" sidebar-title: "resolve_run_plan_from_config" -description: "Resolve a typed Fabric config and typed profile overlays into a runnable plan." -position: 41 +description: "Resolve a typed Fabric config into a runnable plan." +position: 33 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
FabricConfig,\n    profiles: &[ProfileConfig],\n    context: ResolveContext,\n) -> Result<RunPlan>"}} />
+
FabricConfig,\n    context: ResolveContext,\n) -> Result<RunPlan>"}} />
-Resolve a typed Fabric config and typed profile overlays into a runnable plan. +Resolve a typed Fabric config into a runnable plan. -This is the SDK-facing entrypoint. File and YAML loading stays outside this function; callers provide already-typed configs and the path context used for resolving relative paths. +Callers provide an already-composed typed config and the explicit base directory used for resolving relative paths. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-effective-config.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-effective-config.mdx deleted file mode 100644 index 21299f44d..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-effective-config.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function resolve_run_plan_from_effective_config" -sidebar-title: "resolve_run_plan_from_effective_config" -description: "Resolve execution planning metadata from merged effective config." -position: 42 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
EffectiveConfig,\n) -> Result<RunPlan>"}} />
- -Resolve execution planning metadata from merged effective config. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-with-profiles.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-with-profiles.mdx deleted file mode 100644 index 0b28b5fca..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-with-profiles.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function resolve_run_plan_with_profiles" -sidebar-title: "resolve_run_plan_with_profiles" -description: "Resolve an agent directory or single agent config with ordered profile application." -position: 43 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
AsRef<Path>,\n    profiles: &[String],\n) -> Result<RunPlan>"}} />
- -Resolve an agent directory or single agent config with ordered profile application. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan.mdx deleted file mode 100644 index fd80030da..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function resolve_run_plan" -sidebar-title: "resolve_run_plan" -description: "Resolve an agent directory or single agent config into a runnable plan." -position: 40 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
AsRef<Path>,\n    profile: Option<&str>,\n) -> Result<RunPlan>"}} />
- -Resolve an agent directory or single agent config into a runnable plan. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-validate-agent-directory.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-validate-agent-directory.mdx deleted file mode 100644 index 7706821b3..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/fn-validate-agent-directory.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Function validate_agent_directory" -sidebar-title: "validate_agent_directory" -description: "Validate an agent directory or config, including discoverable profile YAMLs." -position: 44 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
AsRef<Path>) -> Result<()>"}} />
- -Validate an agent directory or config, including discoverable profile YAMLs. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/index.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/index.mdx index 45fd6b667..4de4cef4d 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/index.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/index.mdx @@ -2,7 +2,7 @@ title: "Module config" sidebar-title: "config" description: "Fabric config models and loading helpers." -position: 76 +position: 65 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} @@ -21,7 +21,6 @@ Fabric config models and loading helpers. - [CapabilityPlan](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilityplan): Resolved capability configuration. - [CapabilityRoute](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilityroute): One capability routing decision. - [CapabilityTargetPlan](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilitytargetplan): Capabilities routed to one target. -- [EffectiveConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-effectiveconfig): Merged Fabric config after applying selected profiles. - [EnvironmentConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentconfig): Execution environment configuration. - [EnvironmentPlan](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentplan): Resolved environment plan. - [FabricConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-fabricconfig): Versioned Fabric agent config. @@ -31,8 +30,6 @@ Fabric config models and loading helpers. - [McpServerPlan](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverplan): Resolved MCP server exposure. - [MetadataConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-metadataconfig): Human-readable metadata. - [ModelConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-modelconfig): Model configuration. -- [ProfileConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileconfig): Profile config applied on top of a Fabric config. -- [ProfileRegistryConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileregistryconfig): Profile discovery config for curated package profiles. - [RelayAtifConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatifconfig): Relay ATIF export configuration. - [RelayAtofConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofconfig): Relay ATOF export configuration. - [RelayAtofEndpointConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofendpointconfig): Relay ATOF endpoint configuration. @@ -61,7 +58,6 @@ Fabric config models and loading helpers. - [CapabilityTarget](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-capabilitytarget): Capability routing target. - [ControlLocation](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-controllocation): Where Fabric control code runs relative to the environment. - [EnvironmentOwnership](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-environmentownership): Whether Fabric owns the underlying environment resource. -- [FabricDocument](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-fabricdocument): A loaded Fabric document with resolved source path and agent root. - [McpExposure](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-mcpexposure): MCP exposure strategy. - [RelayAtifStorageConfig](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatifstorageconfig): Relay ATIF remote storage configuration. - [RelayAtofEndpointFieldNamePolicy](/reference/api/rust-library-reference/nemo-fabric-core/config/enum-relayatofendpointfieldnamepolicy): Relay ATOF endpoint field-name policy. @@ -79,12 +75,4 @@ Fabric config models and loading helpers. ## Functions - [load_adapter_descriptor](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-adapter-descriptor): Load an adapter descriptor from JSON package metadata. -- [load_fabric_document](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-load-fabric-document): Load a Fabric document from an agent directory or single agent config. -- [resolve_effective_config](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config): Resolve an agent directory or single agent config into merged effective config. -- [resolve_effective_config_from_config](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-from-config): Resolve typed config/profile overlays into merged effective config. -- [resolve_effective_config_with_profiles](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-effective-config-with-profiles): Resolve an agent directory or single agent config with ordered profiles into merged effective config. -- [resolve_run_plan](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan): Resolve an agent directory or single agent config into a runnable plan. -- [resolve_run_plan_from_config](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-config): Resolve a typed Fabric config and typed profile overlays into a runnable plan. -- [resolve_run_plan_from_effective_config](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-effective-config): Resolve execution planning metadata from merged effective config. -- [resolve_run_plan_with_profiles](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-with-profiles): Resolve an agent directory or single agent config with ordered profile application. -- [validate_agent_directory](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-validate-agent-directory): Validate an agent directory or config, including discoverable profile YAMLs. +- [resolve_run_plan_from_config](/reference/api/rust-library-reference/nemo-fabric-core/config/fn-resolve-run-plan-from-config): Resolve a typed Fabric config into a runnable plan. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilityplan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilityplan.mdx index a3e63f791..8e98b7c73 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilityplan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-capabilityplan.mdx @@ -45,7 +45,7 @@ Capabilities that are configured but not executable by this Fabric build. ### `routes: Vec` -Routing decisions made while resolving the effective config. +Routing decisions made while planning the configured capabilities. ## Trait Implementations diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-effectiveconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-effectiveconfig.mdx deleted file mode 100644 index ffc2d9c9f..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-effectiveconfig.mdx +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: "Struct Effective Config" -sidebar-title: "EffectiveConfig" -description: "Merged Fabric config after applying selected profiles." -position: 11 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
String,\n    pub profiles: Vec<String>,\n    pub agent_root: PathBuf,\n    pub config_path: PathBuf,\n    pub config_root: PathBuf,\n    pub config: FabricConfig,\n}"}} />
- -Merged Fabric config after applying selected profiles. - -## Fields - -### `agent_name: String` - -Stable agent name. - -### `profiles: Vec` - -Ordered selected profiles. - -### `agent_root: PathBuf` - -Root used to resolve agent package paths. - -### `config_path: PathBuf` - -Resolved Fabric config path. - -### `config_root: PathBuf` - -Root used to resolve config-local paths. - -### `config: FabricConfig` - -Merged Fabric config with authoring-time profile discovery removed. - -## Trait Implementations - -### `impl Clone for EffectiveConfig` - -
Clone for EffectiveConfig"}} />
- -#### `clone` - -
clone(&self) -> EffectiveConfig"}} />
- -#### `clone_from` - -
clone_from(&mut self, source: &Self)"}} />
- -### `impl Debug for EffectiveConfig` - -
Debug for EffectiveConfig"}} />
- -#### `fmt` - -
fmt(&self, f: &mut Formatter<'_>) -> Result"}} />
- -### `impl<'de> Deserialize<'de> for EffectiveConfig` - -
Deserialize<'de> for EffectiveConfig"}} />
- -#### `deserialize` - -
deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where\n    __D: Deserializer<'de>,"}} />
- -### `impl JsonSchema for EffectiveConfig` - -
EffectiveConfig"}} />
- -#### `schema_name` - -
Cow<'static, str>"}} />
- -#### `schema_id` - -
Cow<'static, str>"}} />
- -#### `json_schema` - -
- -#### `inline_schema` - -
bool"}} />
- -### `impl PartialEq for EffectiveConfig` - -
PartialEq for EffectiveConfig"}} />
- -#### `eq` - -
eq(&self, other: &EffectiveConfig) -> bool"}} />
- -#### `ne` - -
ne(&self, other: &Rhs) -> bool"}} />
- -### `impl Serialize for EffectiveConfig` - -
Serialize for EffectiveConfig"}} />
- -#### `serialize` - -
serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>where\n    __S: Serializer,"}} />
- -### `impl StructuralPartialEq for EffectiveConfig` - -
StructuralPartialEq for EffectiveConfig"}} />
diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentconfig.mdx index 4c0cc7b44..97e9e0d19 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Environment Config" sidebar-title: "EnvironmentConfig" description: "Execution environment configuration." -position: 12 +position: 11 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentplan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentplan.mdx index 906e78ccc..f0f664bc7 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentplan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-environmentplan.mdx @@ -2,7 +2,7 @@ title: "Struct Environment Plan" sidebar-title: "EnvironmentPlan" description: "Resolved environment plan." -position: 14 +position: 13 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-fabricconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-fabricconfig.mdx index 04b88254e..dca40ab9c 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-fabricconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-fabricconfig.mdx @@ -2,14 +2,14 @@ title: "Struct Fabric Config" sidebar-title: "FabricConfig" description: "Versioned Fabric agent config." -position: 15 +position: 14 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
String,\n    pub metadata: MetadataConfig,\n    pub harness: HarnessConfig,\n    pub models: BTreeMap<String, ModelConfig>,\n    pub runtime: RuntimeConfig,\n    pub environment: Option<EnvironmentConfig>,\n    pub tools: Option<ToolsConfig>,\n    pub skills: Option<SkillConfig>,\n    pub mcp: Option<McpConfig>,\n    pub telemetry: Option<TelemetryConfig>,\n    pub relay: Option<RelayConfig>,\n    pub profiles: ProfileRegistryConfig,\n    pub extensions: BTreeMap<String, Value>,\n}"}} />
+
String,\n    pub metadata: MetadataConfig,\n    pub harness: HarnessConfig,\n    pub models: BTreeMap<String, ModelConfig>,\n    pub runtime: RuntimeConfig,\n    pub environment: Option<EnvironmentConfig>,\n    pub tools: Option<ToolsConfig>,\n    pub skills: Option<SkillConfig>,\n    pub mcp: Option<McpConfig>,\n    pub telemetry: Option<TelemetryConfig>,\n    pub relay: Option<RelayConfig>,\n    pub extensions: BTreeMap<String, Value>,\n}"}} />
Versioned Fabric agent config. @@ -59,10 +59,6 @@ Telemetry configuration. First-class NeMo Relay integration configuration. -### `profiles: ProfileRegistryConfig` - -Optional profile discovery config. - ### `extensions: BTreeMap` Additive fields not yet recognized by this core version. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-harnessconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-harnessconfig.mdx index 111869755..ce73c2a14 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-harnessconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-harnessconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Harness Config" sidebar-title: "HarnessConfig" description: "Harness selection." -position: 17 +position: 15 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpconfig.mdx index 33a7d5e50..12e5c64c5 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpconfig.mdx @@ -2,7 +2,7 @@ title: "Struct McpConfig" sidebar-title: "McpConfig" description: "MCP capability configuration." -position: 18 +position: 16 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverconfig.mdx index 0d3eb1f09..a569574dd 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverconfig.mdx @@ -2,7 +2,7 @@ title: "Struct McpServer Config" sidebar-title: "McpServerConfig" description: "MCP server configuration." -position: 15 +position: 14 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverplan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverplan.mdx index c51dbefb5..6902533b3 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverplan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-mcpserverplan.mdx @@ -2,7 +2,7 @@ title: "Struct McpServer Plan" sidebar-title: "McpServerPlan" description: "Resolved MCP server exposure." -position: 20 +position: 18 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-metadataconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-metadataconfig.mdx index 40ba1d635..c9bfdec0d 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-metadataconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-metadataconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Metadata Config" sidebar-title: "MetadataConfig" description: "Human-readable metadata." -position: 21 +position: 19 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-modelconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-modelconfig.mdx index 43673736a..92033d79b 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-modelconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-modelconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Model Config" sidebar-title: "ModelConfig" description: "Model configuration." -position: 22 +position: 20 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileconfig.mdx deleted file mode 100644 index 94b6c8443..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileconfig.mdx +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: "Struct Profile Config" -sidebar-title: "ProfileConfig" -description: "Profile config applied on top of a Fabric config." -position: 23 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
Option<String>,\n    pub name: Option<String>,\n    pub description: Option<String>,\n    pub overlay: BTreeMap<String, Value>,\n}"}} />
- -Profile config applied on top of a Fabric config. - -## Fields - -### `schema_version: Option` - -Optional profile schema version. - -### `name: Option` - -Optional profile name used for directory discovery. - -### `description: Option` - -Optional profile description. - -### `overlay: BTreeMap` - -Raw config fields recursively merged over the base config. - -## Trait Implementations - -### `impl Clone for ProfileConfig` - -
Clone for ProfileConfig"}} />
- -#### `clone` - -
clone(&self) -> ProfileConfig"}} />
- -#### `clone_from` - -
clone_from(&mut self, source: &Self)"}} />
- -### `impl Debug for ProfileConfig` - -
Debug for ProfileConfig"}} />
- -#### `fmt` - -
fmt(&self, f: &mut Formatter<'_>) -> Result"}} />
- -### `impl Default for ProfileConfig` - -
Default for ProfileConfig"}} />
- -#### `default` - -
default() -> ProfileConfig"}} />
- -### `impl<'de> Deserialize<'de> for ProfileConfig` - -
Deserialize<'de> for ProfileConfig"}} />
- -#### `deserialize` - -
deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where\n    __D: Deserializer<'de>,"}} />
- -### `impl JsonSchema for ProfileConfig` - -
ProfileConfig"}} />
- -#### `schema_name` - -
Cow<'static, str>"}} />
- -#### `json_schema` - -
- -#### `inline_schema` - -
bool"}} />
- -#### `schema_id` - -
Cow<'static, str>"}} />
- -### `impl PartialEq for ProfileConfig` - -
PartialEq for ProfileConfig"}} />
- -#### `eq` - -
eq(&self, other: &ProfileConfig) -> bool"}} />
- -#### `ne` - -
ne(&self, other: &Rhs) -> bool"}} />
- -### `impl Serialize for ProfileConfig` - -
Serialize for ProfileConfig"}} />
- -#### `serialize` - -
serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>where\n    __S: Serializer,"}} />
- -### `impl StructuralPartialEq for ProfileConfig` - -
StructuralPartialEq for ProfileConfig"}} />
diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileregistryconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileregistryconfig.mdx deleted file mode 100644 index 86d980c6d..000000000 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-profileregistryconfig.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: "Struct Profile Registry Config" -sidebar-title: "ProfileRegistryConfig" -description: "Profile discovery config for curated package profiles." -position: 20 ---- -{/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -SPDX-License-Identifier: Apache-2.0 */} - -Generated from `cargo doc --no-deps -p nemo-fabric-core`. - -
Vec<PathBuf>,\n    pub extensions: BTreeMap<String, Value>,\n}"}} />
- -Profile discovery config for curated package profiles. - -## Fields - -### `directories: Vec` - -Directories searched when a caller selects a profile by name. - -### `extensions: BTreeMap` - -Additive profile-discovery fields. - -## Trait Implementations - -### `impl Clone for ProfileRegistryConfig` - -
Clone for ProfileRegistryConfig"}} />
- -#### `clone` - -
clone(&self) -> ProfileRegistryConfig"}} />
- -#### `clone_from` - -
clone_from(&mut self, source: &Self)"}} />
- -### `impl Debug for ProfileRegistryConfig` - -
Debug for ProfileRegistryConfig"}} />
- -#### `fmt` - -
fmt(&self, f: &mut Formatter<'_>) -> Result"}} />
- -### `impl Default for ProfileRegistryConfig` - -
Default for ProfileRegistryConfig"}} />
- -#### `default` - -
default() -> ProfileRegistryConfig"}} />
- -### `impl<'de> Deserialize<'de> for ProfileRegistryConfig` - -
Deserialize<'de> for ProfileRegistryConfig"}} />
- -#### `deserialize` - -
deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where\n    __D: Deserializer<'de>,"}} />
- -### `impl JsonSchema for ProfileRegistryConfig` - -
ProfileRegistryConfig"}} />
- -#### `schema_name` - -
Cow<'static, str>"}} />
- -#### `schema_id` - -
Cow<'static, str>"}} />
- -#### `json_schema` - -
- -#### `inline_schema` - -
bool"}} />
- -### `impl PartialEq for ProfileRegistryConfig` - -
PartialEq for ProfileRegistryConfig"}} />
- -#### `eq` - -
eq(&self, other: &ProfileRegistryConfig) -> bool"}} />
- -#### `ne` - -
ne(&self, other: &Rhs) -> bool"}} />
- -### `impl Serialize for ProfileRegistryConfig` - -
Serialize for ProfileRegistryConfig"}} />
- -#### `serialize` - -
serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>where\n    __S: Serializer,"}} />
- -### `impl StructuralPartialEq for ProfileRegistryConfig` - -
StructuralPartialEq for ProfileRegistryConfig"}} />
diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatifconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatifconfig.mdx index 4c28fe811..2beb9d723 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatifconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatifconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Atif Config" sidebar-title: "RelayAtifConfig" description: "Relay ATIF export configuration." -position: 21 +position: 18 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofconfig.mdx index c667bfddf..0d91c211a 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Atof Config" sidebar-title: "RelayAtofConfig" description: "Relay ATOF export configuration." -position: 22 +position: 19 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofendpointconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofendpointconfig.mdx index 1977b524b..74f698421 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofendpointconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayatofendpointconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Atof Endpoint Config" sidebar-title: "RelayAtofEndpointConfig" description: "Relay ATOF endpoint configuration." -position: 23 +position: 20 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relaycomponentconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relaycomponentconfig.mdx index dc0043292..44df6f4e6 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relaycomponentconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relaycomponentconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Component Config" sidebar-title: "RelayComponentConfig" description: "Generic NeMo Relay plugin component configuration." -position: 24 +position: 21 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfig.mdx index 1b8b6bff5..852abee85 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Config" sidebar-title: "RelayConfig" description: "NeMo Relay integration configuration." -position: 25 +position: 22 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfigpolicy.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfigpolicy.mdx index 3011b139d..66b07af70 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfigpolicy.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayconfigpolicy.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Config Policy" sidebar-title: "RelayConfigPolicy" description: "Relay validation policy." -position: 26 +position: 23 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayobservabilityconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayobservabilityconfig.mdx index 785fdead5..1fba378f6 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayobservabilityconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayobservabilityconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Observability Config" sidebar-title: "RelayObservabilityConfig" description: "NeMo Relay observability component configuration." -position: 27 +position: 24 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayotlpconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayotlpconfig.mdx index 2965e9161..0d9cfc977 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayotlpconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-relayotlpconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Relay Otlp Config" sidebar-title: "RelayOtlpConfig" description: "Relay OpenTelemetry/OpenInference export configuration." -position: 28 +position: 25 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvecontext.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvecontext.mdx index 42b530b0e..1fd20085e 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvecontext.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvecontext.mdx @@ -2,30 +2,22 @@ title: "Struct Resolve Context" sidebar-title: "ResolveContext" description: "Source context used when resolving an in-memory Fabric config." -position: 25 +position: 22 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
PathBuf,\n    pub config_path: PathBuf,\n    pub config_root: PathBuf,\n}"}} />
+
PathBuf,\n}"}} />
Source context used when resolving an in-memory Fabric config. ## Fields -### `agent_root: PathBuf` +### `base_dir: PathBuf` -Root used to resolve agent package paths. - -### `config_path: PathBuf` - -Path recorded as config provenance in the run plan. - -### `config_root: PathBuf` - -Root used to resolve config-local paths. +Base directory used to resolve relative Fabric paths. ## Implementations @@ -33,17 +25,11 @@ Root used to resolve config-local paths.
ResolveContext"}} />
-#### `from_agent_root` - -
Into<PathBuf>) -> Self"}} />
- -Build a context for an agent package root. - -#### `from_config_path` +#### `new` -
Into<PathBuf>,\n    root: impl Into<PathBuf>,\n) -> Self"}} />
+
Into<PathBuf>) -> Self"}} />
-Build a context for a config file and its config root. +Build a context with an explicit base directory. ## Trait Implementations diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvedadapterdescriptor.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvedadapterdescriptor.mdx index 0fa3450f7..c1891a955 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvedadapterdescriptor.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-resolvedadapterdescriptor.mdx @@ -2,7 +2,7 @@ title: "Struct Resolved Adapter Descriptor" sidebar-title: "ResolvedAdapterDescriptor" description: "Adapter descriptor selected for a run plan." -position: 26 +position: 23 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runplan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runplan.mdx index c0c331303..f042afb24 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runplan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runplan.mdx @@ -2,30 +2,30 @@ title: "Struct RunPlan" sidebar-title: "RunPlan" description: "Resolved Fabric run plan." -position: 27 +position: 24 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
EffectiveConfig,\n    pub agent_name: String,\n    pub profiles: Vec<String>,\n    pub adapter_descriptor: Option<ResolvedAdapterDescriptor>,\n    pub resolution: Option<ResolutionStrategy>,\n    pub environment_plan: Option<EnvironmentPlan>,\n    pub capability_plan: CapabilityPlan,\n    pub capabilities: RuntimeCapabilities,\n    pub telemetry_plan: Option<TelemetryPlan>,\n    pub agent_root: PathBuf,\n    pub config_path: PathBuf,\n    pub config_root: PathBuf,\n    pub config: FabricConfig,\n}"}} />
+
String,\n    pub base_dir: PathBuf,\n    pub config: FabricConfig,\n    pub adapter_descriptor: Option<ResolvedAdapterDescriptor>,\n    pub resolution: Option<ResolutionStrategy>,\n    pub environment_plan: Option<EnvironmentPlan>,\n    pub capability_plan: CapabilityPlan,\n    pub capabilities: RuntimeCapabilities,\n    pub telemetry_plan: Option<TelemetryPlan>,\n}"}} />
Resolved Fabric run plan. ## Fields -### `effective_config: EffectiveConfig` - -Merged config and provenance used as the base for this plan. - ### `agent_name: String` Stable agent name. -### `profiles: Vec` +### `base_dir: PathBuf` -Ordered selected profiles. +Base directory used to resolve relative Fabric paths. + +### `config: FabricConfig` + +Complete typed Fabric config. ### `adapter_descriptor: Option` @@ -51,22 +51,6 @@ Lifecycle behavior implemented by the selected runtime path. Resolved telemetry pass-through plan. -### `agent_root: PathBuf` - -Root used to resolve agent package paths. - -### `config_path: PathBuf` - -Resolved Fabric config path. - -### `config_root: PathBuf` - -Root used to resolve config-local paths. - -### `config: FabricConfig` - -Resolved Fabric profile config. - ## Trait Implementations ### `impl Clone for RunPlan` diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimecapabilities.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimecapabilities.mdx index 2f73a4d20..7ef3c1696 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimecapabilities.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimecapabilities.mdx @@ -2,7 +2,7 @@ title: "Struct Runtime Capabilities" sidebar-title: "RuntimeCapabilities" description: "Lifecycle behavior implemented by a resolved runtime path." -position: 28 +position: 25 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimeconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimeconfig.mdx index 8b51cafcc..86641ac9b 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimeconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-runtimeconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Runtime Config" sidebar-title: "RuntimeConfig" description: "Runtime input/output contract." -position: 29 +position: 26 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-skillconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-skillconfig.mdx index 8ea5d934d..9572bbf71 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-skillconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-skillconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Skill Config" sidebar-title: "SkillConfig" description: "Skill capability configuration." -position: 30 +position: 27 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} @@ -17,7 +17,7 @@ Skill capability configuration. ### `paths: Vec` -Skill paths relative to the agent root. +Skill paths resolved relative to the config base directory. ### `extensions: BTreeMap` diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryconfig.mdx index 9338bbfb4..5dd271a6f 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Telemetry Config" sidebar-title: "TelemetryConfig" description: "Telemetry configuration." -position: 31 +position: 28 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryplan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryplan.mdx index eee9a11e3..04c79e8c9 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryplan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryplan.mdx @@ -2,7 +2,7 @@ title: "Struct Telemetry Plan" sidebar-title: "TelemetryPlan" description: "Resolved telemetry plan." -position: 32 +position: 29 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryproviderconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryproviderconfig.mdx index 67483880a..21e9291ba 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryproviderconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-telemetryproviderconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Telemetry Provider Config" sidebar-title: "TelemetryProviderConfig" description: "Provider-specific telemetry configuration." -position: 34 +position: 31 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsconfig.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsconfig.mdx index 1d39c422e..ccedcf918 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsconfig.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsconfig.mdx @@ -2,7 +2,7 @@ title: "Struct Tools Config" sidebar-title: "ToolsConfig" description: "Harness-neutral tool capability configuration." -position: 38 +position: 35 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsplan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsplan.mdx index fa1ed8399..948ab6ecf 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsplan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/config/struct-toolsplan.mdx @@ -2,7 +2,7 @@ title: "Struct Tools Plan" sidebar-title: "ToolsPlan" description: "Normalized tool policy for a run." -position: 39 +position: 36 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/enum-doctorstatus.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/enum-doctorstatus.mdx index 4bdf73ab3..0d424ce77 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/enum-doctorstatus.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/enum-doctorstatus.mdx @@ -2,7 +2,7 @@ title: "Enum Doctor Status" sidebar-title: "DoctorStatus" description: "Diagnostic status." -position: 47 +position: 36 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/fn-doctor-plan.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/fn-doctor-plan.mdx index 64841c884..c25887030 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/fn-doctor-plan.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/fn-doctor-plan.mdx @@ -2,7 +2,7 @@ title: "Function doctor_plan" sidebar-title: "doctor_plan" description: "Inspect a resolved run plan without mutating the environment." -position: 48 +position: 37 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/index.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/index.mdx index c409cd201..5dff6b0b1 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/index.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/index.mdx @@ -2,7 +2,7 @@ title: "Module doctor" sidebar-title: "doctor" description: "Plan diagnostics for Fabric." -position: 77 +position: 66 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorcheck.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorcheck.mdx index ade547253..75af40335 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorcheck.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorcheck.mdx @@ -2,7 +2,7 @@ title: "Struct Doctor Check" sidebar-title: "DoctorCheck" description: "Diagnostic check result." -position: 45 +position: 34 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorreport.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorreport.mdx index 14a0150e4..e7b635eb3 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorreport.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/doctor/struct-doctorreport.mdx @@ -2,14 +2,14 @@ title: "Struct Doctor Report" sidebar-title: "DoctorReport" description: "Diagnostic report for a resolved run plan." -position: 46 +position: 35 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
String,\n    pub profiles: Vec<String>,\n    pub status: DoctorStatus,\n    pub checks: Vec<DoctorCheck>,\n}"}} />
+
String,\n    pub status: DoctorStatus,\n    pub checks: Vec<DoctorCheck>,\n}"}} />
Diagnostic report for a resolved run plan. @@ -19,10 +19,6 @@ Diagnostic report for a resolved run plan. Agent name. -### `profiles: Vec` - -Ordered profiles applied to the inspected plan. - ### `status: DoctorStatus` Overall status. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/error/enum-fabricerror.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/error/enum-fabricerror.mdx index 8f6cdeecd..4ff429c42 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/error/enum-fabricerror.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/error/enum-fabricerror.mdx @@ -2,72 +2,40 @@ title: "Enum Fabric Error" sidebar-title: "FabricError" description: "Errors raised by Fabric config loading and validation." -position: 49 +position: 38 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
PathBuf),\n    MissingEntrypoint(PathBuf),\n    UnsupportedExtension(PathBuf),\n    UnknownProfile {\n        profile: String,\n        agent: String,\n        available: Vec<String>,\n    },\n    ProfileError {\n        path: PathBuf,\n        message: String,\n    },\n    UnknownAdapter {\n        adapter_id: String,\n        available: Vec<String>,\n    },\n    AdapterDescriptorMismatch {\n        path: PathBuf,\n        field: &'static str,\n        expected: String,\n        actual: String,\n    },\n    AdapterDescriptorUnsupported {\n        adapter_id: String,\n        field: &'static str,\n        value: String,\n    },\n    InvalidAdapterDescriptor {\n        path: PathBuf,\n        message: String,\n    },\n    UnknownSchema {\n        schema: String,\n        available: Vec<String>,\n    },\n    ProfileTargetNotConfig {\n        profile: String,\n        path: PathBuf,\n    },\n    ProfileSelectionNotSupported(PathBuf),\n    UnsupportedRuntimeAdapter {\n        harness: String,\n        adapter_kind: AdapterKind,\n    },\n    UnsupportedToolsPolicy {\n        harness: String,\n        reason: String,\n    },\n    RuntimeHandleMismatch {\n        field: &'static str,\n        expected: String,\n        actual: String,\n        runtime_id: String,\n    },\n    UnsupportedEnvironmentProvider {\n        provider: String,\n        adapter_kind: AdapterKind,\n    },\n    InvalidProcessSettings {\n        path: PathBuf,\n        source: Error,\n    },\n    InvalidPythonSettings {\n        path: PathBuf,\n        source: Error,\n    },\n    PythonInterpreterUnavailable {\n        path: PathBuf,\n        origin: String,\n        reason: String,\n    },\n    ProcessRunner {\n        command: String,\n        source: Error,\n    },\n    SerializeJson(Error),\n    Read {\n        path: PathBuf,\n        source: Error,\n    },\n    Write {\n        path: PathBuf,\n        source: Error,\n    },\n    ParseYaml {\n        path: PathBuf,\n        source: Error,\n    },\n    ParseJson {\n        path: PathBuf,\n        source: Error,\n    },\n}"}} />
+
PathBuf,\n        source: Error,\n    },\n    PathNotFound(PathBuf),\n    UnknownAdapter {\n        adapter_id: String,\n        available: Vec<String>,\n    },\n    AdapterDescriptorMismatch {\n        path: PathBuf,\n        field: &'static str,\n        expected: String,\n        actual: String,\n    },\n    AdapterDescriptorUnsupported {\n        adapter_id: String,\n        field: &'static str,\n        value: String,\n    },\n    InvalidAdapterDescriptor {\n        path: PathBuf,\n        message: String,\n    },\n    UnknownSchema {\n        schema: String,\n        available: Vec<String>,\n    },\n    UnsupportedRuntimeAdapter {\n        harness: String,\n        adapter_kind: AdapterKind,\n    },\n    UnsupportedToolsPolicy {\n        harness: String,\n        reason: String,\n    },\n    RuntimeHandleMismatch {\n        field: &'static str,\n        expected: String,\n        actual: String,\n        runtime_id: String,\n    },\n    UnsupportedEnvironmentProvider {\n        provider: String,\n        adapter_kind: AdapterKind,\n    },\n    InvalidProcessSettings {\n        path: PathBuf,\n        source: Error,\n    },\n    InvalidPythonSettings {\n        path: PathBuf,\n        source: Error,\n    },\n    PythonInterpreterUnavailable {\n        path: PathBuf,\n        origin: String,\n        reason: String,\n    },\n    ProcessRunner {\n        command: String,\n        source: Error,\n    },\n    SerializeJson(Error),\n    Read {\n        path: PathBuf,\n        source: Error,\n    },\n    Write {\n        path: PathBuf,\n        source: Error,\n    },\n    ParseJson {\n        path: PathBuf,\n        source: Error,\n    },\n}"}} />
Errors raised by Fabric config loading and validation. ## Variants -### `PathNotFound(PathBuf)` - -
PathBuf)"}} />
- -The requested path does not exist. - -### `MissingEntrypoint(PathBuf)` - -
PathBuf)"}} />
+### `ResolveBaseDirectory` -A directory did not contain the expected Fabric entrypoint. +
-### `UnsupportedExtension(PathBuf)` - -
PathBuf)"}} />
- -A file extension is not recognized for Fabric config loading. - -### `UnknownProfile` - -
- -A requested profile is not present in an agent manifest. +The base directory could not be resolved to an absolute path. #### Fields -### `profile: String` - -Requested profile. - -### `agent: String` - -Agent name. - -### `available: Vec` - -Available profile names. - -### `ProfileError` - -
+### `path: PathBuf` -A profile config failed validation. +Base directory supplied by the caller. -#### Fields +### `source: Error` -### `path: PathBuf` +Underlying path-resolution error. -Profile path. +### `PathNotFound(PathBuf)` -### `message: String` +
PathBuf)"}} />
-Validation message. +The requested path does not exist. ### `UnknownAdapter` @@ -161,28 +129,6 @@ Requested schema name. Available schema names. -### `ProfileTargetNotConfig` - -
- -A profile path resolved to an agent manifest instead of a profile config. - -#### Fields - -### `profile: String` - -Profile name. - -### `path: PathBuf` - -Resolved path. - -### `ProfileSelectionNotSupported(PathBuf)` - -
PathBuf)"}} />
- -A profile was requested for a single profile config. - ### `UnsupportedRuntimeAdapter`
@@ -361,22 +307,6 @@ File path. Underlying IO error. -### `ParseYaml` - -
- -YAML parse failed. - -#### Fields - -### `path: PathBuf` - -File path. - -### `source: Error` - -Underlying YAML error. - ### `ParseJson`
diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/error/index.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/error/index.mdx index 569e37226..bc0a4a451 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/error/index.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/error/index.mdx @@ -2,7 +2,7 @@ title: "Module error" sidebar-title: "error" description: "Error types for Fabric core." -position: 78 +position: 67 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/error/type-result.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/error/type-result.mdx index 64e9cf199..011b5b223 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/error/type-result.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/error/type-result.mdx @@ -2,7 +2,7 @@ title: "Type Alias Result" sidebar-title: "Result" description: "Core Fabric result type." -position: 50 +position: 39 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/fn-version.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/fn-version.mdx index b677a330b..b9f5b49fb 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/fn-version.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/fn-version.mdx @@ -2,7 +2,7 @@ title: "Function version" sidebar-title: "version" description: "Returns the crate version compiled into this build." -position: 81 +position: 70 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/index.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/index.mdx index c52d13b64..0f9030b11 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/index.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/index.mdx @@ -23,19 +23,16 @@ Core config and runtime contract for NeMo Fabric. - `pub use config::AdapterTelemetrySupport;` - `pub use config::CapabilityPlan;` - `pub use config::ControlLocation;` -- `pub use config::EffectiveConfig;` - `pub use config::EnvironmentConfig;` - `pub use config::EnvironmentOwnership;` - `pub use config::EnvironmentPlan;` - `pub use config::FabricConfig;` -- `pub use config::FabricDocument;` - `pub use config::HarnessConfig;` - `pub use config::McpConfig;` - `pub use config::McpExposure;` - `pub use config::McpServerPlan;` - `pub use config::MetadataConfig;` - `pub use config::ModelConfig;` -- `pub use config::ProfileConfig;` - `pub use config::ResolutionStrategy;` - `pub use config::ResolveContext;` - `pub use config::ResolvedAdapterDescriptor;` @@ -48,15 +45,7 @@ Core config and runtime contract for NeMo Fabric. - `pub use config::TelemetryProvider;` - `pub use config::TelemetryProviderConfig;` - `pub use config::load_adapter_descriptor;` -- `pub use config::load_fabric_document;` -- `pub use config::resolve_effective_config;` -- `pub use config::resolve_effective_config_from_config;` -- `pub use config::resolve_effective_config_with_profiles;` -- `pub use config::resolve_run_plan;` - `pub use config::resolve_run_plan_from_config;` -- `pub use config::resolve_run_plan_from_effective_config;` -- `pub use config::resolve_run_plan_with_profiles;` -- `pub use config::validate_agent_directory;` - `pub use doctor::DoctorCheck;` - `pub use doctor::DoctorReport;` - `pub use doctor::DoctorStatus;` diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/enum-errorstage.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/enum-errorstage.mdx index 16442abed..48aa7dd9c 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/enum-errorstage.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/enum-errorstage.mdx @@ -30,7 +30,7 @@ Fabric lifecycle stage associated with an error.
-Configuration or profile loading failed. +Configuration resolution failed. ### `Plan` diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/index.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/index.mdx index 8e8af21f9..05f895e78 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/index.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/index.mdx @@ -2,7 +2,7 @@ title: "Module runtime" sidebar-title: "runtime" description: "Runtime invocation helpers." -position: 79 +position: 68 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-adapterinvocation.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-adapterinvocation.mdx index 4d332bd2e..24052b9de 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-adapterinvocation.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-adapterinvocation.mdx @@ -9,15 +9,23 @@ SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
EffectiveConfig,\n    pub runtime_context: RuntimeContext,\n    pub request: RunRequest,\n    pub capability_plan: CapabilityPlan,\n    pub telemetry_plan: Option<TelemetryPlan>,\n}"}} />
+
String,\n    pub base_dir: PathBuf,\n    pub config: FabricConfig,\n    pub runtime_context: RuntimeContext,\n    pub request: RunRequest,\n    pub capability_plan: CapabilityPlan,\n    pub telemetry_plan: Option<TelemetryPlan>,\n}"}} />
Adapter-facing invocation payload. ## Fields -### `effective_config: EffectiveConfig` +### `agent_name: String` -Merged agent config and provenance. +Stable agent name. + +### `base_dir: PathBuf` + +Absolute base directory used to resolve relative Fabric paths. + +### `config: FabricConfig` + +Complete typed Fabric config. ### `runtime_context: RuntimeContext` diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runrequest.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runrequest.mdx index f6f5fa597..0912f2d46 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runrequest.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runrequest.mdx @@ -29,7 +29,7 @@ Runtime context such as task, rollout, workflow, or caller metadata. ### `overrides: Option` -Per-invocation overrides allowed by the resolved profile. +Per-invocation overrides allowed by the resolved config. ## Implementations diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runresult.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runresult.mdx index 3f0018cbb..34db337ff 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runresult.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/runtime/struct-runresult.mdx @@ -9,7 +9,7 @@ SPDX-License-Identifier: Apache-2.0 */} Generated from `cargo doc --no-deps -p nemo-fabric-core`. -
String,\n    pub profiles: Vec<String>,\n    pub harness: String,\n    pub adapter_kind: AdapterKind,\n    pub adapter_id: Option<String>,\n    pub runtime_id: String,\n    pub invocation_id: String,\n    pub request_id: String,\n    pub status: RunStatus,\n    pub output: Value,\n    pub error: Option<ErrorInfo>,\n    pub artifacts: ArtifactManifest,\n    pub telemetry: Option<TelemetryRef>,\n    pub events: Vec<FabricEvent>,\n    pub metadata: BTreeMap<String, Value>,\n}"}} />
+
String,\n    pub harness: String,\n    pub adapter_kind: AdapterKind,\n    pub adapter_id: Option<String>,\n    pub runtime_id: String,\n    pub invocation_id: String,\n    pub request_id: String,\n    pub status: RunStatus,\n    pub output: Value,\n    pub error: Option<ErrorInfo>,\n    pub artifacts: ArtifactManifest,\n    pub telemetry: Option<TelemetryRef>,\n    pub events: Vec<FabricEvent>,\n    pub metadata: BTreeMap<String, Value>,\n}"}} />
Result from a Fabric-managed harness invocation. @@ -19,10 +19,6 @@ Result from a Fabric-managed harness invocation. Stable agent name. -### `profiles: Vec` - -Ordered profiles applied to this run. - ### `harness: String` Stable machine-readable harness identifier used for this run. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/enum-schemaname.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/enum-schemaname.mdx index 97a1e7f7c..b7cc4cbfb 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/enum-schemaname.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/enum-schemaname.mdx @@ -11,10 +11,8 @@ Generated from `cargo doc --no-deps -p nemo-fabric-core`. ```rust pub enum SchemaName { -Show 15 variants Agent, - Profile, +Show 13 variants Agent, AdapterDescriptor, - EffectiveConfig, RunPlan, AdapterInvocation, RuntimeContext, @@ -37,13 +35,7 @@ Public schema snapshots generated by Fabric.
-Base `agent.yaml` schema. - -### `Profile` - -
- -Profile overlay schema. +Complete typed Fabric config schema. ### `AdapterDescriptor` @@ -51,12 +43,6 @@ Profile overlay schema. Adapter descriptor schema. -### `EffectiveConfig` - -
- -Effective merged config schema. - ### `RunPlan`
@@ -131,7 +117,7 @@ Fabric lifecycle event schema. #### `ALL` -
15]"}} />
+
13]"}} />
All public schemas in stable output order. diff --git a/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/index.mdx b/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/index.mdx index 88d03afa2..a3475f92e 100644 --- a/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/index.mdx +++ b/docs/reference/api/rust-library-reference/nemo-fabric-core/schema/index.mdx @@ -2,7 +2,7 @@ title: "Module schema" sidebar-title: "schema" description: "JSON Schema generation for the public Fabric contract." -position: 80 +position: 69 --- {/* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 */} diff --git a/docs/sdk/python.mdx b/docs/sdk/python.mdx index 1df258e22..8c7bfaa0e 100644 --- a/docs/sdk/python.mdx +++ b/docs/sdk/python.mdx @@ -12,9 +12,8 @@ telemetry references. The SDK is config-first. Applications should construct a Pydantic `FabricConfig` from their own job, deployment, or evaluation config. -Portable file formats such as `agent.yaml` remain useful for examples, CI, and -reproducibility, but the SDK does not require callers to write intermediate -files before invoking NeMo Fabric. +Examples, CI jobs, and applications construct the typed config directly and +can use ordinary Python functions to create variants. Generated API reference pages remain the source of truth for exact signatures. This guide explains how the pieces are intended to fit together. @@ -97,7 +96,7 @@ Most application code works with four objects: | Concept | What It Represents | How Consumers Use It | | --- | --- | --- | | `FabricConfig` | Typed configuration for the harness, models, runtime, and capabilities. | Construct it from application config before planning or running. | -| `RunPlan` | The resolved config, selected adapter, and declared capabilities. | Inspect it before starting work when adapter selection or feature support matters. | +| `RunPlan` | The canonical config and path context, selected adapter, and declared capabilities. | Inspect it before starting work when adapter selection or feature support matters. | | `Runtime` | The Python object for one logical, stateful harness execution. | Use it to send ordered invocations and stop the execution. Use it as an async context manager for cleanup. | | `RunResult` | The normalized outcome of one invocation. | Read its status, output, error, events, artifacts, and correlation IDs. | @@ -151,8 +150,7 @@ Telemetry is enabled by adding entries to `telemetry.providers`; Relay-specific settings live in the top-level `relay` block. For evaluation or deployment variations, use ordinary Python functions and -copies of the typed config. Supply the final config to NeMo Fabric when the variation -does not need file-profile merge semantics. +copies of the typed config. Supply the complete final config to NeMo Fabric. ```python def review_agent_config(base, *, github_mcp: bool, relay: bool): @@ -193,12 +191,8 @@ The repository's uses this pattern for complete Hermes, Codex SDK, Deep Agents, environment, MCP, and telemetry variants. -When an in-memory caller needs the same ordered overlay behavior as file-backed -profiles, construct `FabricProfileConfig` values and pass them through -`profiles=[...]`. NeMo Fabric does not accept raw profile mappings. - -If a config contains relative paths, pass a `base_dir` to `resolve(...)`, -`plan(...)`, `doctor(...)`, `run(...)`, or `start_runtime(...)`. The base +If a config contains relative paths, pass a `base_dir` to `plan(...)`, +`doctor(...)`, `run(...)`, or `start_runtime(...)`. The base directory anchors skills, workspaces, artifacts, and other relative paths to the caller's package or job layout. @@ -210,10 +204,9 @@ multiple independent runtimes. | API | Async | Use When | Notes | | --- | --- | --- | --- | -| `Fabric.resolve(config, base_dir=...)` | No | You need the normalized effective config without resolving an adapter. | Does not start a runtime. | | `Fabric.plan(config, base_dir=...)` | No | You need to inspect the selected adapter, capability mapping, and runtime capabilities before running. | Does not start a runtime. | | `Fabric.doctor(config, base_dir=...)` | Yes | You need preflight diagnostics for adapter availability, config support, and environment assumptions. | Checks may touch runtime dependencies. | -| `Fabric.run(config, input=...)` | Yes | You need one complete start, invoke, result, stop lifecycle. | Pass a `RunRequest` instead when the invocation needs IDs, context, or overrides. | +| `Fabric.run(config, base_dir=..., input=...)` | Yes | You need one complete start, invoke, result, stop lifecycle. | `base_dir` is optional. Pass a `RunRequest` instead when the invocation needs IDs, context, or overrides. | | `Fabric.start_runtime(config, ...)` | Yes | You need state across multiple ordered invocations. | Returns a `Runtime`. Use it as an async context manager. | | `Runtime.invoke(...)` | Yes | You need one turn on an existing runtime. | A runtime permits one active invocation at a time. | | `Runtime.stop()` | Yes | You need to stop or detach from the runtime. | Called automatically when using `async with`. | @@ -406,7 +399,7 @@ environment, skills, MCP, telemetry, tools, artifacts, and request context. Use `harness.settings` for adapter-owned configuration that the selected adapter understands. Examples include Hermes-specific launch options, Codex SDK controls, -or adapter-specific config file locations. +or adapter-specific launch paths. Use `metadata` for caller-owned annotations that NeMo Fabric should preserve and echo back, but not interpret. @@ -442,9 +435,8 @@ around that contract. ### Schemas And Python Models The SDK's Pydantic models are maintained against the Rust-generated public -schemas. Use the schemas for persisted field definitions and the generated API -reference for exact Python signatures. New application code should prefer -`FabricConfig` and `RunRequest` for validated SDK inputs. +schemas. The schemas describe the typed cross-language contracts. Use the +generated API reference for exact Python signatures. | Contract | Source | | --- | --- | @@ -460,20 +452,20 @@ reference for exact Python signatures. New application code should prefer NeMo Fabric uses explicit contract versions where persisted or independently maintained artifacts cross package boundaries: -- `schema_version` identifies portable config documents such as `agent.yaml` - and profile files. +- `schema_version` identifies the typed Fabric config contract transported + across SDK and language boundaries. - `contract_version` identifies the adapter descriptor contract implemented by a `fabric-adapter.json` file. - Python and Rust package versions identify the installed SDK/core release. -NeMo Fabric versions top-level persisted documents and independently maintained -contracts. It does not version each config subsection independently. For +NeMo Fabric versions top-level typed contracts and independently maintained adapter +metadata. It does not version each config subsection independently. For example, MCP, skills, models, telemetry, and runtime fields evolve under the enclosing `schema_version`. NeMo Fabric validates adapter descriptor contract versions during planning. Package semver identifies the installed implementation, but it is not the compatibility -contract for saved agent packages or independently maintained adapters. +contract for independently maintained adapters. ### Config Extensibility diff --git a/examples/code_review_agent/README.md b/examples/code_review_agent/README.md index d6efeb8a6..9762d8e98 100644 --- a/examples/code_review_agent/README.md +++ b/examples/code_review_agent/README.md @@ -9,7 +9,7 @@ This example reviews the repository under `repos/my-service`. It constructs a complete `FabricConfig` with the public Pydantic models and passes it directly to the Python SDK. Variants are independent deep copies of that config. -The example does not serialize configs to YAML or use profiles. +Each variant is an independent Python factory that returns a complete config. ## Set up diff --git a/examples/harbor/calculator/task/environment/fabric/adapters/scripted/run.py b/examples/harbor/calculator/task/environment/fabric/adapters/scripted/run.py index fe12b6b50..7c6bc74c8 100644 --- a/examples/harbor/calculator/task/environment/fabric/adapters/scripted/run.py +++ b/examples/harbor/calculator/task/environment/fabric/adapters/scripted/run.py @@ -2,6 +2,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 + """Deterministic adapter used by the credential-free Harbor example.""" import json diff --git a/examples/notebooks/01_quickstart.ipynb b/examples/notebooks/01_quickstart.ipynb index 29af40c2b..ec207bf81 100644 --- a/examples/notebooks/01_quickstart.ipynb +++ b/examples/notebooks/01_quickstart.ipynb @@ -384,8 +384,8 @@ "\n", "print(\"adapter :\", plan.adapter.adapter_id)\n", "print(\"harness :\", plan.adapter.harness)\n", - "print(\"in/out :\", plan.effective_config.config.runtime.input_schema,\n", - " \"/\", plan.effective_config.config.runtime.output_schema)\n", + "print(\"in/out :\", plan.config.runtime.input_schema,\n", + " \"/\", plan.config.runtime.output_schema)\n", "print(\"caps : streaming=%s updates=%s cancellation=%s\" % (\n", " plan.capabilities.streaming,\n", " plan.capabilities.updates,\n", diff --git a/examples/notebooks/02_variations.ipynb b/examples/notebooks/02_variations.ipynb index c81e97155..68f6a8832 100644 --- a/examples/notebooks/02_variations.ipynb +++ b/examples/notebooks/02_variations.ipynb @@ -245,8 +245,8 @@ "for harness in HARNESSES:\n", " cfg = for_harness(harness)\n", " plan = fabric.plan(cfg, base_dir=BASE_DIR)\n", - " rc = plan.effective_config.config.runtime\n", - " model = plan.effective_config.config.models[\"default\"][\"model\"]\n", + " rc = plan.config.runtime\n", + " model = plan.config.models[\"default\"][\"model\"]\n", " print(f\"### {harness['name']}\")\n", " print(f\" adapter = {plan.adapter.adapter_id}\")\n", " print(f\" model = {model} input schema = {rc.input_schema}\")\n", diff --git a/pypi.md b/pypi.md index a8b7b63e6..b760799bf 100644 --- a/pypi.md +++ b/pypi.md @@ -12,9 +12,9 @@ NeMo Fabric standardizes how applications configure, launch, invoke, and collect artifacts from agent harnesses. It provides: - a versioned, typed configuration contract; -- profile-based configuration for evaluation and ablation runs; +- ordinary Python composition for experiment variants; - adapter integrations for harness-specific launch and control; -- a Python SDK backed by a Rust core; +- a Python SDK backed by the Rust core; - normalized run results, artifact manifests, and telemetry references. ## Install @@ -22,7 +22,7 @@ collect artifacts from agent harnesses. It provides: Install the core runtime and Python SDK: ```bash -pip install "nemo-fabric[runtime]" +pip install nemo-fabric ``` To use a supported agent harness, install its adapter extra: @@ -58,17 +58,18 @@ NeMo Fabric supports Python versions 3.11-3.14, however some of the integrations ## Core Concepts -- **Agent source:** Provide either an agent package path or a typed - `FabricConfig`. -- **Typed configuration:** Construct configuration in memory with the Python - SDK, or use `agent.yaml` as a portable representation. -- **Profiles:** Vary the harness, model, MCP servers, tools, skills, telemetry, - or environment without editing the base configuration. +- **Typed configuration:** Construct a complete `FabricConfig` in Python and + use ordinary functions to create experiment variants. - **Adapters:** Select harness-specific integrations with `harness.adapter_id`. - **Artifacts:** Receive normalized output, logs, patches, and telemetry references through an `ArtifactManifest`. +The experimental `nemo-fabric` CLI is distributed separately from the Python +package. It selects complete typed configs from built-in presets and maintained +examples. Applications that need a stable integration surface should use the +Python SDK. + ## Learn More Refer to the [NVIDIA NeMo Fabric documentation](https://nvidia-nemo-fabric.docs.buildwithfern.com/nemo/fabric) diff --git a/pyproject.toml b/pyproject.toml index 9eade9c53..71bd682b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,9 @@ license = "Apache-2.0" license-files = ["LICENSE"] readme = "pypi.md" requires-python = ">=3.11" -dependencies = [] +dependencies = [ + "nemo-fabric-runtime == 0.1.0", +] [project.urls] Repository = "https://github.com/NVIDIA/nemo-fabric/" diff --git a/python/src/nemo_fabric/__init__.py b/python/src/nemo_fabric/__init__.py index 96cceeaa0..df761ccf0 100644 --- a/python/src/nemo_fabric/__init__.py +++ b/python/src/nemo_fabric/__init__.py @@ -13,13 +13,11 @@ from nemo_fabric.models import EnvironmentConfig from nemo_fabric.models import FabricBaseModel from nemo_fabric.models import FabricConfig -from nemo_fabric.models import FabricProfileConfig from nemo_fabric.models import HarnessConfig from nemo_fabric.models import McpConfig from nemo_fabric.models import McpServerConfig from nemo_fabric.models import MetadataConfig from nemo_fabric.models import ModelConfig -from nemo_fabric.models import ProfileRegistryConfig from nemo_fabric.models import RelayAtifConfig from nemo_fabric.models import RelayAtofConfig from nemo_fabric.models import RelayAtofEndpointConfig @@ -43,7 +41,6 @@ from nemo_fabric.types import ArtifactRef from nemo_fabric.types import DoctorCheck from nemo_fabric.types import DoctorReport -from nemo_fabric.types import EffectiveConfig from nemo_fabric.types import ErrorInfo from nemo_fabric.types import FabricEvent from nemo_fabric.types import RunOutput @@ -59,13 +56,11 @@ "ArtifactRef", "DoctorCheck", "DoctorReport", - "EffectiveConfig", "EnvironmentConfig", "ErrorInfo", "Fabric", "FabricBaseModel", "FabricConfig", - "FabricProfileConfig", "FabricCapabilityError", "FabricConfigError", "FabricError", @@ -75,7 +70,6 @@ "McpServerConfig", "MetadataConfig", "ModelConfig", - "ProfileRegistryConfig", "RelayAtifConfig", "RelayAtofConfig", "RelayAtofEndpointConfig", diff --git a/python/src/nemo_fabric/_config_sources.py b/python/src/nemo_fabric/_config_sources.py deleted file mode 100644 index 7b3337d33..000000000 --- a/python/src/nemo_fabric/_config_sources.py +++ /dev/null @@ -1,90 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -"""Agent source normalization for the Fabric Python SDK.""" - -from __future__ import annotations - -import json -import os -from collections.abc import Mapping, Sequence -from typing import Any - -from nemo_fabric.errors import FabricConfigError -from nemo_fabric.models import FabricConfig, FabricProfileConfig - -PathSource = str | os.PathLike[str] -TypedConfigSource = FabricConfig -AgentSource = PathSource | TypedConfigSource -PathProfiles = str | Sequence[str] -TypedProfiles = Sequence[FabricProfileConfig] - - -def is_config_source(value: Any) -> bool: - return isinstance(value, FabricConfig) - - -def path_arg(value: Any) -> str: - if isinstance(value, (str, os.PathLike)): - return os.fspath(value) - if isinstance(value, Mapping): - raise FabricConfigError( - "agent mappings are not accepted directly; " - "use FabricConfig.from_mapping(...) first" - ) - raise FabricConfigError( - "agent must be a path-like source or FabricConfig" - ) - - -def path_profiles(profiles: PathProfiles | None) -> list[str]: - if profiles is None: - return [] - if isinstance(profiles, str): - values = [profiles] - elif isinstance(profiles, bytes): - raise FabricConfigError("profiles must be profile names, not bytes") - elif isinstance(profiles, Mapping): - raise FabricConfigError("profiles must be profile names, not a mapping") - else: - values = list(profiles) - if not all(isinstance(profile, str) and profile for profile in values): - raise FabricConfigError("path profiles must contain only non-empty strings") - return values - - -def config_profiles( - profiles: TypedProfiles | None, -) -> list[FabricProfileConfig]: - if profiles is None: - return [] - if isinstance(profiles, (str, bytes)): - raise FabricConfigError( - "FabricConfig profiles must contain FabricProfileConfig values" - ) - values = list(profiles) - if not all(isinstance(profile, FabricProfileConfig) for profile in values): - raise FabricConfigError( - "FabricConfig profiles must contain FabricProfileConfig values" - ) - return values - - -def validate_base_dir(agent: AgentSource, base_dir: PathSource | None) -> str | None: - if not is_config_source(agent): - if base_dir is not None: - raise FabricConfigError("base_dir is only valid with a typed config source") - return None - return None if base_dir is None else os.fspath(base_dir) - - -def config_json(config: TypedConfigSource) -> str: - if not is_config_source(config): - raise FabricConfigError("config must be a FabricConfig") - return json.dumps(config.to_mapping()) - - -def profiles_json(profiles: Sequence[FabricProfileConfig]) -> str | None: - if not profiles: - return None - return json.dumps([profile.to_mapping() for profile in profiles]) diff --git a/python/src/nemo_fabric/_native.pyi b/python/src/nemo_fabric/_native.pyi index 1f7ad6b85..8df4b4bc0 100644 --- a/python/src/nemo_fabric/_native.pyi +++ b/python/src/nemo_fabric/_native.pyi @@ -2,36 +2,16 @@ # SPDX-License-Identifier: Apache-2.0 def version() -> str: ... -def validate(path: str) -> str: ... -def inspect(path: str, profile: str | list[str] | None = None) -> str: ... -def resolve_config( - config_json: str, - profiles_json: str | None = None, - base_dir: str | None = None, -) -> str: ... -def plan(path: str, profile: str | list[str] | None = None) -> str: ... def plan_config( config_json: str, - profiles_json: str | None = None, base_dir: str | None = None, ) -> str: ... -def doctor(path: str, profile: str | list[str] | None = None) -> str: ... def doctor_config( config_json: str, - profiles_json: str | None = None, base_dir: str | None = None, ) -> str: ... -def run( - path: str, - profile: str | list[str] | None = None, - input_text: str | None = None, - input_file: str | None = None, - request_json: str | None = None, - request_file: str | None = None, -) -> str: ... def run_config( config_json: str, - profiles_json: str | None = None, base_dir: str | None = None, input_text: str | None = None, input_file: str | None = None, diff --git a/python/src/nemo_fabric/client.py b/python/src/nemo_fabric/client.py index 9224fdb5a..64dc088af 100644 --- a/python/src/nemo_fabric/client.py +++ b/python/src/nemo_fabric/client.py @@ -8,22 +8,9 @@ import asyncio import importlib import json -from collections.abc import Mapping, Sequence -from typing import Any, overload - -from nemo_fabric._config_sources import ( - AgentSource, - PathProfiles, - PathSource, - TypedProfiles, - config_json, - config_profiles, - is_config_source, - path_arg, - path_profiles, - profiles_json, - validate_base_dir, -) +import os +from collections.abc import Mapping +from typing import Any from nemo_fabric.errors import ( FabricConfigError, FabricError, @@ -40,7 +27,6 @@ ) from nemo_fabric.types import ( DoctorReport, - EffectiveConfig, RunPlan, RunResult, ) @@ -54,14 +40,13 @@ class Fabric: """Primary Python entrypoint for NeMo Fabric. - The client accepts either a path-backed agent package or a typed - ``FabricConfig``. Path-backed sources select profiles by name; typed sources - accept ordered ``FabricProfileConfig`` values and may use - ``base_dir`` to resolve relative paths. All inspection and execution APIs - return typed, read-only mapping models. + Every lifecycle method accepts a complete, typed ``FabricConfig`` plus an + optional ``base_dir`` used to resolve relative paths. Compose variants in + Python before calling the SDK. The ``doctor()``, ``plan()``, and ``run()`` + results are typed, read-only mapping models. ``start_runtime()`` returns an + active ``Runtime`` handle. - ``Fabric`` is native-only. The ``fabric`` CLI is a separate public - surface over the same Rust core; SDK calls raise + ``Fabric`` uses the native Rust extension. SDK calls raise ``FabricNativeUnavailableError`` when the native extension is not installed. @@ -69,174 +54,50 @@ class Fabric: multi-turn examples. """ - @overload - def resolve( - self, - agent: PathSource, - *, - profiles: PathProfiles | None = None, - base_dir: None = None, - ) -> EffectiveConfig: ... - - @overload - def resolve( - self, - agent: FabricConfig, - *, - profiles: TypedProfiles | None = None, - base_dir: PathSource | None = None, - ) -> EffectiveConfig: ... - - def resolve( - self, - agent: AgentSource, - *, - profiles: PathProfiles | TypedProfiles | None = None, - base_dir: PathSource | None = None, - ) -> EffectiveConfig: - """Resolve an agent source and its ordered profile overlays. - - Resolution validates and normalizes configuration but does not resolve - an adapter or compute runtime capabilities. Use ``plan()`` when those - execution details are required. - - Args: - agent: Agent-package directory or config-file path, or a typed - ``FabricConfig``. Raw - mappings are not accepted; convert them with - ``FabricConfig.from_mapping()``. - profiles: One profile name or an ordered sequence of names for a - path-backed source. For a typed source, an ordered sequence of - ``FabricProfileConfig`` values. - base_dir: Base directory for resolving relative paths in a typed - config. Valid only when ``agent`` is a typed config source. - - Returns: - The normalized ``EffectiveConfig`` snapshot. - - Raises: - FabricConfigError: If the source, profile stack, or resolved config - is invalid. - FabricNativeUnavailableError: If the native extension is not - installed. - """ - - native = self._require_native_module("resolve") - try: - if is_config_source(agent): - typed_profiles = config_profiles(profiles) # type: ignore[arg-type] - raw = native.resolve_config( - config_json(agent), - profiles_json(typed_profiles), - validate_base_dir(agent, base_dir), - ) - else: - validate_base_dir(agent, base_dir) - raw = native.inspect( - path_arg(agent), path_profiles(profiles) # type: ignore[arg-type] - ) - return EffectiveConfig.from_mapping(json.loads(raw)) - except FabricError: - raise - except Exception as error: - raise FabricConfigError(str(error)) from error - - @overload def plan( self, - agent: PathSource, + config: FabricConfig, *, - profiles: PathProfiles | None = None, - base_dir: None = None, - ) -> RunPlan: ... - - @overload - def plan( - self, - agent: FabricConfig, - *, - profiles: TypedProfiles | None = None, - base_dir: PathSource | None = None, - ) -> RunPlan: ... - - def plan( - self, - agent: AgentSource, - *, - profiles: PathProfiles | TypedProfiles | None = None, - base_dir: PathSource | None = None, + base_dir: str | os.PathLike[str] | None = None, ) -> RunPlan: - """Resolve an agent source into an immutable execution plan. + """Resolve a complete typed configuration into an immutable execution plan. - Planning applies profiles, resolves the selected adapter, and reports - optional runtime capabilities such as streaming, updates, and - cancellation. It does not start the runtime. + Planning resolves the selected adapter and reports optional runtime + capabilities such as streaming, updates, and cancellation. Planning + does not start the runtime. Args: - agent: Agent-package directory or config-file path, or a typed - ``FabricConfig``. Raw - mappings are not accepted. - profiles: One profile name or an ordered sequence of names for a - path-backed source. For a typed source, an ordered sequence of - ``FabricProfileConfig`` values. - base_dir: Base directory for resolving relative paths in a typed - config. Valid only when ``agent`` is a typed config source. + config: Complete typed ``FabricConfig``. Raw mappings are not + accepted. + base_dir: Base directory for resolving relative paths. Returns: - A ``RunPlan`` containing the effective config, adapter, and - declared runtime capabilities. + A ``RunPlan`` containing the canonical config, path context, + adapter, and declared runtime capabilities. Raises: - FabricConfigError: If the source, profile stack, config, or adapter - resolution is invalid. + FabricConfigError: If the config or adapter resolution is invalid. FabricNativeUnavailableError: If the native extension is not installed. """ native = self._require_native_module("plan") try: - if is_config_source(agent): - typed_profiles = config_profiles(profiles) # type: ignore[arg-type] - raw = native.plan_config( - config_json(agent), - profiles_json(typed_profiles), - validate_base_dir(agent, base_dir), - ) - else: - validate_base_dir(agent, base_dir) - raw = native.plan( - path_arg(agent), path_profiles(profiles) # type: ignore[arg-type] - ) + raw = native.plan_config( + _config_json(config), + _base_dir_arg(base_dir), + ) return RunPlan.from_mapping(json.loads(raw)) except FabricError: raise except Exception as error: raise FabricConfigError(str(error)) from error - @overload async def doctor( self, - agent: PathSource, + config: FabricConfig, *, - profiles: PathProfiles | None = None, - base_dir: None = None, - ) -> DoctorReport: ... - - @overload - async def doctor( - self, - agent: FabricConfig, - *, - profiles: TypedProfiles | None = None, - base_dir: PathSource | None = None, - ) -> DoctorReport: ... - - async def doctor( - self, - agent: AgentSource, - *, - profiles: PathProfiles | TypedProfiles | None = None, - base_dir: PathSource | None = None, + base_dir: str | os.PathLike[str] | None = None, ) -> DoctorReport: """Diagnose a planned agent without starting its runtime. @@ -244,13 +105,8 @@ async def doctor( environment requirements using the native Fabric core. Args: - agent: Agent-package directory or config-file path, or a typed - ``FabricConfig``. - profiles: One profile name or an ordered sequence of names for a - path-backed source. For a typed source, an ordered sequence of - ``FabricProfileConfig`` values. - base_dir: Base directory for resolving relative paths in a typed - config. Valid only when ``agent`` is a typed config source. + config: Complete typed ``FabricConfig``. + base_dir: Base directory for resolving relative paths. Returns: A ``DoctorReport`` with aggregate status and ordered checks. @@ -265,18 +121,10 @@ async def doctor( native = self._require_native_module("doctor") def diagnose() -> DoctorReport: - if is_config_source(agent): - typed_profiles = config_profiles(profiles) # type: ignore[arg-type] - raw = native.doctor_config( - config_json(agent), - profiles_json(typed_profiles), - validate_base_dir(agent, base_dir), - ) - else: - validate_base_dir(agent, base_dir) - raw = native.doctor( - path_arg(agent), path_profiles(profiles) # type: ignore[arg-type] - ) + raw = native.doctor_config( + _config_json(config), + _base_dir_arg(base_dir), + ) return DoctorReport.from_mapping(json.loads(raw)) try: @@ -286,34 +134,11 @@ def diagnose() -> DoctorReport: except Exception as error: raise FabricConfigError(str(error)) from error - @overload async def run( self, - agent: PathSource, + config: FabricConfig, *, - profiles: PathProfiles | None = None, - base_dir: None = None, - input: Any = None, - request: RunRequest | None = None, - ) -> RunResult: ... - - @overload - async def run( - self, - agent: FabricConfig, - *, - profiles: TypedProfiles | None = None, - base_dir: PathSource | None = None, - input: Any = None, - request: RunRequest | None = None, - ) -> RunResult: ... - - async def run( - self, - agent: AgentSource, - *, - profiles: PathProfiles | TypedProfiles | None = None, - base_dir: PathSource | None = None, + base_dir: str | os.PathLike[str] | None = None, input: Any = None, request: RunRequest | None = None, ) -> RunResult: @@ -325,13 +150,8 @@ async def run( Fabric attempts to stop a started runtime even when invocation fails. Args: - agent: Agent-package directory or config-file path, or a typed - ``FabricConfig``. - profiles: One profile name or an ordered sequence of names for a - path-backed source. For a typed source, an ordered sequence of - ``FabricProfileConfig`` values. - base_dir: Base directory for resolving relative paths in a typed - config. Valid only when ``agent`` is a typed config source. + config: Complete typed ``FabricConfig``. + base_dir: Base directory for resolving relative paths. input: JSON-compatible invocation input. request: Complete validated ``RunRequest``. @@ -348,11 +168,7 @@ async def run( normalized result can be returned. """ - plan = await _call_blocking( - lambda: self.plan( # type: ignore[arg-type] - agent, profiles=profiles, base_dir=base_dir - ) - ) + plan = await _call_blocking(lambda: self.plan(config, base_dir=base_dir)) request_payload = _run_request_payload( input=input, request=request, @@ -362,32 +178,11 @@ async def run( await _run_native_lifecycle(native, plan.to_mapping(), request_payload) ) - @overload - async def start_runtime( - self, - agent: PathSource, - *, - profiles: PathProfiles | None = None, - base_dir: None = None, - overrides: Mapping[str, Any] | None = None, - ) -> Runtime: ... - - @overload - async def start_runtime( - self, - agent: FabricConfig, - *, - profiles: TypedProfiles | None = None, - base_dir: PathSource | None = None, - overrides: Mapping[str, Any] | None = None, - ) -> Runtime: ... - async def start_runtime( self, - agent: AgentSource, + config: FabricConfig, *, - profiles: PathProfiles | TypedProfiles | None = None, - base_dir: PathSource | None = None, + base_dir: str | os.PathLike[str] | None = None, overrides: Mapping[str, Any] | None = None, ) -> Runtime: """Start a stateful runtime for one or more ordered invocations. @@ -396,13 +191,8 @@ async def start_runtime( recursively merged below invocation-scoped overrides. Args: - agent: Agent-package directory or config-file path, or a typed - ``FabricConfig``. - profiles: One profile name or an ordered sequence of names for a - path-backed source. For a typed source, an ordered sequence of - ``FabricProfileConfig`` values. - base_dir: Base directory for resolving relative paths in a typed - config. Valid only when ``agent`` is a typed config source. + config: Complete typed ``FabricConfig``. + base_dir: Base directory for resolving relative paths. overrides: JSON-compatible overrides applied to every invocation in the runtime unless superseded by invocation overrides. @@ -418,11 +208,7 @@ async def start_runtime( """ runtime_overrides = _json_mapping(overrides, "runtime overrides") - plan = await _call_blocking( - lambda: self.plan( # type: ignore[arg-type] - agent, profiles=profiles, base_dir=base_dir - ) - ) + plan = await _call_blocking(lambda: self.plan(config, base_dir=base_dir)) native = self._require_native_module("start_runtime") started_runtime: dict[str, Any] | None = None @@ -470,3 +256,18 @@ def _require_native_module(self, method: str) -> Any: code="native_unavailable", ) return native + + +def _config_json(config: FabricConfig) -> str: + if not isinstance(config, FabricConfig): + if isinstance(config, Mapping): + raise FabricConfigError( + "config mappings are not accepted directly; " + "use FabricConfig.from_mapping(...) first" + ) + raise FabricConfigError("config must be a FabricConfig") + return json.dumps(config.to_mapping()) + + +def _base_dir_arg(base_dir: str | os.PathLike[str] | None) -> str | None: + return None if base_dir is None else os.fspath(base_dir) diff --git a/python/src/nemo_fabric/errors.py b/python/src/nemo_fabric/errors.py index 401704a9a..2af0a058a 100644 --- a/python/src/nemo_fabric/errors.py +++ b/python/src/nemo_fabric/errors.py @@ -51,7 +51,7 @@ def __init__( class FabricConfigError(FabricError): - """Invalid SDK input, request shape, profile stack, or resolved config.""" + """Invalid SDK input, request shape, factory, or resolved config.""" class FabricRuntimeError(FabricError): diff --git a/python/src/nemo_fabric/models.py b/python/src/nemo_fabric/models.py index ee6b956a8..3b7dd813d 100644 --- a/python/src/nemo_fabric/models.py +++ b/python/src/nemo_fabric/models.py @@ -388,12 +388,6 @@ def remove_provider(self, provider: Literal["relay", "native"]) -> Self: return self -class ProfileRegistryConfig(FabricBaseModel): - """Profile discovery config for portable file-backed agent packages.""" - - directories: list[str | Path] = Field(default_factory=list) - - class ToolsConfig(FabricBaseModel): """Harness-neutral tool capability configuration.""" @@ -413,7 +407,6 @@ class FabricConfig(FabricBaseModel): skills: SkillConfig | None = None telemetry: TelemetryConfig | None = None relay: RelayConfig | dict[str, Any] | None = None - profiles: ProfileRegistryConfig | dict[str, Any] | None = None tools: ToolsConfig | dict[str, Any] | None = None @classmethod @@ -526,23 +519,6 @@ def enable_relay( return self -class FabricProfileConfig(FabricBaseModel): - """Typed profile overlay used when a Python caller wants file-style overlays.""" - - schema_version: str = "fabric.profile/v1alpha1" - name: str = Field(min_length=1) - description: str | None = None - harness: HarnessConfig | dict[str, Any] | None = None - runtime: RuntimeConfig | dict[str, Any] | None = None - environment: EnvironmentConfig | dict[str, Any] | None = None - models: dict[str, ModelConfig | dict[str, Any]] | None = None - mcp: McpConfig | dict[str, Any] | None = None - skills: SkillConfig | dict[str, Any] | None = None - telemetry: TelemetryConfig | dict[str, Any] | None = None - relay: RelayConfig | dict[str, Any] | None = None - tools: ToolsConfig | dict[str, Any] | None = None - - class RunRequest(FabricBaseModel): """One validated Fabric invocation request.""" diff --git a/python/src/nemo_fabric/types.py b/python/src/nemo_fabric/types.py index 1298b71af..f9a4cb1e0 100644 --- a/python/src/nemo_fabric/types.py +++ b/python/src/nemo_fabric/types.py @@ -64,15 +64,6 @@ def _required_text(value: Any, name: str) -> str: return value -def _required_profiles(data: Mapping[str, Any], owner: str) -> tuple[str, ...]: - if "profiles" not in data: - raise FabricConfigError(f"{owner} profiles is required") - profiles = data["profiles"] - if isinstance(profiles, (str, bytes)) or not isinstance(profiles, Sequence): - raise FabricConfigError(f"{owner} profiles must be an ordered sequence of strings") - return tuple(_required_text(profile, f"{owner} profile") for profile in profiles) - - def _boolean(value: Any, name: str) -> bool: if not isinstance(value, bool): raise FabricConfigError(f"{name} must be a boolean") @@ -325,8 +316,8 @@ def from_mapping(cls, value: Mapping[str, Any]) -> "_EnvironmentConfig": class _SkillConfig(_ConfigMapping): """Skill capability configuration. - The shape matches the ``skills`` section in ``agent.yaml`` while providing - small authoring helpers for Python callers. + The shape matches the ``skills`` section of ``FabricConfig`` while + providing small authoring helpers for Python callers. """ _fields = frozenset({"paths"}) @@ -550,12 +541,12 @@ def _provider(cls, provider: str) -> str: return value -class _ResolvedFabricConfig(_ConfigMapping): - """Mutable typed representation of a Fabric agent configuration. +class _FabricConfigSnapshot(_ConfigMapping): + """Typed snapshot of the Fabric configuration stored in a run plan. - The object follows the same schema as ``agent.yaml``. It is mutable while - callers compose a job, then copied into immutable resolution and plan - snapshots. Unknown fields survive round trips through ``extra_fields``. + It is reconstructed from the native plan payload and exposed through the + immutable ``RunPlan`` mapping. Unknown fields survive round trips through + ``extra_fields``. Attributes: schema_version: Agent schema identifier. @@ -568,7 +559,6 @@ class _ResolvedFabricConfig(_ConfigMapping): skills: Optional skill configuration. telemetry: Optional telemetry configuration. relay: Optional Relay integration configuration. - profiles: Optional profile-discovery configuration. tools: Optional harness-neutral tool configuration. extra_fields: Preserved extension fields not recognized by this SDK. """ @@ -585,7 +575,6 @@ class _ResolvedFabricConfig(_ConfigMapping): "skills", "telemetry", "relay", - "profiles", "tools", } ) @@ -604,7 +593,6 @@ def __init__( skills: Mapping[str, Any] | None = None, telemetry: Mapping[str, Any] | None = None, relay: Mapping[str, Any] | None = None, - profiles: Mapping[str, Any] | None = None, tools: Mapping[str, Any] | None = None, extra_fields: Mapping[str, Any] | None = None, ) -> None: @@ -634,7 +622,6 @@ def __init__( ("skills", skills_value), ("telemetry", telemetry_value), ("relay", relay_value), - ("profiles", profiles), ("tools", tools_value), ): if item is not None: @@ -642,10 +629,15 @@ def __init__( super().__init__(values, extra_fields=extra_fields) @classmethod - def from_mapping(cls, value: Mapping[str, Any]) -> "_ResolvedFabricConfig": - """Build a typed agent config from the ``agent.yaml`` mapping shape.""" + def from_mapping(cls, value: Mapping[str, Any]) -> "_FabricConfigSnapshot": + """Build a typed agent config from a mapping.""" data = _mapping(value, "FabricConfig") + if "profiles" in data: + raise FabricConfigError( + "FabricConfig profiles are no longer supported; " + "compose a complete typed config before calling the SDK" + ) if "metadata" not in data: raise FabricConfigError("FabricConfig metadata is required") if "harness" not in data: @@ -661,7 +653,6 @@ def from_mapping(cls, value: Mapping[str, Any]) -> "_ResolvedFabricConfig": skills=data.get("skills"), telemetry=data.get("telemetry"), relay=data.get("relay"), - profiles=data.get("profiles"), tools=data.get("tools"), extra_fields={key: item for key, item in data.items() if key not in cls._fields}, ) @@ -724,7 +715,7 @@ def add_mcp_server( url: str, exposure: str = "harness_native", extra_fields: Mapping[str, Any] | None = None, - ) -> "_ResolvedFabricConfig": + ) -> "_FabricConfigSnapshot": """Add or replace a named MCP server and return this config.""" self.mcp.add_server( @@ -736,13 +727,13 @@ def add_mcp_server( ) return self - def add_skill_path(self, path: str | Path) -> "_ResolvedFabricConfig": + def add_skill_path(self, path: str | Path) -> "_FabricConfigSnapshot": """Add a skill path and return this config.""" self.skills.add_path(path) return self - def block_tools(self, *tools: str) -> _ResolvedFabricConfig: + def block_tools(self, *tools: str) -> _FabricConfigSnapshot: """Block adapter-native tool names or toolsets and return this config.""" self.tools.block(*tools) @@ -756,7 +747,7 @@ def enable_relay( observability: Mapping[str, Any] | None = None, components: Sequence[Mapping[str, Any]] | None = None, policy: Mapping[str, Any] | None = None, - ) -> "_ResolvedFabricConfig": + ) -> "_FabricConfigSnapshot": """Enable NeMo Relay telemetry and return this config.""" self.telemetry.enable_relay() @@ -943,61 +934,33 @@ def _normalize(cls, data: dict[str, Any]) -> dict[str, Any]: return data -class EffectiveConfig(FabricMapping): - """Immutable result of config loading and ordered profile application. - - Attributes: - agent_name: Resolved agent name. - profiles: Applied profile names in caller order. - agent_root: Root directory of the path-backed agent source. - config_path: Source config path, or ``None`` for typed configs. - config_root: Base directory used to resolve relative paths. - config: Fully resolved typed ``FabricConfig``. - """ - - agent_name: str - profiles: Sequence[str] - agent_root: Path - config_path: Path | None - config_root: Path - config: _ResolvedFabricConfig - _fields = frozenset({"agent_name", "profiles", "agent_root", "config_path", "config_root", "config"}) - - @classmethod - def _normalize(cls, data: dict[str, Any]) -> dict[str, Any]: - data["profiles"] = _required_profiles(data, "EffectiveConfig") - data["agent_root"] = Path(data.get("agent_root", ".")) - data["config_root"] = Path(data.get("config_root", ".")) - data["config_path"] = None if data.get("config_path") is None else Path(data["config_path"]) - data["config"] = _ResolvedFabricConfig.from_mapping(data.get("config", {})) - return data - - class RunPlan(FabricMapping): """Immutable execution plan produced before a runtime is started. Attributes: - effective_config: Resolved configuration snapshot. agent_name: Resolved agent name. - profiles: Applied profile names in caller order. + base_dir: Base directory used to resolve relative paths. + config: Typed configuration snapshot. adapter: Resolved adapter identity. capabilities: Operations declared by the resolved runtime. """ - effective_config: EffectiveConfig agent_name: str - profiles: Sequence[str] + base_dir: Path + config: _FabricConfigSnapshot adapter: AdapterInfo capabilities: RuntimeCapabilities - _fields = frozenset({"effective_config", "agent_name", "profiles", "adapter", "capabilities"}) + _fields = frozenset({"agent_name", "base_dir", "config", "adapter", "capabilities"}) @classmethod def _normalize(cls, data: dict[str, Any]) -> dict[str, Any]: descriptor = data.get("adapter") if descriptor is None: descriptor = (data.get("adapter_descriptor") or {}).get("descriptor", {}) - data["effective_config"] = EffectiveConfig.from_mapping(data["effective_config"]) - data["profiles"] = _required_profiles(data, "RunPlan") + if "base_dir" not in data: + raise FabricConfigError("RunPlan base_dir is required") + data["base_dir"] = Path(data["base_dir"]) + data["config"] = _FabricConfigSnapshot.from_mapping(data.get("config", {})) data["adapter"] = AdapterInfo.from_mapping(descriptor) data["capabilities"] = RuntimeCapabilities.from_mapping(data.get("capabilities", {})) return data @@ -1031,20 +994,17 @@ class DoctorReport(FabricMapping): Attributes: agent_name: Resolved agent name. - profiles: Applied profile names in caller order. status: Aggregate outcome: ``pass``, ``warn``, or ``fail``. checks: Ordered ``DoctorCheck`` results. """ agent_name: str - profiles: Sequence[str] status: str checks: Sequence[DoctorCheck] - _fields = frozenset({"agent_name", "profiles", "status", "checks"}) + _fields = frozenset({"agent_name", "status", "checks"}) @classmethod def _normalize(cls, data: dict[str, Any]) -> dict[str, Any]: - data["profiles"] = _required_profiles(data, "DoctorReport") data["checks"] = tuple(DoctorCheck.from_mapping(check) for check in data.get("checks", [])) return data @@ -1265,7 +1225,6 @@ class RunResult(FabricMapping): Attributes: agent_name: Resolved agent name. - profiles: Applied profile names. harness: Stable harness identifier. adapter_kind: Adapter execution mechanism. adapter_id: Fabric adapter identifier. @@ -1283,7 +1242,6 @@ class RunResult(FabricMapping): """ agent_name: str - profiles: Sequence[str] harness: str adapter_kind: str adapter_id: str @@ -1300,7 +1258,6 @@ class RunResult(FabricMapping): _fields = frozenset( { "agent_name", - "profiles", "harness", "adapter_kind", "adapter_id", @@ -1320,7 +1277,6 @@ class RunResult(FabricMapping): @classmethod def _normalize(cls, data: dict[str, Any]) -> dict[str, Any]: - data["profiles"] = _required_profiles(data, "RunResult") for field in ( "agent_name", "harness", diff --git a/schemas/SCHEMA.md b/schemas/SCHEMA.md index ef262463c..bd534e92e 100644 --- a/schemas/SCHEMA.md +++ b/schemas/SCHEMA.md @@ -15,17 +15,16 @@ schema-alignment tests in the same change. ## Exported Schemas -`fabric schema` exports the current public typed contract. +The core schema generator exports the current public typed contract. -### Config And Planning +### Config and Planning -- `agent`: portable base `agent.yaml` config. -- `profile`: profile config applied over an agent config. +- `agent`: complete typed `FabricConfig`. - `adapter-descriptor`: minimal adapter descriptor consumed by Fabric. Each descriptor declares a `contract_version`; Fabric rejects descriptors for unsupported adapter contracts during planning. -- `effective-config`: merged config after profile resolution. -- `run-plan`: executable plan derived from effective config. +- `run-plan`: executable plan containing the canonical typed config, absolute + base directory, selected adapter, and derived execution metadata. ### Adapter Invocation @@ -57,16 +56,10 @@ and export them here. ## How To Maintain -Use the Fabric CLI to regenerate them after intentional contract changes: +Use the core generator to regenerate them after intentional contract changes: ```bash -cargo run -p nemo-fabric-cli -- schema --output-dir schemas -``` - -Use the CLI to inspect one schema: - -```bash -cargo run -p nemo-fabric-cli -- schema --name agent +cargo run -p nemo-fabric-core --example generate-schemas -- schemas ``` To add a new schema-backed typed model: @@ -76,8 +69,7 @@ To add a new schema-backed typed model: 3. Add a `SchemaName` variant in `crates/fabric-core/src/schema.rs`. 4. Add the variant to `SchemaName::ALL`, `as_str()`, `parse()`, and `generate_schema()`. -5. Regenerate schemas with `cargo run -p nemo-fabric-cli -- schema --output-dir - schemas`. +5. Regenerate schemas with the command above. 6. Add the new schema to the exported list above. Run `cargo test` after regenerating schemas. The snapshot tests compare the diff --git a/schemas/adapter-descriptor.schema.json b/schemas/adapter-descriptor.schema.json index 7eb806702..6c93bfe13 100644 --- a/schemas/adapter-descriptor.schema.json +++ b/schemas/adapter-descriptor.schema.json @@ -217,4 +217,4 @@ ], "title": "AdapterDescriptor", "type": "object" -} +} \ No newline at end of file diff --git a/schemas/adapter-invocation.schema.json b/schemas/adapter-invocation.schema.json index d1624c1ca..44162719f 100644 --- a/schemas/adapter-invocation.schema.json +++ b/schemas/adapter-invocation.schema.json @@ -95,7 +95,7 @@ "description": "Capabilities mapped into the harness-native surface." }, "routes": { - "description": "Routing decisions made while resolving the effective config.", + "description": "Routing decisions made while planning the configured capabilities.", "items": { "$ref": "#/$defs/CapabilityRoute" }, @@ -216,47 +216,6 @@ } ] }, - "EffectiveConfig": { - "description": "Merged Fabric config after applying selected profiles.", - "properties": { - "agent_name": { - "description": "Stable agent name.", - "type": "string" - }, - "agent_root": { - "description": "Root used to resolve agent package paths.", - "type": "string" - }, - "config": { - "$ref": "#/$defs/FabricConfig", - "description": "Merged Fabric config with authoring-time profile discovery removed." - }, - "config_path": { - "description": "Resolved Fabric config path.", - "type": "string" - }, - "config_root": { - "description": "Root used to resolve config-local paths.", - "type": "string" - }, - "profiles": { - "description": "Ordered selected profiles.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "agent_name", - "profiles", - "agent_root", - "config_path", - "config_root", - "config" - ], - "type": "object" - }, "EnvironmentConfig": { "additionalProperties": true, "description": "Execution environment configuration.", @@ -418,10 +377,6 @@ "description": "Model aliases.", "type": "object" }, - "profiles": { - "$ref": "#/$defs/ProfileRegistryConfig", - "description": "Optional profile discovery config." - }, "relay": { "anyOf": [ { @@ -649,20 +604,6 @@ ], "type": "object" }, - "ProfileRegistryConfig": { - "additionalProperties": true, - "description": "Profile discovery config for curated package profiles.", - "properties": { - "directories": { - "description": "Directories searched when a caller selects a profile by name.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, "RelayAtifConfig": { "additionalProperties": true, "description": "Relay ATIF export configuration.", @@ -1287,7 +1228,7 @@ "description": "Request payload for the harness." }, "overrides": { - "description": "Per-invocation overrides allowed by the resolved profile." + "description": "Per-invocation overrides allowed by the resolved config." }, "request_id": { "description": "Request id.", @@ -1404,7 +1345,7 @@ "description": "Skill capability configuration.", "properties": { "paths": { - "description": "Skill paths relative to the agent root.", + "description": "Skill paths resolved relative to the config base directory.", "items": { "type": "string" }, @@ -1531,6 +1472,14 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Adapter-facing invocation payload.", "properties": { + "agent_name": { + "description": "Stable agent name.", + "type": "string" + }, + "base_dir": { + "description": "Absolute base directory used to resolve relative Fabric paths.", + "type": "string" + }, "capability_plan": { "$ref": "#/$defs/CapabilityPlan", "default": { @@ -1548,9 +1497,9 @@ }, "description": "Derived capability routing plan for the selected adapter." }, - "effective_config": { - "$ref": "#/$defs/EffectiveConfig", - "description": "Merged agent config and provenance." + "config": { + "$ref": "#/$defs/FabricConfig", + "description": "Complete typed Fabric config." }, "request": { "$ref": "#/$defs/RunRequest", @@ -1573,7 +1522,9 @@ } }, "required": [ - "effective_config", + "agent_name", + "base_dir", + "config", "runtime_context", "request" ], diff --git a/schemas/agent.schema.json b/schemas/agent.schema.json index f664b81ed..8e0be3c05 100644 --- a/schemas/agent.schema.json +++ b/schemas/agent.schema.json @@ -226,20 +226,6 @@ ], "type": "object" }, - "ProfileRegistryConfig": { - "additionalProperties": true, - "description": "Profile discovery config for curated package profiles.", - "properties": { - "directories": { - "description": "Directories searched when a caller selects a profile by name.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, "RelayAtifConfig": { "additionalProperties": true, "description": "Relay ATIF export configuration.", @@ -880,7 +866,7 @@ "description": "Skill capability configuration.", "properties": { "paths": { - "description": "Skill paths relative to the agent root.", + "description": "Skill paths resolved relative to the config base directory.", "items": { "type": "string" }, @@ -969,10 +955,6 @@ "description": "Model aliases.", "type": "object" }, - "profiles": { - "$ref": "#/$defs/ProfileRegistryConfig", - "description": "Optional profile discovery config." - }, "relay": { "anyOf": [ { diff --git a/schemas/effective-config.schema.json b/schemas/effective-config.schema.json deleted file mode 100644 index 6fc533a5b..000000000 --- a/schemas/effective-config.schema.json +++ /dev/null @@ -1,1078 +0,0 @@ -{ - "$defs": { - "ControlLocation": { - "description": "Where Fabric control code runs relative to the environment.", - "oneOf": [ - { - "const": "external_control", - "description": "Fabric runs on the host/control plane and starts or connects to the harness in the environment.", - "type": "string" - }, - { - "const": "in_env_control", - "description": "Fabric runs inside the prepared environment with the harness.", - "type": "string" - } - ] - }, - "EnvironmentConfig": { - "additionalProperties": true, - "description": "Execution environment configuration.", - "properties": { - "artifacts": { - "description": "Artifact path inside or outside the provider.", - "type": [ - "string", - "null" - ] - }, - "connection": { - "additionalProperties": true, - "description": "Provider connection metadata, such as server URL, credential reference, or namespace.", - "type": "object" - }, - "control_location": { - "$ref": "#/$defs/ControlLocation", - "default": "in_env_control", - "description": "Where Fabric control code runs relative to the environment." - }, - "metadata": { - "additionalProperties": true, - "description": "Consumer-provided environment metadata.", - "type": "object" - }, - "ownership": { - "$ref": "#/$defs/EnvironmentOwnership", - "default": "caller_owned", - "description": "Whether Fabric owns the environment resource." - }, - "provider": { - "description": "Environment provider, for example `local`, `docker`, `opensandbox`, or `k8s`.", - "type": "string" - }, - "settings": { - "additionalProperties": true, - "description": "Provider-specific settings.", - "type": "object" - }, - "workspace": { - "description": "Workspace path inside or outside the provider.", - "type": [ - "string", - "null" - ] - } - }, - "required": [ - "provider" - ], - "type": "object" - }, - "EnvironmentOwnership": { - "description": "Whether Fabric owns the underlying environment resource.", - "oneOf": [ - { - "const": "caller_owned", - "description": "The caller or a surrounding system owns the environment resource.", - "type": "string" - }, - { - "const": "fabric_owned", - "description": "Fabric created or leased the environment resource and may release it.", - "type": "string" - } - ] - }, - "FabricConfig": { - "additionalProperties": true, - "description": "Versioned Fabric agent config.", - "properties": { - "environment": { - "anyOf": [ - { - "$ref": "#/$defs/EnvironmentConfig" - }, - { - "type": "null" - } - ], - "description": "Environment where the harness or its tools execute." - }, - "harness": { - "$ref": "#/$defs/HarnessConfig", - "description": "Harness selection and harness-specific settings." - }, - "mcp": { - "anyOf": [ - { - "$ref": "#/$defs/McpConfig" - }, - { - "type": "null" - } - ], - "description": "MCP capability configuration." - }, - "metadata": { - "$ref": "#/$defs/MetadataConfig", - "description": "Human-readable metadata." - }, - "models": { - "additionalProperties": { - "$ref": "#/$defs/ModelConfig" - }, - "description": "Model aliases.", - "type": "object" - }, - "profiles": { - "$ref": "#/$defs/ProfileRegistryConfig", - "description": "Optional profile discovery config." - }, - "relay": { - "anyOf": [ - { - "$ref": "#/$defs/RelayConfig" - }, - { - "type": "null" - } - ], - "description": "First-class NeMo Relay integration configuration." - }, - "runtime": { - "$ref": "#/$defs/RuntimeConfig", - "description": "Runtime input/output contract." - }, - "schema_version": { - "description": "Config schema version.", - "type": "string" - }, - "skills": { - "anyOf": [ - { - "$ref": "#/$defs/SkillConfig" - }, - { - "type": "null" - } - ], - "description": "Skill capability configuration." - }, - "telemetry": { - "anyOf": [ - { - "$ref": "#/$defs/TelemetryConfig" - }, - { - "type": "null" - } - ], - "description": "Telemetry configuration." - }, - "tools": { - "anyOf": [ - { - "$ref": "#/$defs/ToolsConfig" - }, - { - "type": "null" - } - ], - "description": "Tool capability configuration." - } - }, - "required": [ - "schema_version", - "metadata", - "harness", - "runtime" - ], - "type": "object" - }, - "HarnessConfig": { - "additionalProperties": true, - "description": "Harness selection.", - "properties": { - "adapter_id": { - "description": "Adapter implementation id.", - "type": "string" - }, - "resolution": { - "anyOf": [ - { - "$ref": "#/$defs/ResolutionStrategy" - }, - { - "type": "null" - } - ], - "description": "Selected install or availability strategy." - }, - "settings": { - "additionalProperties": true, - "description": "Harness-specific settings.", - "type": "object" - } - }, - "required": [ - "adapter_id" - ], - "type": "object" - }, - "McpConfig": { - "additionalProperties": true, - "description": "MCP capability configuration.", - "properties": { - "servers": { - "additionalProperties": { - "$ref": "#/$defs/McpServerConfig" - }, - "description": "Named MCP servers.", - "type": "object" - } - }, - "type": "object" - }, - "McpExposure": { - "description": "MCP exposure strategy.", - "oneOf": [ - { - "const": "harness_native", - "description": "Map into harness-native MCP config through the selected adapter.", - "type": "string" - }, - { - "const": "fabric_managed", - "description": "Fabric manages MCP and exposes basic tools/actions.", - "type": "string" - } - ] - }, - "McpServerConfig": { - "additionalProperties": true, - "description": "MCP server configuration.", - "properties": { - "exposure": { - "$ref": "#/$defs/McpExposure", - "description": "How Fabric exposes the MCP capability to the harness." - }, - "transport": { - "description": "MCP transport.", - "type": "string" - }, - "url": { - "description": "MCP server URL or process command, depending on transport.", - "type": "string" - } - }, - "required": [ - "transport", - "url", - "exposure" - ], - "type": "object" - }, - "MetadataConfig": { - "additionalProperties": true, - "description": "Human-readable metadata.", - "properties": { - "description": { - "description": "Optional description.", - "type": [ - "string", - "null" - ] - }, - "name": { - "description": "Agent/config name.", - "type": "string" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "ModelConfig": { - "additionalProperties": true, - "description": "Model configuration.", - "properties": { - "api_key_env": { - "description": "Optional environment variable containing an API key.", - "type": [ - "string", - "null" - ] - }, - "model": { - "description": "Provider model identifier.", - "type": "string" - }, - "provider": { - "description": "Model provider name.", - "type": "string" - }, - "settings": { - "additionalProperties": true, - "description": "Provider-specific settings.", - "type": "object" - }, - "temperature": { - "description": "Optional temperature.", - "format": "double", - "type": [ - "number", - "null" - ] - } - }, - "required": [ - "provider", - "model" - ], - "type": "object" - }, - "ProfileRegistryConfig": { - "additionalProperties": true, - "description": "Profile discovery config for curated package profiles.", - "properties": { - "directories": { - "description": "Directories searched when a caller selects a profile by name.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "RelayAtifConfig": { - "additionalProperties": true, - "description": "Relay ATIF export configuration.", - "properties": { - "agent_name": { - "default": "NeMo Relay", - "description": "Agent name written into ATIF.", - "type": "string" - }, - "agent_version": { - "description": "Agent version written into ATIF.", - "type": [ - "string", - "null" - ] - }, - "enabled": { - "default": false, - "description": "Whether ATIF export is enabled.", - "type": "boolean" - }, - "extra": { - "description": "Extra ATIF metadata." - }, - "filename_template": { - "default": "nemo-relay-atif-{session_id}.json", - "description": "ATIF file name template.", - "type": "string" - }, - "model_name": { - "default": "unknown", - "description": "Model name written into ATIF.", - "type": "string" - }, - "output_directory": { - "description": "Directory used for ATIF files.", - "type": [ - "string", - "null" - ] - }, - "storage": { - "description": "Optional ATIF remote storage.", - "items": { - "$ref": "#/$defs/RelayAtifStorageConfig" - }, - "type": [ - "array", - "null" - ] - }, - "tool_definitions": { - "description": "Tool definitions written into ATIF.", - "items": true, - "type": [ - "array", - "null" - ] - } - }, - "type": "object" - }, - "RelayAtifStorageConfig": { - "description": "Relay ATIF remote storage configuration.", - "oneOf": [ - { - "additionalProperties": true, - "description": "Upload ATIF artifacts to HTTP storage.", - "properties": { - "endpoint": { - "default": "", - "description": "HTTP storage endpoint.", - "type": "string" - }, - "header_env": { - "additionalProperties": { - "type": "string" - }, - "description": "Environment-variable-backed HTTP headers.", - "type": "object" - }, - "headers": { - "additionalProperties": { - "type": "string" - }, - "description": "Static HTTP headers.", - "type": "object" - }, - "timeout_millis": { - "default": 3000, - "description": "Request timeout in milliseconds.", - "format": "uint64", - "minimum": 0, - "type": "integer" - }, - "type": { - "const": "http", - "type": "string" - } - }, - "required": [ - "type" - ], - "type": "object" - }, - { - "additionalProperties": true, - "description": "Upload ATIF artifacts to S3-compatible storage.", - "properties": { - "access_key_id": { - "description": "AWS access key id.", - "type": [ - "string", - "null" - ] - }, - "allow_http": { - "description": "Allow HTTP endpoints for S3-compatible storage.", - "type": [ - "boolean", - "null" - ] - }, - "bucket": { - "default": "", - "description": "S3 bucket name.", - "type": "string" - }, - "endpoint_url": { - "description": "S3-compatible endpoint URL.", - "type": [ - "string", - "null" - ] - }, - "key_prefix": { - "description": "Optional S3 object key prefix.", - "type": [ - "string", - "null" - ] - }, - "region": { - "description": "AWS region.", - "type": [ - "string", - "null" - ] - }, - "secret_access_key_var": { - "description": "Environment variable containing the AWS secret access key.", - "type": [ - "string", - "null" - ] - }, - "session_token_var": { - "description": "Environment variable containing the AWS session token.", - "type": [ - "string", - "null" - ] - }, - "type": { - "const": "s3", - "type": "string" - } - }, - "required": [ - "type" - ], - "type": "object" - } - ] - }, - "RelayAtofConfig": { - "additionalProperties": true, - "description": "Relay ATOF export configuration.", - "properties": { - "enabled": { - "default": false, - "description": "Whether ATOF export is enabled.", - "type": "boolean" - }, - "endpoints": { - "description": "Optional remote ATOF endpoints.", - "items": { - "$ref": "#/$defs/RelayAtofEndpointConfig" - }, - "type": "array" - }, - "filename": { - "description": "ATOF file name.", - "type": [ - "string", - "null" - ] - }, - "mode": { - "$ref": "#/$defs/RelayAtofMode", - "default": "append", - "description": "File write mode." - }, - "output_directory": { - "description": "Directory used for ATOF files.", - "type": [ - "string", - "null" - ] - } - }, - "type": "object" - }, - "RelayAtofEndpointConfig": { - "additionalProperties": true, - "description": "Relay ATOF endpoint configuration.", - "properties": { - "field_name_policy": { - "$ref": "#/$defs/RelayAtofEndpointFieldNamePolicy", - "default": "preserve", - "description": "Field-name handling policy." - }, - "headers": { - "additionalProperties": { - "type": "string" - }, - "description": "Endpoint headers.", - "type": "object" - }, - "timeout_millis": { - "default": 3000, - "description": "Request timeout in milliseconds.", - "format": "uint64", - "minimum": 0, - "type": "integer" - }, - "transport": { - "$ref": "#/$defs/RelayAtofEndpointTransport", - "default": "http_post", - "description": "Endpoint transport." - }, - "url": { - "description": "Endpoint URL.", - "type": "string" - } - }, - "required": [ - "url" - ], - "type": "object" - }, - "RelayAtofEndpointFieldNamePolicy": { - "description": "Relay ATOF endpoint field-name policy.", - "oneOf": [ - { - "const": "preserve", - "description": "Preserve field names.", - "type": "string" - }, - { - "const": "replace_dots", - "description": "Replace dots in field names.", - "type": "string" - } - ] - }, - "RelayAtofEndpointTransport": { - "description": "Relay ATOF endpoint transport.", - "oneOf": [ - { - "const": "http_post", - "description": "HTTP POST transport.", - "type": "string" - }, - { - "const": "websocket", - "description": "WebSocket transport.", - "type": "string" - }, - { - "const": "ndjson", - "description": "NDJSON transport.", - "type": "string" - } - ] - }, - "RelayAtofMode": { - "description": "Relay ATOF file mode.", - "oneOf": [ - { - "const": "append", - "description": "Append to an existing ATOF file.", - "type": "string" - }, - { - "const": "overwrite", - "description": "Overwrite an existing ATOF file.", - "type": "string" - } - ] - }, - "RelayComponentConfig": { - "additionalProperties": true, - "description": "Generic NeMo Relay plugin component configuration.", - "properties": { - "config": { - "additionalProperties": true, - "description": "Component-local Relay plugin config.", - "type": "object" - }, - "enabled": { - "default": true, - "description": "Whether this Relay component should be activated.", - "type": "boolean" - }, - "kind": { - "description": "Registered Relay plugin kind.", - "type": "string" - } - }, - "required": [ - "kind" - ], - "type": "object" - }, - "RelayConfig": { - "additionalProperties": true, - "description": "NeMo Relay integration configuration.", - "properties": { - "components": { - "description": "Additional Relay plugin components.", - "items": { - "$ref": "#/$defs/RelayComponentConfig" - }, - "type": "array" - }, - "observability": { - "anyOf": [ - { - "$ref": "#/$defs/RelayObservabilityConfig" - }, - { - "type": "null" - } - ], - "description": "Relay observability component configuration." - }, - "output_dir": { - "description": "Optional Relay output directory.", - "type": [ - "string", - "null" - ] - }, - "policy": { - "anyOf": [ - { - "$ref": "#/$defs/RelayConfigPolicy" - }, - { - "type": "null" - } - ], - "description": "Relay plugin validation policy." - }, - "project": { - "description": "Optional project name for Relay backends.", - "type": [ - "string", - "null" - ] - } - }, - "type": "object" - }, - "RelayConfigPolicy": { - "description": "Relay validation policy.", - "properties": { - "unknown_component": { - "$ref": "#/$defs/RelayUnsupportedBehavior", - "default": "warn", - "description": "Policy for unknown components." - }, - "unknown_field": { - "$ref": "#/$defs/RelayUnsupportedBehavior", - "default": "warn", - "description": "Policy for unknown fields." - }, - "unsupported_value": { - "$ref": "#/$defs/RelayUnsupportedBehavior", - "default": "error", - "description": "Policy for unsupported values." - } - }, - "type": "object" - }, - "RelayObservabilityConfig": { - "additionalProperties": true, - "description": "NeMo Relay observability component configuration.", - "properties": { - "atif": { - "anyOf": [ - { - "$ref": "#/$defs/RelayAtifConfig" - }, - { - "type": "null" - } - ], - "description": "ATIF export configuration." - }, - "atof": { - "anyOf": [ - { - "$ref": "#/$defs/RelayAtofConfig" - }, - { - "type": "null" - } - ], - "description": "ATOF export configuration." - }, - "openinference": { - "anyOf": [ - { - "$ref": "#/$defs/RelayOtlpConfig" - }, - { - "type": "null" - } - ], - "description": "OpenInference export configuration." - }, - "opentelemetry": { - "anyOf": [ - { - "$ref": "#/$defs/RelayOtlpConfig" - }, - { - "type": "null" - } - ], - "description": "OpenTelemetry export configuration." - }, - "policy": { - "anyOf": [ - { - "$ref": "#/$defs/RelayConfigPolicy" - }, - { - "type": "null" - } - ], - "description": "Relay config validation policy." - }, - "version": { - "default": 1, - "description": "Relay observability config version.", - "format": "uint32", - "minimum": 0, - "type": "integer" - } - }, - "type": "object" - }, - "RelayOtlpConfig": { - "additionalProperties": true, - "description": "Relay OpenTelemetry/OpenInference export configuration.", - "properties": { - "enabled": { - "default": false, - "description": "Whether OTLP export is enabled.", - "type": "boolean" - }, - "endpoint": { - "description": "OTLP endpoint.", - "type": [ - "string", - "null" - ] - }, - "headers": { - "additionalProperties": { - "type": "string" - }, - "description": "OTLP headers.", - "type": "object" - }, - "instrumentation_scope": { - "description": "OTLP instrumentation scope.", - "type": [ - "string", - "null" - ] - }, - "resource_attributes": { - "additionalProperties": { - "type": "string" - }, - "description": "OTLP resource attributes.", - "type": "object" - }, - "service_name": { - "default": "nemo-relay", - "description": "OTLP service name.", - "type": "string" - }, - "service_namespace": { - "description": "OTLP service namespace.", - "type": [ - "string", - "null" - ] - }, - "service_version": { - "description": "OTLP service version.", - "type": [ - "string", - "null" - ] - }, - "timeout_millis": { - "default": 3000, - "description": "Request timeout in milliseconds.", - "format": "uint64", - "minimum": 0, - "type": "integer" - }, - "transport": { - "$ref": "#/$defs/RelayOtlpTransport", - "default": "http_binary", - "description": "OTLP transport." - } - }, - "type": "object" - }, - "RelayOtlpTransport": { - "description": "Relay OTLP transport.", - "oneOf": [ - { - "const": "http_binary", - "description": "OTLP HTTP binary transport.", - "type": "string" - }, - { - "const": "grpc", - "description": "OTLP gRPC transport.", - "type": "string" - } - ] - }, - "RelayUnsupportedBehavior": { - "description": "Relay unsupported/unknown config handling.", - "oneOf": [ - { - "const": "ignore", - "description": "Ignore the unsupported or unknown value.", - "type": "string" - }, - { - "const": "warn", - "description": "Warn on the unsupported or unknown value.", - "type": "string" - }, - { - "const": "error", - "description": "Error on the unsupported or unknown value.", - "type": "string" - } - ] - }, - "ResolutionStrategy": { - "description": "Adapter install or availability strategy.", - "oneOf": [ - { - "const": "preinstalled", - "description": "Harness is already available in the prepared environment.", - "type": "string" - }, - { - "const": "image_provided", - "description": "Environment image already contains the harness and dependencies.", - "type": "string" - }, - { - "const": "pip_uv", - "description": "Adapter may install a Python package with pip or uv.", - "type": "string" - }, - { - "const": "npm", - "description": "Adapter may install a Node package.", - "type": "string" - }, - { - "const": "source", - "description": "Adapter may install from source.", - "type": "string" - }, - { - "const": "service", - "description": "Adapter connects to an already-running service.", - "type": "string" - }, - { - "const": "native_plugin", - "description": "Adapter is installed through a harness-native plugin manager.", - "type": "string" - } - ] - }, - "RuntimeConfig": { - "additionalProperties": true, - "description": "Runtime input/output contract.", - "properties": { - "artifacts": { - "description": "Artifact directory.", - "type": [ - "string", - "null" - ] - }, - "input_schema": { - "default": "text", - "description": "Input schema label.", - "type": "string" - }, - "output_schema": { - "default": "text", - "description": "Output schema label.", - "type": "string" - } - }, - "type": "object" - }, - "SkillConfig": { - "additionalProperties": true, - "description": "Skill capability configuration.", - "properties": { - "paths": { - "description": "Skill paths relative to the agent root.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "TelemetryConfig": { - "additionalProperties": true, - "description": "Telemetry configuration.", - "properties": { - "providers": { - "additionalProperties": { - "$ref": "#/$defs/TelemetryProviderConfig" - }, - "description": "Telemetry providers enabled for this run.", - "type": "object" - } - }, - "type": "object" - }, - "TelemetryProviderConfig": { - "additionalProperties": true, - "description": "Provider-specific telemetry configuration.", - "properties": { - "config": { - "description": "Provider-specific pass-through config." - } - }, - "type": "object" - }, - "ToolsConfig": { - "additionalProperties": true, - "description": "Harness-neutral tool capability configuration.", - "properties": { - "blocked": { - "description": "Adapter-native tool names or toolset names to block.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - } - }, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "Merged Fabric config after applying selected profiles.", - "properties": { - "agent_name": { - "description": "Stable agent name.", - "type": "string" - }, - "agent_root": { - "description": "Root used to resolve agent package paths.", - "type": "string" - }, - "config": { - "$ref": "#/$defs/FabricConfig", - "description": "Merged Fabric config with authoring-time profile discovery removed." - }, - "config_path": { - "description": "Resolved Fabric config path.", - "type": "string" - }, - "config_root": { - "description": "Root used to resolve config-local paths.", - "type": "string" - }, - "profiles": { - "description": "Ordered selected profiles.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "agent_name", - "profiles", - "agent_root", - "config_path", - "config_root", - "config" - ], - "title": "EffectiveConfig", - "type": "object" -} \ No newline at end of file diff --git a/schemas/error-info.schema.json b/schemas/error-info.schema.json index 7f72f0e76..b989b1cc1 100644 --- a/schemas/error-info.schema.json +++ b/schemas/error-info.schema.json @@ -5,7 +5,7 @@ "oneOf": [ { "const": "config", - "description": "Configuration or profile loading failed.", + "description": "Configuration resolution failed.", "type": "string" }, { diff --git a/schemas/profile.schema.json b/schemas/profile.schema.json deleted file mode 100644 index 63ebc6e0d..000000000 --- a/schemas/profile.schema.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "$defs": { - "ToolsConfig": { - "additionalProperties": true, - "description": "Harness-neutral tool capability configuration.", - "properties": { - "blocked": { - "description": "Adapter-native tool names or toolset names to block.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - } - }, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": true, - "properties": { - "description": { - "description": "Optional profile description.", - "type": [ - "string", - "null" - ] - }, - "environment": { - "additionalProperties": true, - "description": "Partial environment overlay.", - "type": [ - "object", - "null" - ] - }, - "harness": { - "additionalProperties": true, - "description": "Partial harness overlay.", - "type": [ - "object", - "null" - ] - }, - "mcp": { - "additionalProperties": true, - "description": "Partial MCP overlay.", - "type": [ - "object", - "null" - ] - }, - "models": { - "additionalProperties": true, - "description": "Partial model overlays by alias.", - "type": [ - "object", - "null" - ] - }, - "name": { - "description": "Optional profile name used for directory discovery.", - "type": [ - "string", - "null" - ] - }, - "relay": { - "additionalProperties": true, - "description": "Partial Relay integration overlay.", - "type": [ - "object", - "null" - ] - }, - "runtime": { - "additionalProperties": true, - "description": "Partial runtime overlay.", - "type": [ - "object", - "null" - ] - }, - "schema_version": { - "description": "Optional profile schema version.", - "type": [ - "string", - "null" - ] - }, - "skills": { - "additionalProperties": true, - "description": "Partial skill overlay.", - "type": [ - "object", - "null" - ] - }, - "telemetry": { - "additionalProperties": true, - "description": "Partial telemetry overlay.", - "type": [ - "object", - "null" - ] - }, - "tools": { - "anyOf": [ - { - "$ref": "#/$defs/ToolsConfig" - }, - { - "type": "null" - } - ], - "description": "Tool capability overlay." - } - }, - "title": "ProfileConfig", - "type": "object" -} \ No newline at end of file diff --git a/schemas/run-plan.schema.json b/schemas/run-plan.schema.json index a5f6efd4e..110290d0f 100644 --- a/schemas/run-plan.schema.json +++ b/schemas/run-plan.schema.json @@ -245,7 +245,7 @@ "description": "Capabilities mapped into the harness-native surface." }, "routes": { - "description": "Routing decisions made while resolving the effective config.", + "description": "Routing decisions made while planning the configured capabilities.", "items": { "$ref": "#/$defs/CapabilityRoute" }, @@ -366,47 +366,6 @@ } ] }, - "EffectiveConfig": { - "description": "Merged Fabric config after applying selected profiles.", - "properties": { - "agent_name": { - "description": "Stable agent name.", - "type": "string" - }, - "agent_root": { - "description": "Root used to resolve agent package paths.", - "type": "string" - }, - "config": { - "$ref": "#/$defs/FabricConfig", - "description": "Merged Fabric config with authoring-time profile discovery removed." - }, - "config_path": { - "description": "Resolved Fabric config path.", - "type": "string" - }, - "config_root": { - "description": "Root used to resolve config-local paths.", - "type": "string" - }, - "profiles": { - "description": "Ordered selected profiles.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "agent_name", - "profiles", - "agent_root", - "config_path", - "config_root", - "config" - ], - "type": "object" - }, "EnvironmentConfig": { "additionalProperties": true, "description": "Execution environment configuration.", @@ -568,10 +527,6 @@ "description": "Model aliases.", "type": "object" }, - "profiles": { - "$ref": "#/$defs/ProfileRegistryConfig", - "description": "Optional profile discovery config." - }, "relay": { "anyOf": [ { @@ -799,20 +754,6 @@ ], "type": "object" }, - "ProfileRegistryConfig": { - "additionalProperties": true, - "description": "Profile discovery config for curated package profiles.", - "properties": { - "directories": { - "description": "Directories searched when a caller selects a profile by name.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, "RelayAtifConfig": { "additionalProperties": true, "description": "Relay ATIF export configuration.", @@ -1512,7 +1453,7 @@ "description": "Skill capability configuration.", "properties": { "paths": { - "description": "Skill paths relative to the agent root.", + "description": "Skill paths resolved relative to the config base directory.", "items": { "type": "string" }, @@ -1654,8 +1595,8 @@ "description": "Stable agent name.", "type": "string" }, - "agent_root": { - "description": "Root used to resolve agent package paths.", + "base_dir": { + "description": "Base directory used to resolve relative Fabric paths.", "type": "string" }, "capabilities": { @@ -1681,19 +1622,7 @@ }, "config": { "$ref": "#/$defs/FabricConfig", - "description": "Resolved Fabric profile config." - }, - "config_path": { - "description": "Resolved Fabric config path.", - "type": "string" - }, - "config_root": { - "description": "Root used to resolve config-local paths.", - "type": "string" - }, - "effective_config": { - "$ref": "#/$defs/EffectiveConfig", - "description": "Merged config and provenance used as the base for this plan." + "description": "Complete typed Fabric config." }, "environment_plan": { "anyOf": [ @@ -1706,13 +1635,6 @@ ], "description": "Resolved environment plan." }, - "profiles": { - "description": "Ordered selected profiles.", - "items": { - "type": "string" - }, - "type": "array" - }, "resolution": { "anyOf": [ { @@ -1737,15 +1659,11 @@ } }, "required": [ - "effective_config", "agent_name", - "profiles", - "capabilities", - "agent_root", - "config_path", - "config_root", - "config" + "base_dir", + "config", + "capabilities" ], "title": "RunPlan", "type": "object" -} +} \ No newline at end of file diff --git a/schemas/run-request.schema.json b/schemas/run-request.schema.json index 506d095c6..8397f0225 100644 --- a/schemas/run-request.schema.json +++ b/schemas/run-request.schema.json @@ -12,7 +12,7 @@ "description": "Request payload for the harness." }, "overrides": { - "description": "Per-invocation overrides allowed by the resolved profile." + "description": "Per-invocation overrides allowed by the resolved config." }, "request_id": { "description": "Request id.", diff --git a/schemas/run-result.schema.json b/schemas/run-result.schema.json index ca1a2a3d9..54272bb3b 100644 --- a/schemas/run-result.schema.json +++ b/schemas/run-result.schema.json @@ -113,7 +113,7 @@ "oneOf": [ { "const": "config", - "description": "Configuration or profile loading failed.", + "description": "Configuration resolution failed.", "type": "string" }, { @@ -285,13 +285,6 @@ "default": null, "description": "Primary output." }, - "profiles": { - "description": "Ordered profiles applied to this run.", - "items": { - "type": "string" - }, - "type": "array" - }, "request_id": { "description": "Request id.", "type": "string" @@ -318,7 +311,6 @@ }, "required": [ "agent_name", - "profiles", "harness", "adapter_kind", "runtime_id", diff --git a/scripts/licensing/attributions_lockfile_md.py b/scripts/licensing/attributions_lockfile_md.py index 35e582cdd..4e5f494b7 100755 --- a/scripts/licensing/attributions_lockfile_md.py +++ b/scripts/licensing/attributions_lockfile_md.py @@ -27,6 +27,7 @@ ROOT = Path(__file__).resolve().parents[2] MARKDOWN_CODE_FENCE = "```\n" +MARKDOWN_TEXT_CODE_FENCE = "\n```text\n" MARKDOWN_CODE_BLOCK_END = "```\n\n" @@ -362,20 +363,20 @@ def _render_rust_metadata_fallback_attribution(crate: dict[str, Any]) -> tuple[s license_name = _normalize_license_name(str(crate.get("license") or "UNKNOWN")) parts = [ - f"## {name} - {version}\n", + f"## {name} - {version}\n\n", f"**Repository URL**: {repo}\n", f"**License Type(s)**: {license_name}\n", - f"### License: {spdx_url(license_name, fallback='https://spdx.org/licenses/')}\n", + f"\n### License: {spdx_url(license_name, fallback='https://spdx.org/licenses/')}\n\n", ] license_files = _rust_license_files(crate) if license_files: for label, text in license_files: parts.append(f"### License File: {label}\n") - parts.append(MARKDOWN_CODE_FENCE) + parts.append(MARKDOWN_TEXT_CODE_FENCE) parts.append(text if text.endswith("\n") else text + "\n") parts.append(MARKDOWN_CODE_BLOCK_END) else: - parts.append(MARKDOWN_CODE_FENCE) + parts.append(MARKDOWN_TEXT_CODE_FENCE) parts.append(f"License expression from Cargo metadata: {license_name}\n") parts.append("No package license file was found in the downloaded crate archive.\n") parts.append(MARKDOWN_CODE_BLOCK_END) @@ -411,11 +412,11 @@ def _render_rust_crate_attribution( rendered = "".join( [ - f"## {name} - {version}\n", + f"## {name} - {version}\n\n", f"**Repository URL**: {repo}\n", f"**License Type(s)**: {license_id}\n", - f"### License: https://spdx.org/licenses/{license_id}.html\n", - MARKDOWN_CODE_FENCE, + f"\n### License: https://spdx.org/licenses/{license_id}.html\n", + MARKDOWN_TEXT_CODE_FENCE, license_text, "\n", MARKDOWN_CODE_BLOCK_END, @@ -898,4 +899,3 @@ def main() -> int: if __name__ == "__main__": raise SystemExit(main()) - diff --git a/skills/nemo-fabric-integrate/SKILL.md b/skills/nemo-fabric-integrate/SKILL.md index 523cc5f21..110d5a21c 100644 --- a/skills/nemo-fabric-integrate/SKILL.md +++ b/skills/nemo-fabric-integrate/SKILL.md @@ -23,13 +23,13 @@ Fabric itself, use the maintainer skills in `.agents/skills/` instead. Stay on the public, in-memory contract. These rules keep a consumer integration supported and upgrade-safe: -- Import only from the public `nemo_fabric` package. Never import `_native`, - `_config_sources`, or any adapter-internal module. +- Import only from the public `nemo_fabric` package. Never import `_native` or + any adapter-internal module. - Build configuration as a typed `FabricConfig` in memory and pass it directly to Fabric. Create every deployment or evaluation variant with ordinary Python - functions and `model_copy(deep=True)`. (A platform integration such as Harbor - may bake a config file into a task image at its deployment boundary — that is a - deployment mechanic, not the in-memory consumer pattern here.) + functions and `model_copy(deep=True)`. A platform integration can serialize + the typed config inside a private transient run specification when it crosses + a process boundary; that transport is not a public authoring format. - Let Fabric own harness control. Do not reimplement start, invoke, or stop logic, and do not manage adapter threads, sessions, or processes directly. - Treat `runtime_id`, `invocation_id`, and `request_id` as opaque correlation @@ -47,7 +47,7 @@ runtime assumptions but never installs harnesses or credentials at run time. - Fabric is not published on PyPI yet. From a source checkout, `just build-all` builds the native extension and installs the SDK. To install into another environment, build wheels with `just wheels`, then - `uv pip install --find-links "nemo-fabric[runtime]"` (add the + `uv pip install --find-links nemo-fabric` (add the `harbor` extra for the Harbor integration). See the [installation guide](https://github.com/NVIDIA/NeMo-Fabric/blob/main/docs/getting-started/install.mdx). - Select a harness adapter — the `adapter_id` set in `HarnessConfig`, for example @@ -126,9 +126,9 @@ Pick the smallest lifecycle the consumer needs: Errors). A runtime accepts one active invocation at a time; overlapping calls raise `FabricStateError`. -The example below shows both lifecycles as a complete, runnable program; the -shorter async snippets elsewhere in this skill are fragments that assume the same -async context: +The lifecycle fragment below shows both forms. It assumes the caller has already +set `config = to_fabric_config(job)` and chosen `base`, as described in the +configuration example above: ```python import asyncio @@ -175,8 +175,6 @@ print(plan.adapter.adapter_id, report.status) contents of `harness.settings`: an unknown or misspelled adapter setting still passes and is silently ignored unless the adapter reads it, so validate settings against the adapter's own docs and your integration tests. -- Use `resolve(...)` when only the normalized effective config is needed, with - no adapter resolution. ## Consume Results And Handle Errors @@ -230,13 +228,14 @@ result-field and error inventory, and - Run the consumer project's own build and test commands. For a source checkout of Fabric, `just build-all` rebuilds the native extension and `just test-python` runs the Python suite. -- Confirm no config files were written and no non-public imports were added. +- Confirm the typed config is passed directly to Fabric and no non-public + imports were added. ## Checklist - [ ] The consumer config object is translated directly into an in-memory `FabricConfig`. -- [ ] Only public `nemo_fabric` symbols are imported; no `_native`, `_config_sources`, or adapter internals. -- [ ] The consumer config is built in memory and passed directly to Fabric, with no intermediate config file. +- [ ] Only public `nemo_fabric` symbols are imported; no `_native` or adapter internals. +- [ ] The consumer config is built in memory and passed directly to Fabric. - [ ] The right lifecycle is chosen: `run(...)` for one-shot, `start_runtime(...)` with `async with` for multi-turn. - [ ] `plan(...)` and `doctor(...)` validate adapter selection, capabilities, and environment before execution. - [ ] Installation, adapter dependencies, and credentials are owned by the environment, not consumer code. @@ -250,7 +249,7 @@ result-field and error inventory, and Link to these canonical sources instead of duplicating them: - [Python SDK guide](https://github.com/NVIDIA/NeMo-Fabric/blob/main/docs/sdk/python.mdx) -- [Getting started](https://github.com/NVIDIA/NeMo-Fabric/blob/main/docs/getting-started/overview.mdx) and +- [NeMo Fabric overview](https://github.com/NVIDIA/NeMo-Fabric/blob/main/docs/about-nemo-fabric/overview.mdx) and [installation guide](https://github.com/NVIDIA/NeMo-Fabric/blob/main/docs/getting-started/install.mdx) - Generated API reference (public API index; the installed `nemo_fabric` type stubs are authoritative for exact signatures, fields, and defaults): @@ -264,9 +263,7 @@ Link to these canonical sources instead of duplicating them: - Platform and evaluation-harness integration: [examples/harbor](https://github.com/NVIDIA/NeMo-Fabric/tree/main/examples/harbor) and [nemo_fabric.integrations.harbor](https://github.com/NVIDIA/NeMo-Fabric/tree/main/python/src/nemo_fabric/integrations/harbor). - Note the difference: Harbor bakes a config into the task image and passes it as - a file-backed `fabric_config_path` (YAML) at the container boundary. That is a - Harbor deployment mechanic, not the in-memory `FabricConfig` pattern this skill - teaches — follow the code-review example for consumer integration code, and - treat Harbor as platform context where a config crosses into a task container - as a file. + Harbor constructs a typed config from explicit agent inputs and transports it + inside a private transient run specification at the task-process boundary. + Follow the code-review example for consumer integration code; Harbor's + transport representation is an internal process-boundary contract. diff --git a/skills/nemo-fabric-integrate/references/config-mapping.md b/skills/nemo-fabric-integrate/references/config-mapping.md index 2d2bea345..0e6de9df5 100644 --- a/skills/nemo-fabric-integrate/references/config-mapping.md +++ b/skills/nemo-fabric-integrate/references/config-mapping.md @@ -68,7 +68,7 @@ ordinary Python. ## Relative Paths If the config uses relative paths for skills, workspaces, or artifacts, pass -`base_dir=...` to `resolve(...)`, `plan(...)`, `doctor(...)`, `run(...)`, or +`base_dir=...` to `plan(...)`, `doctor(...)`, `run(...)`, or `start_runtime(...)`. The base directory anchors those paths to the consumer's package or job layout, so nothing depends on the process working directory. @@ -92,9 +92,10 @@ package or job layout, so nothing depends on the process working directory. Do not surface these mechanics in the consumer-facing integration: -- Serializing `FabricConfig` to disk as the integration path (`to_mapping()` is - for inspection and logging, not a required file step). -- Importing `nemo_fabric._native`, `nemo_fabric._config_sources`, or - adapter-internal modules. +- Replacing direct SDK calls with a private serialized transport + (`to_mapping()` is for inspection and private process boundaries; redact + credentials, headers, metadata, and other sensitive or user-provided fields + before logging, and never emit an unredacted mapping to logs). +- Importing `nemo_fabric._native` or adapter-internal modules. - Reimplementing harness start, invoke, or stop logic, or managing adapter threads, sessions, or processes. diff --git a/skills/nemo-fabric-integrate/references/sdk-api-inventory.md b/skills/nemo-fabric-integrate/references/sdk-api-inventory.md index ef9498b67..99f6b1ad2 100644 --- a/skills/nemo-fabric-integrate/references/sdk-api-inventory.md +++ b/skills/nemo-fabric-integrate/references/sdk-api-inventory.md @@ -20,7 +20,6 @@ The following table lists the `Fabric` methods and when to use each. | Method | Async | Use When | Returns | | --- | --- | --- | --- | -| `resolve(config, *, base_dir=...)` | No | You need the normalized effective config, without resolving an adapter. | `EffectiveConfig` | | `plan(config, *, base_dir=...)` | No | You need the selected adapter, capability routing, and runtime capabilities before running. | `RunPlan` | | `doctor(config, *, base_dir=...)` | Yes | You need preflight diagnostics for adapter availability, config support, and environment assumptions. | `DoctorReport` | | `run(config, *, base_dir=..., input=... \| request=...)` | Yes | You need one complete start, invoke, result, and stop cycle. | `RunResult` | diff --git a/tests/_utils/configs.py b/tests/_utils/configs.py new file mode 100644 index 000000000..c72d23ed6 --- /dev/null +++ b/tests/_utils/configs.py @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Complete typed configs shared by Fabric tests.""" + +from __future__ import annotations + +from nemo_fabric import EnvironmentConfig, FabricConfig, HarnessConfig, MetadataConfig, ModelConfig, RuntimeConfig + + +def hermes_shim_config() -> FabricConfig: + config = FabricConfig( + metadata=MetadataConfig(name="hermes-shim-agent", description="Test-only Hermes-shaped agent."), + harness=HarnessConfig( + adapter_id="test.fabric.hermes_shim", + resolution="preinstalled", + settings={"workspace": "./repos/my-service"}, + ), + models={"default": ModelConfig(provider="test", model="test-model", temperature=0.0)}, + runtime=RuntimeConfig(input_schema="chat", output_schema="message", artifacts="./artifacts"), + environment=EnvironmentConfig( + provider="local", + workspace="./repos/my-service", + artifacts="./artifacts/local", + ), + ) + config.add_skill_path("./skills/code-review") + config.add_mcp_server( + "github", + transport="streamable-http", + url="${GITHUB_MCP_URL}", + exposure="harness_native", + ) + return config + + +def swebench_shim_config() -> FabricConfig: + config = hermes_shim_config() + config.harness = HarnessConfig( + adapter_id="test.fabric.hermes_shim", + resolution="preinstalled", + settings={ + "mode": "swebench_shim", + "workspace": "./repos/my-service", + "target_file": "calculator.py", + "expected_before": "return 41", + "replacement": "return 42", + "new_file": "generated/fix-notes.txt", + "new_file_contents": "patched by Fabric\n", + }, + ) + config.runtime = RuntimeConfig( + input_schema="swe_bench_task", + output_schema="patch_result", + artifacts="./artifacts/swebench", + ) + config.environment = EnvironmentConfig( + provider="local", + workspace="./repos/my-service", + artifacts="./artifacts/swebench", + ) + return config + + +def harbor_swebench_config() -> FabricConfig: + config = hermes_shim_config() + workspace = "./repos/swebench-django-13741" + config.harness = HarnessConfig( + adapter_id="test.fabric.hermes_shim", + resolution="preinstalled", + settings={ + "mode": "swebench_shim", + "workspace": workspace, + "target_file": "django/contrib/auth/forms.py", + "expected_before": " kwargs.setdefault(\"required\", False)\n super().__init__(*args, **kwargs)", + "replacement": " kwargs.setdefault(\"required\", False)\n kwargs.setdefault('disabled', True)\n super().__init__(*args, **kwargs)", + }, + ) + config.runtime = RuntimeConfig( + input_schema="harbor_swe_bench_task", + output_schema="patch_result", + artifacts="./artifacts/harbor-swebench-django-13741", + ) + config.environment = EnvironmentConfig( + provider="local", + workspace=workspace, + artifacts="./artifacts/harbor-swebench-django-13741", + metadata={"source": "harbor_swebench", "instance_id": "django__django-13741"}, + ) + return config diff --git a/tests/_utils/utils.py b/tests/_utils/utils.py index 00c565beb..6b3c10ec0 100644 --- a/tests/_utils/utils.py +++ b/tests/_utils/utils.py @@ -2,17 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 import json -import subprocess from collections.abc import Mapping from pathlib import Path from typing import Any -import yaml - -REPO_ROOT = Path(__file__).resolve().parents[2] -FABRIC_COMMAND = ("cargo", "run", "-q", "-p", "nemo-fabric-cli", "--") - - def _relay_event_total_tokens(event: dict) -> int: profile = event.get("category_profile") or {} annotated = profile.get("annotated_response") or {} @@ -64,25 +57,6 @@ def assert_semantic_relay_artifacts( assert any( expected_response.lower() in message.lower() for message in agent_messages ), agent_messages - - -def run_fabric_cli( - *args: object, - stdin: str | None = None, - timeout: float = 60.0, -) -> subprocess.CompletedProcess[str]: - """Run the Fabric CLI from the repository root and capture its output.""" - return subprocess.run( - [*FABRIC_COMMAND, *(str(arg) for arg in args)], - cwd=REPO_ROOT, - input=stdin, - text=True, - capture_output=True, - check=False, - timeout=timeout, - ) - - def assert_relay_disabled_native_observability(result: dict): """Assert telemetry-off runs still surface native harness evidence.""" @@ -111,18 +85,3 @@ def assert_process_adapter_native_observability(result: dict): assert_relay_disabled_native_observability(result) assert result["output"]["returncode"] == 0 assert result["output"]["stderr"] == "" - - -def update_base_url(profile_path: Path, api_server: str): - """ - Update the base URL in a profile. - - Since the api_server uses a random available TCP port, the base_url needs to be updated for each test. - - Args: - profile_path (Path): The absolute path to the profile YAML file. - api_server (str): The API server URL. - """ - profile = yaml.safe_load(profile_path.read_text(encoding="utf-8")) - profile["harness"]["settings"]["base_url"] = f"{api_server}/v1" - profile_path.write_text(yaml.safe_dump(profile, sort_keys=False), encoding="utf-8") diff --git a/tests/adapters/test_adapaters_common_utils.py b/tests/adapters/test_adapaters_common_utils.py index 7b4716f40..906025224 100644 --- a/tests/adapters/test_adapaters_common_utils.py +++ b/tests/adapters/test_adapaters_common_utils.py @@ -140,21 +140,19 @@ def test_selected_model_config( if selected_model is not None: settings["model"] = selected_model payload = { - "effective_config": { - "config": { - "harness": {"settings": settings}, - "models": models, - } + "config": { + "harness": {"settings": settings}, + "models": models, } } assert common_utils.selected_model_config(payload) == expected -def test_payload_accessors_prefer_effective_config(): +def test_payload_accessors_use_canonical_plan_fields(): payload = { "agent_name": "outer-agent", - "config_root": "/outer", + "base_dir": "/outer", "request": {"input": "hello"}, "environment": {"workspace": "/outer-workspace"}, "settings": {"outer": True}, @@ -163,21 +161,16 @@ def test_payload_accessors_prefer_effective_config(): "runtime_context": { "environment": {"workspace": "/runtime-workspace"}, }, - "effective_config": { - "agent_name": "effective-agent", - "config_root": "/effective", - "config": { - "harness": {"settings": {"inner": True}}, - "models": {"inner": {"model": "inner-model"}}, - }, + "config": { + "harness": {"settings": {"inner": True}}, + "models": {"inner": {"model": "inner-model"}}, }, "capability_plan": {"native": {"skill_paths": ["skills"]}}, } - assert common_utils.effective_config(payload) == payload["effective_config"] - assert common_utils.fabric_config(payload) == payload["effective_config"]["config"] - assert common_utils.agent_name(payload) == "effective-agent" - assert common_utils.config_root(payload) == "/effective" + assert common_utils.fabric_config(payload) == payload["config"] + assert common_utils.agent_name(payload) == "outer-agent" + assert common_utils.base_dir(payload) == "/outer" assert common_utils.runtime_context(payload) == payload["runtime_context"] assert common_utils.environment_payload(payload) == {"workspace": "/runtime-workspace"} assert common_utils.settings_payload(payload) == {"inner": True} @@ -185,6 +178,12 @@ def test_payload_accessors_prefer_effective_config(): assert common_utils.capability_plan(payload) == {"native": {"skill_paths": ["skills"]}} +@pytest.mark.parametrize("value", [None, "", "relative/path"]) +def test_base_dir_requires_an_absolute_path(value): + with pytest.raises(ValueError, match="base_dir"): + common_utils.base_dir({"base_dir": value}) + + def test_load_payload_reads_fabric_invocation(tmp_path: Path): invocation_path = tmp_path / "invocation.json" invocation_path.write_text( @@ -305,13 +304,11 @@ def test_load_relay_plugin_config_wraps_and_normalizes_bare_observability_config "{}", encoding="utf-8" ) payload = { - "effective_config": { - "agent_name": "review-agent", - "config_root": str(tmp_path), - "config": { - "harness": {"settings": {"model": "review"}}, - "models": {"review": {"model": "nvidia/review-model"}}, - }, + "agent_name": "review-agent", + "base_dir": str(tmp_path), + "config": { + "harness": {"settings": {"model": "review"}}, + "models": {"review": {"model": "nvidia/review-model"}}, }, "runtime_context": {"runtime_id": "runtime-current"}, } diff --git a/tests/adapters/test_claude_adapter.py b/tests/adapters/test_claude_adapter.py index 26376b1b0..22d388f62 100644 --- a/tests/adapters/test_claude_adapter.py +++ b/tests/adapters/test_claude_adapter.py @@ -81,10 +81,9 @@ def claude_payload_fixture(tmp_path) -> dict[str, Any]: skill_path.mkdir(parents=True) (skill_path / "SKILL.md").write_text("# Review\n", encoding="utf-8") return { - "effective_config": { - "agent_name": "claude-test", - "config_root": str(tmp_path), - "config": { + "agent_name": "claude-test", + "base_dir": str(tmp_path), + "config": { "harness": { "adapter_id": "nvidia.fabric.claude", "settings": { @@ -106,7 +105,6 @@ def claude_payload_fixture(tmp_path) -> dict[str, Any]: } }, "tools": {"blocked": ["Bash"]}, - }, }, "runtime_context": { "runtime_id": "runtime-claude-1", @@ -332,7 +330,7 @@ def test_build_options_does_not_enable_skills_for_relay_plugin_alone( def test_build_options_maps_blocked_tools_to_disallowed_tools(claude_payload): - claude_payload["effective_config"]["config"]["tools"] = { + claude_payload["config"]["tools"] = { "blocked": ["Bash", "WebFetch"] } @@ -356,7 +354,7 @@ def test_build_options_maps_blocked_tools_to_disallowed_tools(claude_payload): def test_build_options_rejects_normalized_capabilities_in_harness_settings( claude_payload, name, normalized_field ): - claude_payload["effective_config"]["config"]["harness"]["settings"][name] = [] + claude_payload["config"]["harness"]["settings"][name] = [] with pytest.raises( adapter.AdapterConfigError, match=normalized_field.replace(".", r"\.") @@ -372,11 +370,88 @@ def test_build_options_rejects_skill_path_without_skill_manifest(claude_payload) adapter.build_options(claude_payload, resume=None) +def test_build_options_maps_nvidia_provider_to_claude_gateway_environment( + claude_payload, +): + model = claude_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "aws/anthropic/claude-opus-4-5", + "api_key_env": "NVIDIA_API_KEY", + "settings": {"base_url": "https://nvidia.example/v1/"}, + } + ) + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + + options = adapter.build_options(claude_payload, resume=None) + + assert options.model == "aws/anthropic/claude-opus-4-5" + assert options.env["ANTHROPIC_BASE_URL"] == "https://nvidia.example" + assert options.env["ANTHROPIC_API_KEY"] == "nvidia-secret" + assert options.env["ANTHROPIC_AUTH_TOKEN"] == "" + + +def test_build_options_uses_nvidia_provider_endpoint_and_default_credential( + claude_payload, +): + model = claude_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "aws/anthropic/claude-opus-4-5", + } + ) + model.pop("api_key_env") + claude_payload["config"]["harness"]["settings"].pop("env") + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + os.environ["NVIDIA_FRONTIER_BASE_URL"] = "https://frontier.example/v1" + + options = adapter.build_options(claude_payload, resume=None) + + assert options.env["ANTHROPIC_BASE_URL"] == "https://frontier.example" + assert options.env["ANTHROPIC_API_KEY"] == "nvidia-secret" + + +def test_build_options_requires_nvidia_provider_endpoint(claude_payload): + model = claude_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "aws/anthropic/claude-opus-4-5", + "api_key_env": "NVIDIA_API_KEY", + } + ) + model.pop("settings", None) + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + os.environ.pop("NVIDIA_FRONTIER_BASE_URL", None) + + with pytest.raises(adapter.AdapterConfigError, match="NVIDIA_FRONTIER_BASE_URL"): + adapter.build_options(claude_payload, resume=None) + + +def test_build_options_requires_nvidia_provider_credential(claude_payload): + model = claude_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "aws/anthropic/claude-opus-4-5", + "api_key_env": "NVIDIA_API_KEY", + } + ) + os.environ.pop("NVIDIA_API_KEY", None) + + with pytest.raises(adapter.AdapterConfigError, match="NVIDIA_API_KEY is required"): + adapter.build_options(claude_payload, resume=None) + + def test_selected_model_rejects_unsupported_provider(claude_payload): - model = claude_payload["effective_config"]["config"]["models"]["default"] - model["provider"] = "nvidia" + model = claude_payload["config"]["models"]["default"] + model["provider"] = "openai" - with pytest.raises(adapter.AdapterConfigError, match="provider must be anthropic"): + with pytest.raises( + adapter.AdapterConfigError, match="provider must be anthropic or nvidia" + ): adapter.selected_model(claude_payload) @@ -842,9 +917,9 @@ def test_run_reports_relay_start_failure_without_raw_diagnostic( def test_build_options_forwards_anthropic_auth_environment( claude_payload, auth_environment ): - model = claude_payload["effective_config"]["config"]["models"]["default"] + model = claude_payload["config"]["models"]["default"] model.pop("api_key_env") - settings = claude_payload["effective_config"]["config"]["harness"]["settings"] + settings = claude_payload["config"]["harness"]["settings"] settings.pop("env") for name in ANTHROPIC_AUTH_ENV_NAMES: os.environ.pop(name, None) diff --git a/tests/adapters/test_codex_adapter.py b/tests/adapters/test_codex_adapter.py index 991605de0..aa804644c 100644 --- a/tests/adapters/test_codex_adapter.py +++ b/tests/adapters/test_codex_adapter.py @@ -20,10 +20,9 @@ def codex_payload_fixture(tmp_path): workspace = tmp_path / "workspace" workspace.mkdir() return { - "effective_config": { - "agent_name": "codex-test", - "config_root": str(tmp_path), - "config": { + "agent_name": "codex-test", + "base_dir": str(tmp_path), + "config": { "harness": { "adapter_id": "nvidia.fabric.codex", "settings": { @@ -41,7 +40,6 @@ def codex_payload_fixture(tmp_path): } }, "runtime": {}, - }, }, "runtime_context": { "runtime_id": "runtime-1", @@ -149,7 +147,7 @@ def test_sdk_oneshot_uses_native_thread_and_turn_contract( os.environ["CODEX_HOME"] = str(tmp_path / "codex-home") os.environ["CODEX_INTERNAL_ORIGINATOR_OVERRIDE"] = "parent-codex" os.environ["FABRIC_UNRELATED_SECRET"] = "do-not-forward" - codex_payload["effective_config"]["config"]["harness"]["settings"]["env"] = { + codex_payload["config"]["harness"]["settings"]["env"] = { "CODEX_EXPLICIT": "forward-me" } @@ -196,7 +194,7 @@ def test_sdk_can_use_an_explicit_codex_runtime(codex_payload, mock_codex, tmp_pa codex_bin = tmp_path / "bin" / "codex" codex_bin.parent.mkdir() codex_bin.touch() - codex_payload["effective_config"]["config"]["harness"]["settings"][ + codex_payload["config"]["harness"]["settings"][ "codex_bin" ] = str(codex_bin) @@ -207,22 +205,22 @@ def test_sdk_can_use_an_explicit_codex_runtime(codex_payload, mock_codex, tmp_pa @pytest.mark.parametrize("codex_bin", ["bin/codex", "~/bin/codex"]) -def test_sdk_resolves_relative_codex_runtime_from_config_root( +def test_sdk_resolves_relative_codex_runtime_from_base_dir( codex_payload, codex_bin ): - codex_payload["effective_config"]["config"]["harness"]["settings"][ + codex_payload["config"]["harness"]["settings"][ "codex_bin" ] = codex_bin config = adapter.sdk_config(codex_payload, relay=None) - config_root = Path(codex_payload["effective_config"]["config_root"]) - assert config.codex_bin == str((config_root / codex_bin).resolve()) + base_dir = Path(codex_payload["base_dir"]) + assert config.codex_bin == str((base_dir / codex_bin).resolve()) def test_sdk_keeps_absolute_codex_runtime_path(codex_payload, tmp_path): codex_bin = tmp_path / "bin" / ".." / "codex" - codex_payload["effective_config"]["config"]["harness"]["settings"][ + codex_payload["config"]["harness"]["settings"][ "codex_bin" ] = str(codex_bin) @@ -294,13 +292,112 @@ def test_incomplete_sdk_turn_is_failed_without_persisting_thread( def test_selected_model_rejects_unsupported_provider(codex_payload, mock_codex): - model = codex_payload["effective_config"]["config"]["models"]["default"] - model["provider"] = "nvidia" + model = codex_payload["config"]["models"]["default"] + model["provider"] = "anthropic" output = adapter.run(codex_payload) assert output["error"]["code"] == "codex_invalid_configuration" - assert "provider must be openai" in output["error"]["message"] + assert "provider must be openai or nvidia" in output["error"]["message"] + mock_codex.assert_not_called() + + +def test_nvidia_provider_uses_responses_api_and_nvidia_credential( + codex_payload, mock_codex +): + model = codex_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "openai/gpt-oss-120b", + "api_key_env": "NVIDIA_API_KEY", + "settings": {"base_url": "https://nvidia.example/v1/"}, + } + ) + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + + output = adapter.run(codex_payload) + + assert output["completed"] is True + client = mock_codex.instances[0] + assert client.config.env["NVIDIA_API_KEY"] == "nvidia-secret" + start = client.thread_start.await_args.kwargs + assert start["model"] == "openai/gpt-oss-120b" + assert start["model_provider"] == "nvidia" + assert client.config.env["CODEX_HOME"].endswith("/.fabric/codex/nvidia-home") + assert start["config"]["features"] == {"web_search": False} + assert start["config"]["model_providers"] == { + "nvidia": { + "name": "NVIDIA", + "base_url": "https://nvidia.example/v1", + "env_key": "NVIDIA_API_KEY", + "wire_api": "responses", + } + } + + +def test_nvidia_provider_normalizes_codex_home_creation_failure( + codex_payload, mock_codex, monkeypatch +): + model = codex_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "openai/gpt-oss-120b", + "api_key_env": "NVIDIA_API_KEY", + "settings": {"base_url": "https://nvidia.example/v1"}, + } + ) + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + + async def fail_to_create_home(*_args, **_kwargs): + raise OSError("read-only filesystem") + + monkeypatch.setattr(adapter.asyncio, "to_thread", fail_to_create_home) + + output = adapter.run(codex_payload) + + assert output["error"]["code"] == "codex_runtime_unavailable" + mock_codex.assert_not_called() + + +def test_nvidia_provider_requires_credential(codex_payload, mock_codex): + model = codex_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "openai/gpt-oss-120b", + "api_key_env": "NVIDIA_API_KEY", + } + ) + os.environ.pop("NVIDIA_API_KEY", None) + + output = adapter.run(codex_payload) + + assert output["error"]["code"] == "codex_invalid_configuration" + assert "NVIDIA_API_KEY is required" in output["error"]["message"] + assert not (adapter.state_dir(codex_payload) / "nvidia-home").exists() + mock_codex.assert_not_called() + + +def test_nvidia_provider_requires_endpoint(codex_payload, mock_codex): + model = codex_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "openai/gpt-oss-120b", + "api_key_env": "NVIDIA_API_KEY", + } + ) + model.pop("settings", None) + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + os.environ.pop("NVIDIA_FRONTIER_BASE_URL", None) + + output = adapter.run(codex_payload) + + assert output["error"]["code"] == "codex_invalid_configuration" + assert "NVIDIA_FRONTIER_BASE_URL" in output["error"]["message"] + assert not (adapter.state_dir(codex_payload) / "nvidia-home").exists() mock_codex.assert_not_called() @@ -380,6 +477,31 @@ def test_relay_uses_gateway_and_request_scoped_sdk_config( stop_gateway.assert_called_once_with(process) +def test_relay_rejects_nvidia_provider(codex_payload, mock_codex): + model = codex_payload["config"]["models"]["default"] + model.update( + { + "provider": "nvidia", + "model": "openai/gpt-oss-120b", + "api_key_env": "NVIDIA_API_KEY", + "settings": {"base_url": "https://nvidia.example/v1"}, + } + ) + codex_payload["telemetry_plan"] = { + "providers": ["relay"], + "relay_enabled": True, + } + os.environ["NVIDIA_API_KEY"] = "nvidia-secret" + + output = adapter.run(codex_payload) + + assert output["error"]["code"] == "codex_invalid_configuration" + assert output["error"]["message"] == ( + "NeMo Relay requires the built-in openai model provider" + ) + mock_codex.assert_not_called() + + def test_prepare_relay_reuses_one_resolved_executable( codex_payload, monkeypatch, tmp_path ): @@ -415,7 +537,7 @@ def test_prepare_relay_reuses_one_resolved_executable( assert relay.gateway.executable == executable assert relay.gateway.url == "http://127.0.0.1:43210" resolve.assert_called_once_with( - Path(codex_payload["effective_config"]["config_root"]).resolve(), + Path(codex_payload["base_dir"]).resolve(), "nemo-relay", ) contract.assert_called_once_with(executable) @@ -462,7 +584,7 @@ def test_relay_cleanup_failure_changes_success_to_failure( def test_native_sdk_controls_and_telemetry_are_request_scoped( codex_payload, mock_codex ): - settings = codex_payload["effective_config"]["config"]["harness"]["settings"] + settings = codex_payload["config"]["harness"]["settings"] settings.update( { "personality": "pragmatic", @@ -529,7 +651,7 @@ async def block(): mock_blocking_thread.handle.run.side_effect = block mock_codex.next_thread = mock_blocking_thread - codex_payload["effective_config"]["config"]["harness"]["settings"][ + codex_payload["config"]["harness"]["settings"][ "timeout_seconds" ] = 0.01 @@ -545,7 +667,7 @@ async def block(): "setting", ["codex_command", "codex_args", "codex_profile", "skip_git_repo_check"] ) def test_cli_only_settings_are_rejected(codex_payload, setting): - codex_payload["effective_config"]["config"]["harness"]["settings"][setting] = ( + codex_payload["config"]["harness"]["settings"][setting] = ( "legacy" ) @@ -587,8 +709,8 @@ def test_codex_config_resolves_sdk_adapter(): assert plan.adapter.adapter_id == "nvidia.fabric.codex" assert plan.adapter.harness == "codex" - assert plan.effective_config.config.runtime.input_schema == "text" - assert plan.effective_config.config.harness.settings["reasoning_effort"] == "high" + assert plan.config.runtime.input_schema == "text" + assert plan.config.harness.settings["reasoning_effort"] == "high" unsupported = plan["capability_plan"]["unsupported"] assert not unsupported.get("skill_paths") assert not unsupported.get("mcp_servers") @@ -611,7 +733,7 @@ def test_environment_preserves_runtime_telemetry_env(codex_payload): "CODEX_EXPLICIT": "telemetry", } } - codex_payload["effective_config"]["config"]["harness"]["settings"]["env"] = { + codex_payload["config"]["harness"]["settings"]["env"] = { "CODEX_EXPLICIT": "configured" } os.environ["FABRIC_RELAY_CONFIG_PATH"] = "/tmp/parent-relay.json" diff --git a/tests/adapters/test_deepagents.py b/tests/adapters/test_deepagents.py index 5e49411da..bffa8c10a 100644 --- a/tests/adapters/test_deepagents.py +++ b/tests/adapters/test_deepagents.py @@ -14,6 +14,7 @@ import importlib.machinery import sys import types +from collections.abc import Iterator from pathlib import Path from typing import Any from unittest.mock import AsyncMock @@ -126,9 +127,8 @@ def make_payload_fixture(): def make(tmp_path: Path, *, runtime_id: str = "run-1") -> dict[str, Any]: return { - "effective_config": { - "config_root": str(tmp_path), - "config": { + "base_dir": str(tmp_path), + "config": { "harness": {"settings": {"system_prompt": "be concise"}}, "models": { "default": { @@ -137,7 +137,6 @@ def make(tmp_path: Path, *, runtime_id: str = "run-1") -> dict[str, Any]: "api_key_env": "NVIDIA_API_KEY", } }, - }, }, "runtime_context": { "runtime_id": runtime_id, @@ -174,14 +173,14 @@ class ScopeType: Agent = "agent" @contextlib.contextmanager - def scope_ctx(name, scope_type, **_): + def scope_ctx(name: str, scope_type: object, **_: object) -> Iterator[None]: # Record every scope entered so tests can assert the top-level # ``deepagents-request`` Agent scope wraps the invocation. calls.setdefault("scopes", []).append((name, scope_type)) yield class NemoRelayDeepAgentsCallbackHandler: - def __init__(self, *_args, **_kwargs): + def __init__(self, *_args: object, **_kwargs: object) -> None: calls["callback_handler"] = self relay_root = types.ModuleType("nemo_relay") @@ -269,7 +268,9 @@ async def test_missing_deepagents_package_is_normalized(tmp_path, make_payload, real_find_spec = importlib_util.find_spec - def fake_find_spec(name, *args, **kwargs): + def fake_find_spec( + name: str, *args: object, **kwargs: object + ) -> importlib.machinery.ModuleSpec | None: if name == "deepagents": return None return real_find_spec(name, *args, **kwargs) @@ -401,7 +402,9 @@ async def test_missing_nemo_relay_with_native_telemetry_is_normalized(tmp_path, real_find_spec = importlib_util.find_spec - def fake_find_spec(name, *args, **kwargs): + def fake_find_spec( + name: str, *args: object, **kwargs: object + ) -> importlib.machinery.ModuleSpec | None: if name == "nemo_relay": return None return real_find_spec(name, *args, **kwargs) @@ -426,6 +429,30 @@ def fake_find_spec(name, *args, **kwargs): assert "[relay]" in output["error"] +async def test_incomplete_nemo_relay_install_is_normalized( + tmp_path, make_payload, monkeypatch, fake_relay +): + monkeypatch.delitem(sys.modules, "nemo_relay.integrations.deepagents") + payload = make_payload(tmp_path) + payload["telemetry_plan"] = { + "providers": ["native"], + "relay_enabled": False, + "native_config": { + "version": 1, + "components": [ + {"kind": "observability", "enabled": True, "config": {"version": 1}} + ], + }, + "adapter_outputs": [], + } + + output = await adapter.run_deepagents(payload) + + assert output["failed"] is True + assert "compatible 'nemo-relay' package" in output["error"] + assert "[relay]" in output["error"] + + def test_apply_callbacks_preserves_existing_ahead_of_new(): # A consumer-provided callback already on the run config must be kept, with the # Relay callback appended after it rather than replacing it. @@ -579,7 +606,7 @@ def build(**kwargs): async def test_openai_provider_keeps_openai_endpoint(tmp_path, make_payload, monkeypatch, fake_sdks): monkeypatch.setenv("OPENAI_API_KEY", "sk-test") payload = make_payload(tmp_path) - payload["effective_config"]["config"]["models"]["default"] = { + payload["config"]["models"]["default"] = { "provider": "openai", "model": "gpt-4o", "api_key_env": "OPENAI_API_KEY", @@ -693,12 +720,12 @@ async def test_subagents_are_gated_by_blocked_tools(tmp_path, make_payload): from langchain_core.messages import ToolMessage payload = make_payload(tmp_path) - payload["effective_config"]["config"]["tools"] = {"blocked": ["write_file"]} - payload["effective_config"]["config"]["harness"]["settings"]["deepagents"] = { + payload["config"]["tools"] = {"blocked": ["write_file"]} + payload["config"]["harness"]["settings"]["deepagents"] = { "subagents": [{"name": "researcher", "prompt": "research"}] } - settings = payload["effective_config"]["config"]["harness"]["settings"] + settings = payload["config"]["harness"]["settings"] create_kwargs = await adapter.build_agent_kwargs(payload, MagicMock(), settings) assert create_kwargs["middleware"], "main agent blocked-tools middleware not attached" subagents = create_kwargs["subagents"] @@ -724,9 +751,9 @@ def request(name: str) -> types.SimpleNamespace: @pytest.mark.usefixtures("use_real_langgraph") async def test_default_subagent_is_gated_by_blocked_tools(tmp_path, make_payload): payload = make_payload(tmp_path) - payload["effective_config"]["config"]["tools"] = {"blocked": ["write_file"]} + payload["config"]["tools"] = {"blocked": ["write_file"]} - settings = payload["effective_config"]["config"]["harness"]["settings"] + settings = payload["config"]["harness"]["settings"] create_kwargs = await adapter.build_agent_kwargs(payload, MagicMock(), settings) assert [subagent["name"] for subagent in create_kwargs["subagents"]] == ["general-purpose"] @@ -736,12 +763,12 @@ async def test_default_subagent_is_gated_by_blocked_tools(tmp_path, make_payload @pytest.mark.parametrize("unsupported", [{"graph_id": "remote"}, {"runnable": "compiled"}]) async def test_blocked_tools_reject_unenforceable_subagents(tmp_path, make_payload, unsupported): payload = make_payload(tmp_path) - payload["effective_config"]["config"]["tools"] = {"blocked": ["write_file"]} - payload["effective_config"]["config"]["harness"]["settings"]["deepagents"] = { + payload["config"]["tools"] = {"blocked": ["write_file"]} + payload["config"]["harness"]["settings"]["deepagents"] = { "subagents": [{"name": "worker", **unsupported}] } - settings = payload["effective_config"]["config"]["harness"]["settings"] + settings = payload["config"]["harness"]["settings"] with pytest.raises(adapter.AdapterConfigError, match="cannot be enforced"): await adapter.build_agent_kwargs(payload, MagicMock(), settings) @@ -769,7 +796,7 @@ def test_gated_subagents_reject_invalid_configuration(subagents, message): async def test_deepagents_passthrough_forwards_supported_options(tmp_path, make_payload, fake_sdks): # Documented JSON-serializable options reach create_deep_agent unchanged. payload = make_payload(tmp_path) - payload["effective_config"]["config"]["harness"]["settings"]["deepagents"] = {"interrupt_on": {"write_file": True}} + payload["config"]["harness"]["settings"]["deepagents"] = {"interrupt_on": {"write_file": True}} await adapter.run_deepagents(payload) @@ -780,7 +807,7 @@ async def test_deepagents_passthrough_cannot_override_fabric_owned_keys(tmp_path # Overriding a Fabric-owned key (here backend) would defeat workspace confinement; # it must fail loudly rather than silently replacing the derived value. payload = make_payload(tmp_path) - payload["effective_config"]["config"]["harness"]["settings"]["deepagents"] = {"backend": {"root_dir": "/etc"}} + payload["config"]["harness"]["settings"]["deepagents"] = {"backend": {"root_dir": "/etc"}} output = await adapter.run_deepagents(payload) @@ -791,7 +818,7 @@ async def test_deepagents_passthrough_cannot_override_fabric_owned_keys(tmp_path async def test_deepagents_passthrough_rejects_unknown_option(tmp_path, make_payload): # A typo or unsupported option must fail clearly instead of being silently dropped. payload = make_payload(tmp_path) - payload["effective_config"]["config"]["harness"]["settings"]["deepagents"] = { + payload["config"]["harness"]["settings"]["deepagents"] = { "interupt_on": {} # note the typo } @@ -872,7 +899,7 @@ async def test_unknown_provider_requires_api_key_env(tmp_path, make_payload, mon # defaulting to NVIDIA_API_KEY and sending the wrong key to the endpoint. monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-x") payload = make_payload(tmp_path) - payload["effective_config"]["config"]["models"]["default"] = { + payload["config"]["models"]["default"] = { "provider": "anthropic", "model": "claude-x", } @@ -889,7 +916,7 @@ async def test_openai_provider_defaults_to_openai_key(tmp_path, make_payload, mo monkeypatch.delenv("NVIDIA_API_KEY", raising=False) monkeypatch.setenv("OPENAI_API_KEY", "sk-test") payload = make_payload(tmp_path) - payload["effective_config"]["config"]["models"]["default"] = { + payload["config"]["models"]["default"] = { "provider": "openai", "model": "gpt-4o", } @@ -905,7 +932,7 @@ async def test_openai_compatible_provider_requires_api_key_env(tmp_path, make_pa # openai-compatible uses ChatOpenAI but has no default credential var, so it must # set api_key_env explicitly rather than silently falling back to NVIDIA_API_KEY. payload = make_payload(tmp_path) - payload["effective_config"]["config"]["models"]["default"] = { + payload["config"]["models"]["default"] = { "provider": "openai-compatible", "model": "some/model", } diff --git a/tests/adapters/test_hermes_adapter.py b/tests/adapters/test_hermes_adapter.py index 5cd6b408a..0124ab8f8 100644 --- a/tests/adapters/test_hermes_adapter.py +++ b/tests/adapters/test_hermes_adapter.py @@ -69,8 +69,7 @@ def test_build_hermes_config_maps_fabric_config_to_hermes_config(): }, } }, - "effective_config": { - "config": { + "config": { "harness": { "settings": { "model": "review", @@ -91,7 +90,6 @@ def test_build_hermes_config_maps_fabric_config_to_hermes_config(): "settings": {"base_url": "https://model.example/v1"}, } }, - } }, } @@ -144,11 +142,9 @@ def test_build_hermes_config_omits_max_turns_when_max_iterations_unset(): # When max_iterations is unset the config layer must leave agent.max_turns # absent so Hermes applies its own default rather than a starving override. payload = { - "effective_config": { - "config": { + "config": { "harness": {"settings": {}}, "models": {"default": {"provider": "nvidia", "model": "nvidia/test-model"}}, - } } } @@ -161,11 +157,9 @@ def test_build_hermes_config_omits_max_turns_when_max_iterations_null(): # An explicit null max_iterations is treated like unset: agent.max_turns is # omitted so Hermes applies its own default instead of a starving override. payload = { - "effective_config": { - "config": { + "config": { "harness": {"settings": {"max_iterations": None}}, "models": {"default": {"provider": "nvidia", "model": "nvidia/test-model"}}, - } } } @@ -219,10 +213,9 @@ def test_hermes_config_variation_matrix_surfaces_supported_capabilities( }, } }, - "effective_config": { - "agent_name": "matrix-agent", - "config_root": str(tmp_path), - "config": { + "agent_name": "matrix-agent", + "base_dir": str(tmp_path), + "config": { "harness": { "settings": { "model": "review", @@ -237,7 +230,6 @@ def test_hermes_config_variation_matrix_surfaces_supported_capabilities( "model": "nvidia/review-model", } }, - }, }, } @@ -274,11 +266,9 @@ def test_hermes_config_variation_matrix_surfaces_supported_capabilities( def test_write_hermes_config_writes_file(tmp_path: Path): payload = { - "effective_config": { - "config": { + "config": { "harness": {"settings": {}}, "models": {"default": {"provider": "nvidia", "model": "nvidia/test-model"}}, - } } } @@ -407,10 +397,9 @@ async def test_fabric_runtime_id_drives_hermes_session_id_and_db_history( os.environ["TEST_API_KEY"] = "secret" payload = { - "effective_config": { - "agent_name": "demo", - "config_root": str(tmp_path), - "config": { + "agent_name": "demo", + "base_dir": str(tmp_path), + "config": { "harness": { "settings": { "hermes_home": "./hermes-home", @@ -427,7 +416,6 @@ async def test_fabric_runtime_id_drives_hermes_session_id_and_db_history( "api_key_env": "TEST_API_KEY", } }, - }, }, "runtime_context": { "runtime_id": "runtime-fabric-123", diff --git a/tests/conftest.py b/tests/conftest.py index 15a8ffaa8..f68f47af6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -92,22 +92,6 @@ def code_review_agent_dir_fixture(repo_root: Path, tmp_path: Path) -> Path: ) -@pytest.fixture(name="file_config_agent_dir_src", scope="session") -def file_config_agent_dir_src_fixture(repo_root: Path) -> Path: - """Return the test-only portable config package.""" - - return repo_root / "tests" / "fixtures" / "file-config-agent" - - -@pytest.fixture(name="file_config_agent_dir") -def file_config_agent_dir_fixture( - file_config_agent_dir_src: Path, - tmp_path: Path, -) -> Path: - """Create a writable copy for CLI and file-profile tests.""" - - return _copy_agent_dir(file_config_agent_dir_src, tmp_path, "file-config-agent") - @pytest.fixture(name="api_server") def api_server_fixture(unused_tcp_port: int) -> Iterator[str]: from _utils.mock_api_server import mock_api_server diff --git a/tests/docs/test_python_api_docs.py b/tests/docs/test_python_api_docs.py index d9105b735..f8873df3c 100644 --- a/tests/docs/test_python_api_docs.py +++ b/tests/docs/test_python_api_docs.py @@ -96,12 +96,12 @@ def test_landing_page_routes_new_users_through_the_product() -> None: assert " - section: APIs\n" not in navigation for heading in ( - "## What NeMo Fabric gives you", - "## How NeMo Fabric fits", - "## Quick start", - "## Choose your interface", - "## Core workflow", - "## Next steps", + "## What NeMo Fabric Gives You", + "## How NeMo Fabric Fits", + "## Quick Start", + "## Choose Your Interface", + "## Core Workflow", + "## Next Steps", ): assert heading in landing @@ -113,8 +113,8 @@ def test_landing_page_routes_new_users_through_the_product() -> None: ): assert destination in landing - quick_start = landing.split("## Quick start", maxsplit=1)[1].split( - "## Choose your interface", maxsplit=1 + quick_start = landing.split("## Quick Start", maxsplit=1)[1].split( + "## Choose Your Interface", maxsplit=1 )[0] assert "client.plan(" not in quick_start assert "client.doctor(" not in quick_start diff --git a/tests/e2e/test_cli.py b/tests/e2e/test_cli.py deleted file mode 100644 index b6100c3f0..000000000 --- a/tests/e2e/test_cli.py +++ /dev/null @@ -1,200 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -"""Smoke test for CLI examples used in the Fabric README/design snippets.""" - -from __future__ import annotations - -import json -import subprocess -from pathlib import Path - -from _utils.utils import assert_relay_disabled_native_observability -from _utils.utils import run_fabric_cli - - -def test_cli( - tmp_path: Path, - file_config_agent_dir: Path, - hermes_shim_agent_dir: Path, -): - temp_example = file_config_agent_dir - temp_fixture = hermes_shim_agent_dir - - assert call_text("validate", temp_example).startswith("validated") - inspected = call_json("inspect", temp_example) - assert inspected["agent_name"] == "code-review-agent" - assert inspected.get("profiles", []) == [] - assert inspected["config"]["metadata"]["name"] == "code-review-agent" - - plan = call_json("plan", temp_example, "--profile", "env_local") - assert plan["agent_name"] == "code-review-agent" - assert plan["effective_config"]["agent_name"] == "code-review-agent" - assert plan["effective_config"]["profiles"] == ["env_local"] - assert plan["adapter_descriptor"]["source"] == "repository" - assert ( - plan["adapter_descriptor"]["descriptor"]["adapter_id"] - == "nvidia.fabric.hermes" - ) - - agent_schema = call_json("schema", "--name", "agent") - assert agent_schema["title"] == "FabricConfig" - - schema_dir = tmp_path / "schemas" - call_text("schema", "--output-dir", schema_dir) - assert (schema_dir / "agent.schema.json").is_file() - assert (schema_dir / "adapter-descriptor.schema.json").is_file() - assert (schema_dir / "effective-config.schema.json").is_file() - assert (schema_dir / "adapter-invocation.schema.json").is_file() - assert (schema_dir / "runtime-context.schema.json").is_file() - assert (schema_dir / "environment-handle.schema.json").is_file() - assert (schema_dir / "runtime-handle.schema.json").is_file() - assert (schema_dir / "invocation-handle.schema.json").is_file() - assert (schema_dir / "error-info.schema.json").is_file() - assert (schema_dir / "fabric-event.schema.json").is_file() - - direct_profile = temp_example / "profiles" / "hermes.yaml" - direct_plan = call_json("plan", temp_example, "--profile", direct_profile) - assert direct_plan["profiles"] == [str(direct_profile)] - assert ( - direct_plan["adapter_descriptor"]["descriptor"]["adapter_id"] - == "nvidia.fabric.hermes" - ) - - profile_plans = [ - (("hermes",), "nvidia.fabric.hermes", "python", False), - (("hermes", "relay"), "nvidia.fabric.hermes", "python", True), - ] - for profiles, adapter_id, adapter_kind, relay_enabled in profile_plans: - profile_args = [arg for profile in profiles for arg in ("--profile", profile)] - profile_plan = call_json("plan", temp_example, *profile_args) - assert profile_plan["profiles"] == list(profiles) - descriptor = profile_plan["adapter_descriptor"]["descriptor"] - assert descriptor["adapter_id"] == adapter_id - assert descriptor["adapter_kind"] == adapter_kind - assert "mode" not in profile_plan["config"]["runtime"] - assert profile_plan["capability_plan"]["native"]["skill_paths"] - assert "github" in profile_plan["capability_plan"]["native"]["mcp_servers"] - if relay_enabled: - telemetry_plan = profile_plan["telemetry_plan"] - assert telemetry_plan["relay_enabled"] is True - assert telemetry_plan["relay_output_dir"] - else: - assert profile_plan.get("telemetry_plan") is None - - multi_plan = call_json( - "plan", - temp_fixture, - "--profile", - "env_local", - "--profile", - "mcp_github", - ) - assert multi_plan["profiles"] == ["env_local", "mcp_github"] - assert "profile" not in multi_plan - assert multi_plan["telemetry_plan"]["relay_enabled"] is True - - doctor = call_json("doctor", temp_fixture, "--profile", "env_local") - assert doctor["agent_name"] == "hermes-shim-agent" - assert doctor["checks"] - - hermes = call_json( - "run", temp_fixture, "--profile", "env_local", "--input", "hello hermes" - ) - assert hermes["status"] == "succeeded" - assert hermes["adapter_kind"] == "python" - assert hermes["output"]["mode"] == "shim" - assert hermes["output"]["native_skill_paths"] - assert hermes["output"]["native_mcp_servers"] == ["github"] - assert hermes["output"]["managed_skill_paths"] == [] - assert hermes["output"]["managed_mcp_servers"] == [] - assert_relay_disabled_native_observability(hermes) - - second_run = call_json( - "run", - temp_fixture, - "--profile", - "env_local", - "--input", - "hello runtime hermes", - ) - assert second_run["status"] == "succeeded" - assert second_run["output"]["runtime_id"] == second_run["runtime_id"] - - request = json.dumps( - { - "request_id": "cli-structured-request", - "input": "hello structured hermes", - "context": {"task": {"source": "smoke"}}, - } - ) - structured = call_json( - "run", temp_fixture, "--profile", "env_local", "--request-json", request - ) - assert structured["request_id"] == "cli-structured-request" - assert structured["output"]["received"] == "hello structured hermes" - - chat = run_with_stdin( - "/help\n/verbose on\nhello chat\n/verbose off\n/clear\n/info\n/exit\n", - "chat", - temp_fixture, - "--profile", - "env_local", - "--verbose", - ) - assert chat.stdout == "" - assert '"received": "hello chat"' in chat.stderr - assert '"runtime_id": "runtime-' in chat.stderr - assert "NEMO FABRIC" in chat.stderr - assert "interactive runtime" in chat.stderr - assert "agent: hermes-shim-agent" in chat.stderr - assert "profile: env_local" in chat.stderr - assert "harness: hermes" in chat.stderr - assert "adapter: python" in chat.stderr - assert chat.stderr.count("runtime_id: runtime-") >= 2 - assert "you[env_local:runtime-" in chat.stderr - assert "> \nagent> {" in chat.stderr - assert "agent> {" in chat.stderr - assert "runtime_id: runtime-" in chat.stderr - assert "/verbose on|off" in chat.stderr - assert "/clear" in chat.stderr - assert "verbose: on" in chat.stderr - assert "verbose: off" in chat.stderr - assert "\x1b[2J\x1b[H" in chat.stderr - assert "\n\n+-- turn 1 metadata" in chat.stderr - assert "+-- turn 1 metadata" in chat.stderr - assert "| status: succeeded" in chat.stderr - assert "| request_id: request-" in chat.stderr - assert "| invocation_id: invocation-" in chat.stderr - assert "| artifact_count:" in chat.stderr - -def call_text(*args: object) -> str: - completed = run(*args) - return completed.stdout.strip() - - -def call_json(*args: object) -> dict: - completed = run(*args) - return json.loads(completed.stdout) - - -def run(*args: object) -> subprocess.CompletedProcess[str]: - completed = run_fabric_cli(*args) - if completed.returncode != 0: - raise AssertionError( - f"command failed: {completed.args}\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" - ) - return completed - - -def run_with_stdin(stdin: str, *args: object) -> subprocess.CompletedProcess[str]: - completed = run_raw(stdin, *args) - if completed.returncode != 0: - raise AssertionError( - f"command failed: {completed.args}\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" - ) - return completed - - -def run_raw(stdin: str, *args: object) -> subprocess.CompletedProcess[str]: - return run_fabric_cli(*args, stdin=stdin) diff --git a/tests/e2e/test_cli_scaffold.py b/tests/e2e/test_cli_scaffold.py new file mode 100644 index 000000000..f36521ffc --- /dev/null +++ b/tests/e2e/test_cli_scaffold.py @@ -0,0 +1,111 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import json +import os +from pathlib import Path +import subprocess +import sys + + +ROOT = Path(__file__).parents[2] + + +def generate_scaffold(destination: Path, language: str) -> None: + subprocess.run( + [ + "cargo", + "run", + "--quiet", + "-p", + "nemo-fabric-cli", + "--", + "example", + "init", + "code-review", + str(destination), + "--language", + language, + ], + cwd=ROOT, + check=True, + capture_output=True, + text=True, + ) + + +def test_generated_python_scaffold_installs_editable(tmp_path: Path): + destination = tmp_path / "python-agent" + generate_scaffold(destination, "python") + venv = tmp_path / "venv" + subprocess.run( + ["uv", "venv", "--seed", "--python", sys.executable, str(venv)], + check=True, + capture_output=True, + text=True, + ) + python = venv / ("Scripts/python.exe" if os.name == "nt" else "bin/python") + environment = os.environ.copy() + environment["PIP_NO_BUILD_ISOLATION"] = "1" + environment["PIP_NO_DEPS"] = "1" + + subprocess.run( + [str(python), "-m", "pip", "install", "-e", "."], + cwd=destination, + env=environment, + check=True, + capture_output=True, + text=True, + ) + + +def test_generated_rust_scaffold_builds(tmp_path: Path): + destination = tmp_path / "rust-agent" + generate_scaffold(destination, "rust") + assert "path =" not in (destination / "Cargo.toml").read_text() + environment = os.environ.copy() + environment["CARGO_TARGET_DIR"] = str(ROOT / "target") + core_path = json.dumps(str(ROOT / "crates/fabric-core")) + + subprocess.run( + [ + "cargo", + "build", + "--config", + f"patch.crates-io.nemo-fabric-core.path={core_path}", + "--manifest-path", + str(destination / "Cargo.toml"), + ], + env=environment, + check=True, + capture_output=True, + text=True, + ) + + +def test_failed_cli_run_returns_nonzero_status(): + environment = os.environ.copy() + environment.pop("NVIDIA_API_KEY", None) + result = subprocess.run( + [ + "cargo", + "run", + "--quiet", + "-p", + "nemo-fabric-cli", + "--", + "run", + "--preset", + "hermes", + "--input", + "Say hello", + ], + cwd=ROOT, + env=environment, + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode != 0 + assert json.loads(result.stdout)["status"] == "failed" diff --git a/tests/e2e/test_harbor_swebench_task.py b/tests/e2e/test_harbor_swebench_task.py index 05c49a682..5687161c7 100644 --- a/tests/e2e/test_harbor_swebench_task.py +++ b/tests/e2e/test_harbor_swebench_task.py @@ -5,7 +5,7 @@ This smoke is opt-in because it needs Docker and a local SWE-Bench image. It keeps Harbor responsible for task materialization and verification while Fabric -is responsible for invoking the selected harness profile and collecting a patch. +is responsible for invoking the selected typed harness config and collecting a patch. """ from __future__ import annotations @@ -17,7 +17,8 @@ import pytest -from _utils.utils import run_fabric_cli +from _utils.configs import harbor_swebench_config +from nemo_fabric import Fabric, RunRequest ROOT = Path(__file__).resolve().parents[2] HARBOR_ROOT = ROOT.parent / "harbor" @@ -29,7 +30,7 @@ VERIFY_ENV = "RUN_FABRIC_HARBOR_SWEBENCH_VERIFY" @pytest.mark.usefixtures("requires_harbor") -def test_harbor_swebench_task(hermes_shim_agent_dir: Path): +async def test_harbor_swebench_task(hermes_shim_agent_dir: Path): if os.environ.get(RUN_ENV) != "1": pytest.skip(f"set {RUN_ENV}=1 to run the Docker-backed SWE-Bench test") @@ -44,19 +45,13 @@ def test_harbor_swebench_task(hermes_shim_agent_dir: Path): copy_testbed_from_image(workspace) assert_clean_workspace(workspace) - request_file = hermes_shim_agent_dir / "django-13741.request.json" - request_file.write_text( - json.dumps(build_request(task_dir), indent=2), encoding="utf-8" - ) - - result = call_json( - "run", - hermes_shim_agent_dir, - "--profile", - "harbor_swebench_django_13741", - "--request-file", - request_file, - ) + result = ( + await Fabric().run( + harbor_swebench_config(), + base_dir=hermes_shim_agent_dir, + request=RunRequest.from_mapping(build_request(task_dir)), + ) + ).to_mapping() assert result["status"] == "succeeded", result assert result["output"]["task"]["instance_id"] == "django__django-13741" @@ -170,17 +165,6 @@ def verify_with_harbor_task(task_dir: Path, workspace: Path, logs: Path) -> None assert reward == "1", (logs / "verifier" / "report.json").read_text( encoding="utf-8" ) - - -def call_json(*args: object) -> dict: - completed = run_fabric_cli(*args) - if completed.returncode != 0: - raise AssertionError( - f"command failed: {completed.args}\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" - ) - return json.loads(completed.stdout) - - def run(*command: object, cwd: Path | None = None) -> subprocess.CompletedProcess[str]: completed = subprocess.run( [str(part) for part in command], diff --git a/tests/e2e/test_hermes_config_mapping.py b/tests/e2e/test_hermes_config_mapping.py index b231ae74b..9920260c2 100644 --- a/tests/e2e/test_hermes_config_mapping.py +++ b/tests/e2e/test_hermes_config_mapping.py @@ -51,7 +51,7 @@ def test_hermes_config_mapping(tmp_path: Path): def payload(tmpdir: str) -> dict: return { "agent_name": "code-review-agent", - "config_root": tmpdir, + "base_dir": tmpdir, "environment": { "workspace": f"{tmpdir}/workspace", }, diff --git a/tests/e2e/test_hermes_e2e.py b/tests/e2e/test_hermes_e2e.py index 118ba7d4f..2ef94a5e6 100644 --- a/tests/e2e/test_hermes_e2e.py +++ b/tests/e2e/test_hermes_e2e.py @@ -118,7 +118,7 @@ async def test_artifacts(self): relay_config = json.loads(relay_config_path.read_text(encoding="utf-8")) assert relay_config["schema_version"] == "fabric.relay/v1alpha1" assert relay_config["relay"]["enabled"] is True - assert relay_config["fabric"]["profiles"] == [] + assert relay_config["fabric"]["agent_name"] == "code-review-agent" async def test_atof_artifacts(self): kinds = {artifact["kind"] for artifact in self.relay_artifacts} diff --git a/tests/e2e/test_local_env_e2e.py b/tests/e2e/test_local_env_e2e.py index baa65c78c..bcb6f52f1 100644 --- a/tests/e2e/test_local_env_e2e.py +++ b/tests/e2e/test_local_env_e2e.py @@ -5,32 +5,31 @@ from __future__ import annotations -import json from pathlib import Path -from _utils.utils import run_fabric_cli +from _utils.configs import hermes_shim_config +from nemo_fabric import Fabric, RunRequest -def test_local_env_e2e(hermes_shim_agent_dir: Path): - plan = call_json("plan", hermes_shim_agent_dir, "--profile", "env_local") +async def test_local_env_e2e(hermes_shim_agent_dir: Path): + fabric = Fabric() + config = hermes_shim_config() + plan = fabric.plan(config, base_dir=hermes_shim_agent_dir).to_mapping() assert plan["environment_plan"]["provider"] == "local" assert plan["environment_plan"]["workspace"].endswith("repos/my-service") assert plan["adapter_descriptor"]["source"] == "local" - result = call_json( - "run", - hermes_shim_agent_dir, - "--profile", - "env_local", - "--request-json", - json.dumps( - { - "request_id": "local-env-e2e", - "input": "review local workspace", - "context": {"source": "local-e2e"}, - } - ), - ) + result = ( + await fabric.run( + config, + base_dir=hermes_shim_agent_dir, + request=RunRequest( + request_id="local-env-e2e", + input="review local workspace", + context={"source": "local-e2e"}, + ), + ) + ).to_mapping() assert result["status"] == "succeeded" assert result["request_id"] == "local-env-e2e" @@ -45,17 +44,6 @@ def test_local_env_e2e(hermes_shim_agent_dir: Path): and event["metadata"]["environment_provider"] == "local" for event in result["events"] ) - - -def call_json(*args: object) -> dict: - completed = run_fabric_cli(*args) - if completed.returncode != 0: - raise AssertionError( - f"command failed: {completed.args}\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" - ) - return json.loads(completed.stdout) - - def read_artifact(result: dict, name: str) -> str: matches = [ artifact diff --git a/tests/e2e/test_swebench_style.py b/tests/e2e/test_swebench_style.py index 562854e82..006f7ae53 100644 --- a/tests/e2e/test_swebench_style.py +++ b/tests/e2e/test_swebench_style.py @@ -5,26 +5,25 @@ from __future__ import annotations -import json import subprocess from pathlib import Path -from _utils.utils import run_fabric_cli +from _utils.configs import swebench_shim_config +from nemo_fabric import Fabric -def test_swebench_style(hermes_shim_agent_dir: Path): +async def test_swebench_style(hermes_shim_agent_dir: Path): workspace = hermes_shim_agent_dir / "repos" / "my-service" run_command(workspace, "git", "init", "-q") run_command(workspace, "git", "add", "calculator.py") - result = call_json( - "run", - hermes_shim_agent_dir, - "--profile", - "swebench_shim", - "--input", - "Fix the bug so answer() returns 42.", - ) + result = ( + await Fabric().run( + swebench_shim_config(), + base_dir=hermes_shim_agent_dir, + input="Fix the bug so answer() returns 42.", + ) + ).to_mapping() assert result["status"] == "succeeded", result assert result["adapter_kind"] == "python" @@ -47,22 +46,6 @@ def test_swebench_style(hermes_shim_agent_dir: Path): ] assert len(status_artifacts) == 1 assert "calculator.py" in Path(status_artifacts[0]["path"]).read_text() - - -def call_json(*args: object) -> dict: - completed = run(*args) - return json.loads(completed.stdout) - - -def run(*args: object) -> subprocess.CompletedProcess[str]: - completed = run_fabric_cli(*args) - if completed.returncode != 0: - raise AssertionError( - f"command failed: {completed.args}\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" - ) - return completed - - def run_command(cwd: Path, *command: str) -> None: completed = subprocess.run( command, diff --git a/tests/fixtures/file-config-agent/agent.yaml b/tests/fixtures/file-config-agent/agent.yaml deleted file mode 100644 index ef77f7063..000000000 --- a/tests/fixtures/file-config-agent/agent.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.agent/v1alpha1 - -metadata: - name: code-review-agent - description: Test fixture for file-backed configuration and profiles. - -harness: - adapter_id: nvidia.fabric.hermes - resolution: preinstalled - settings: - workspace: ./repos/my-service - -models: - default: - provider: nvidia - model: nvidia/nemotron-3-nano-30b-a3b - temperature: 0.0 - api_key_env: NVIDIA_API_KEY - -runtime: - input_schema: chat - output_schema: message - artifacts: ./artifacts - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/local - -skills: - paths: - - ./skills/code-review - -mcp: - servers: - github: - transport: streamable-http - url: ${GITHUB_MCP_URL} - exposure: harness_native - -telemetry: null - -profiles: - directories: - - ./profiles diff --git a/tests/fixtures/file-config-agent/profiles/codex.yaml b/tests/fixtures/file-config-agent/profiles/codex.yaml deleted file mode 100644 index 9abca5c06..000000000 --- a/tests/fixtures/file-config-agent/profiles/codex.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: codex -description: Test Codex SDK file-profile resolution. - -harness: - adapter_id: nvidia.fabric.codex - resolution: preinstalled - settings: - sandbox: workspace-write - reasoning_effort: high - -models: - default: - provider: openai - model: openai/gpt-5.4 - api_key_env: null - temperature: null - -skills: null -mcp: null - -runtime: - input_schema: text - output_schema: message - artifacts: ./artifacts/codex - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/codex - -telemetry: null diff --git a/tests/fixtures/file-config-agent/profiles/deepagents.yaml b/tests/fixtures/file-config-agent/profiles/deepagents.yaml deleted file mode 100644 index 8f5d507f7..000000000 --- a/tests/fixtures/file-config-agent/profiles/deepagents.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: deepagents -description: Test Deep Agents file-profile resolution. - -harness: - adapter_id: nvidia.fabric.langchain.deepagents - resolution: preinstalled - settings: - workspace: ./repos/my-service - system_prompt: You are a concise smoke test assistant. - -models: - default: - provider: nvidia - model: nvidia/nemotron-3-nano-30b-a3b - temperature: 0.0 - api_key_env: NVIDIA_API_KEY - -skills: null -mcp: null - -runtime: - input_schema: chat - output_schema: message - artifacts: ./artifacts/deepagents - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/deepagents - -telemetry: - enabled: false diff --git a/tests/fixtures/file-config-agent/profiles/env-local.yaml b/tests/fixtures/file-config-agent/profiles/env-local.yaml deleted file mode 100644 index fe770a7b6..000000000 --- a/tests/fixtures/file-config-agent/profiles/env-local.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: env_local -description: Test local environment file-profile resolution. - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/local - -telemetry: null diff --git a/tests/fixtures/file-config-agent/profiles/env-opensandbox.yaml b/tests/fixtures/file-config-agent/profiles/env-opensandbox.yaml deleted file mode 100644 index d0603fd67..000000000 --- a/tests/fixtures/file-config-agent/profiles/env-opensandbox.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: env_opensandbox -description: Test OpenSandbox environment file-profile resolution. - -environment: - provider: opensandbox - control_location: external_control - workspace: /workspace - artifacts: /workspace/artifacts - metadata: - server_url: http://127.0.0.1:8080 - image: nvcr.io/nvidia/nemo/fabric-hermes:latest - -telemetry: - providers: - relay: {} - -relay: - output_dir: ./artifacts/opensandbox - observability: - atif: - enabled: true - output_directory: ./artifacts/opensandbox diff --git a/tests/fixtures/file-config-agent/profiles/hermes.yaml b/tests/fixtures/file-config-agent/profiles/hermes.yaml deleted file mode 100644 index 8f7870f2c..000000000 --- a/tests/fixtures/file-config-agent/profiles/hermes.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: hermes -description: Test Hermes file-profile resolution. - -harness: - adapter_id: nvidia.fabric.hermes - resolution: preinstalled - settings: - workspace: ./repos/my-service - hermes_home: ./artifacts/hermes-home - base_url: https://integrate.api.nvidia.com/v1 - max_iterations: 1 - max_tokens: 512 - temperature: 0.0 - reasoning_config: - effort: none - enabled_toolsets: [] - system_prompt: You are a concise smoke test assistant. - -runtime: - input_schema: chat - output_schema: message - artifacts: ./artifacts/hermes - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/hermes - -telemetry: null diff --git a/tests/fixtures/file-config-agent/profiles/mcp-github.yaml b/tests/fixtures/file-config-agent/profiles/mcp-github.yaml deleted file mode 100644 index b45bbb80b..000000000 --- a/tests/fixtures/file-config-agent/profiles/mcp-github.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: mcp_github -description: Test MCP and telemetry file-profile merging. - -mcp: - servers: - github: - transport: streamable-http - url: ${GITHUB_MCP_URL} - exposure: fabric_managed - -telemetry: - providers: - relay: {} - -relay: - output_dir: ./artifacts/mcp-github - observability: - atif: - enabled: true - output_directory: ./artifacts/mcp-github - filename_template: "trajectory-{session_id}.atif.json" - atof: - enabled: true - output_directory: ./artifacts/mcp-github - filename: events.atof.jsonl - mode: overwrite diff --git a/tests/fixtures/file-config-agent/profiles/native-otel.yaml b/tests/fixtures/file-config-agent/profiles/native-otel.yaml deleted file mode 100644 index e49a1ee3a..000000000 --- a/tests/fixtures/file-config-agent/profiles/native-otel.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: native_otel -description: Test native telemetry file-profile resolution. - -telemetry: - providers: - native: - config: - version: 1 - components: - - kind: observability - enabled: true - config: - version: 1 - opentelemetry: - enabled: true - transport: http_binary - endpoint: http://localhost:4318/v1/traces - resource_attributes: - deployment.environment: dev diff --git a/tests/fixtures/file-config-agent/profiles/relay-openinference.yaml b/tests/fixtures/file-config-agent/profiles/relay-openinference.yaml deleted file mode 100644 index 0191fcb9a..000000000 --- a/tests/fixtures/file-config-agent/profiles/relay-openinference.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: relay_openinference -description: Test Relay OpenInference file-profile resolution. - -telemetry: - providers: - relay: {} - -relay: - output_dir: ./artifacts/relay-openinference - observability: - atif: - enabled: true - output_directory: ./artifacts/relay-openinference - filename_template: "trajectory-{session_id}.atif.json" - agent_name: code-review-agent - agent_version: fabric-poc - atof: - enabled: true - output_directory: ./artifacts/relay-openinference - filename: events.atof.jsonl - mode: overwrite - openinference: - enabled: true - transport: http_binary - endpoint: http://localhost:6006/v1/traces diff --git a/tests/fixtures/file-config-agent/profiles/relay-otel.yaml b/tests/fixtures/file-config-agent/profiles/relay-otel.yaml deleted file mode 100644 index 662f7d48e..000000000 --- a/tests/fixtures/file-config-agent/profiles/relay-otel.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: relay_otel -description: Test Relay OpenTelemetry file-profile resolution. - -telemetry: - providers: - relay: {} - -relay: - output_dir: ./artifacts/relay-otel - observability: - opentelemetry: - enabled: true - transport: http_binary - endpoint: http://localhost:4318/v1/traces - service_name: code-review-agent - service_namespace: fabric - service_version: fabric-poc - instrumentation_scope: nemo-relay-otel - timeout_millis: 3000 - resource_attributes: - deployment.environment: dev diff --git a/tests/fixtures/file-config-agent/profiles/relay.yaml b/tests/fixtures/file-config-agent/profiles/relay.yaml deleted file mode 100644 index 9550bbd80..000000000 --- a/tests/fixtures/file-config-agent/profiles/relay.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: relay -description: Test Relay ATOF/ATIF file-profile resolution. - -telemetry: - providers: - relay: {} - -relay: - output_dir: ./artifacts/relay - observability: - atif: - enabled: true - output_directory: ./artifacts/relay - filename_template: "trajectory-{session_id}.atif.json" - agent_name: code-review-agent - agent_version: fabric-poc - atof: - enabled: true - output_directory: ./artifacts/relay - filename: events.atof.jsonl - mode: overwrite diff --git a/tests/fixtures/file-config-agent/skills/code-review/README.md b/tests/fixtures/file-config-agent/skills/code-review/README.md index 3fd88c8fc..e9ce2eb55 100644 --- a/tests/fixtures/file-config-agent/skills/code-review/README.md +++ b/tests/fixtures/file-config-agent/skills/code-review/README.md @@ -3,7 +3,7 @@ SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All SPDX-License-Identifier: Apache-2.0 --> -# File Config Fixture Skill +# Relative Skill Fixture -This directory exists only to exercise relative skill paths in file-backed -configuration tests. +This directory exists only to exercise skill paths relative to a typed config's +explicit base directory. diff --git a/tests/fixtures/hermes-shim-agent/adapters/hermes-shim/src/nemo_fabric_test_adapters/hermes_shim/adapter.py b/tests/fixtures/hermes-shim-agent/adapters/hermes-shim/src/nemo_fabric_test_adapters/hermes_shim/adapter.py index 8b472694a..8aee6c9bf 100644 --- a/tests/fixtures/hermes-shim-agent/adapters/hermes-shim/src/nemo_fabric_test_adapters/hermes_shim/adapter.py +++ b/tests/fixtures/hermes-shim-agent/adapters/hermes-shim/src/nemo_fabric_test_adapters/hermes_shim/adapter.py @@ -26,12 +26,8 @@ def run(payload: dict[str, Any]) -> dict[str, Any]: return run_selected_mode(payload) -def effective_config(payload: dict[str, Any]) -> dict[str, Any]: - return payload.get("effective_config") or {} - - def fabric_config(payload: dict[str, Any]) -> dict[str, Any]: - return effective_config(payload).get("config") or {} + return payload.get("config") or {} def runtime_context(payload: dict[str, Any]) -> dict[str, Any]: diff --git a/tests/fixtures/hermes-shim-agent/agent.yaml b/tests/fixtures/hermes-shim-agent/agent.yaml deleted file mode 100644 index 92b17d861..000000000 --- a/tests/fixtures/hermes-shim-agent/agent.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.agent/v1alpha1 - -metadata: - name: hermes-shim-agent - description: Test-only Hermes-shaped agent package. - -harness: - adapter_id: test.fabric.hermes_shim - resolution: preinstalled - settings: - workspace: ./repos/my-service - -models: - default: - provider: test - model: test-model - temperature: 0.0 - -runtime: - input_schema: chat - output_schema: message - artifacts: ./artifacts - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/local - -skills: - paths: - - ./skills/code-review - -mcp: - servers: - github: - transport: streamable-http - url: ${GITHUB_MCP_URL} - exposure: harness_native - -telemetry: null - -profiles: - directories: - - ./profiles diff --git a/tests/fixtures/hermes-shim-agent/profiles/env-local.yaml b/tests/fixtures/hermes-shim-agent/profiles/env-local.yaml deleted file mode 100644 index 3ad46b047..000000000 --- a/tests/fixtures/hermes-shim-agent/profiles/env-local.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: env_local -description: Local test profile with no isolation and Relay disabled. - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/local - -telemetry: null diff --git a/tests/fixtures/hermes-shim-agent/profiles/harbor-swebench-django-13741.yaml b/tests/fixtures/hermes-shim-agent/profiles/harbor-swebench-django-13741.yaml deleted file mode 100644 index ea1d60aac..000000000 --- a/tests/fixtures/hermes-shim-agent/profiles/harbor-swebench-django-13741.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: harbor_swebench_django_13741 -description: Test-only Harbor SWE-Bench django__django-13741 patch run. - -harness: - adapter_id: test.fabric.hermes_shim - resolution: preinstalled - settings: - mode: swebench_shim - workspace: ./repos/swebench-django-13741 - target_file: django/contrib/auth/forms.py - expected_before: " kwargs.setdefault(\"required\", False)\n super().__init__(*args, **kwargs)" - replacement: " kwargs.setdefault(\"required\", False)\n kwargs.setdefault('disabled', True)\n super().__init__(*args, **kwargs)" - -runtime: - input_schema: harbor_swe_bench_task - output_schema: patch_result - artifacts: ./artifacts/harbor-swebench-django-13741 - -environment: - provider: local - workspace: ./repos/swebench-django-13741 - artifacts: ./artifacts/harbor-swebench-django-13741 - metadata: - source: harbor_swebench - instance_id: django__django-13741 - -telemetry: null diff --git a/tests/fixtures/hermes-shim-agent/profiles/mcp-github.yaml b/tests/fixtures/hermes-shim-agent/profiles/mcp-github.yaml deleted file mode 100644 index a5e9896c7..000000000 --- a/tests/fixtures/hermes-shim-agent/profiles/mcp-github.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: mcp_github -description: Test MCP capability variation. - -mcp: - servers: - github: - transport: streamable-http - url: ${GITHUB_MCP_URL} - exposure: harness_native - -telemetry: - providers: - relay: {} - -relay: - output_dir: ./artifacts/relay diff --git a/tests/fixtures/hermes-shim-agent/profiles/swebench-shim.yaml b/tests/fixtures/hermes-shim-agent/profiles/swebench-shim.yaml deleted file mode 100644 index 850a5661d..000000000 --- a/tests/fixtures/hermes-shim-agent/profiles/swebench-shim.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -schema_version: fabric.profile/v1alpha1 -name: swebench_shim -description: Test-only SWE-Bench-style run that mutates a repo and captures a patch artifact. - -harness: - adapter_id: test.fabric.hermes_shim - resolution: preinstalled - settings: - mode: swebench_shim - workspace: ./repos/my-service - target_file: calculator.py - expected_before: "return 41" - replacement: "return 42" - new_file: generated/fix-notes.txt - new_file_contents: "patched by Fabric\n" - -runtime: - input_schema: swe_bench_task - output_schema: patch_result - artifacts: ./artifacts/swebench - -environment: - provider: local - workspace: ./repos/my-service - artifacts: ./artifacts/swebench - -telemetry: null diff --git a/tests/integrations/test_harbor_runner.py b/tests/integrations/test_harbor_runner.py index 7cb870889..44b786538 100644 --- a/tests/integrations/test_harbor_runner.py +++ b/tests/integrations/test_harbor_runner.py @@ -204,9 +204,8 @@ def test_codex_adapter_maps_fabric_request_to_sdk(tmp_path): adapter = load_codex_adapter() payload = { - "effective_config": { - "config_root": str(tmp_path), - "config": { + "base_dir": str(tmp_path), + "config": { "harness": { "settings": { "sandbox": "workspace-write", @@ -220,7 +219,6 @@ def test_codex_adapter_maps_fabric_request_to_sdk(tmp_path): } }, "runtime": {}, - }, }, "runtime_context": { "runtime_id": "harbor-test", @@ -413,7 +411,6 @@ def test_swebench_matrix_translates_harbor_inputs_to_typed_config(tmp_path: Path }, ) - assert base.profiles is None assert base.environment is not None assert str(base.environment.workspace) == "/testbed" assert base.models == {} @@ -470,7 +467,6 @@ def test_harbor_lifecycle_populates_context_after_run(tmp_path: Path): result = { "agent_name": "harbor-hermes", - "profiles": [], "harness": "hermes", "adapter_kind": "python", "adapter_id": "nvidia.fabric.hermes", diff --git a/tests/integrations/test_harbor_telemetry.py b/tests/integrations/test_harbor_telemetry.py index 8c7aa2d37..6ca787f35 100644 --- a/tests/integrations/test_harbor_telemetry.py +++ b/tests/integrations/test_harbor_telemetry.py @@ -16,7 +16,6 @@ def make_result(*artifacts: dict[str, str]) -> RunResult: return RunResult.from_mapping( { "agent_name": "harbor-demo", - "profiles": [], "harness": "hermes", "adapter_kind": "python", "adapter_id": "nvidia.fabric.hermes", diff --git a/tests/python/test_code_review_example.py b/tests/python/test_code_review_example.py index 80d5a80d9..1237ab834 100644 --- a/tests/python/test_code_review_example.py +++ b/tests/python/test_code_review_example.py @@ -83,12 +83,12 @@ def test_capability_and_telemetry_variants_do_not_mutate_their_input(): assert "relay" in variants[3].telemetry.providers -def test_variants_plan_without_file_profiles(): +def test_variants_plan_from_complete_configs(): client = Fabric() for config in (hermes_config(), codex_config(), claude_config()): plan = client.plan(config, base_dir=BASE_DIR) - assert plan.profiles == () + assert plan.base_dir == BASE_DIR assert plan.agent_name == "code-review-agent" assert plan.adapter.adapter_id == config.harness.adapter_id @@ -119,7 +119,6 @@ def test_example_entrypoint_plans_without_starting_a_runtime(): assert completed.returncode == 0, completed.stderr plan = json.loads(completed.stdout) assert plan["agent_name"] == "code-review-agent" - assert plan["profiles"] == [] assert plan["adapter_descriptor"]["descriptor"]["adapter_id"] == adapter_id telemetry_plan = plan.get("telemetry_plan") if relay_enabled: diff --git a/tests/python/test_harbor_integration.py b/tests/python/test_harbor_integration.py index 699aba770..ac6b1145c 100644 --- a/tests/python/test_harbor_integration.py +++ b/tests/python/test_harbor_integration.py @@ -57,7 +57,6 @@ async def exec( self.files[result_path] = json.dumps( { "agent_name": "harbor-demo", - "profiles": [], "harness": "hermes", "adapter_kind": "python", "adapter_id": "nvidia.fabric.hermes", @@ -172,7 +171,6 @@ async def test_harbor_integration(tmp_path: Path): assert context.metadata assert context.metadata["fabric"]["status"] == "succeeded" - assert "profiles" not in context.metadata["fabric"] assert context.metadata["fabric"]["adapter_id"] == "nvidia.fabric.hermes" artifacts = context.metadata["fabric"]["artifacts"]["artifacts"] assert {artifact["name"] for artifact in artifacts} == {"stdout", "workspace_patch"} diff --git a/tests/python/test_native_sdk.py b/tests/python/test_native_sdk.py index 40ea45cb0..ab9576edd 100644 --- a/tests/python/test_native_sdk.py +++ b/tests/python/test_native_sdk.py @@ -5,17 +5,18 @@ from __future__ import annotations +import json import os import sys from pathlib import Path import nemo_fabric._native as native import pytest +from _utils.configs import hermes_shim_config from examples.code_review_agent import BASE_DIR from examples.code_review_agent import base_config from nemo_fabric import Fabric from nemo_fabric import FabricConfig -from nemo_fabric import FabricProfileConfig from nemo_fabric import FabricRuntimeError @@ -31,8 +32,8 @@ async def test_adapter_python_selects_python_adapter_interpreter( os.environ["ADAPTER_PYTHON"] = sys.executable result = await Fabric().run( - hermes_shim_agent_dir, - profiles=["env_local"], + hermes_shim_config(), + base_dir=hermes_shim_agent_dir, input="hello adapter python", ) @@ -47,23 +48,32 @@ async def test_adapter_python_rejects_invalid_path_before_start( with pytest.raises(FabricRuntimeError, match="ADAPTER_PYTHON") as caught: await Fabric().start_runtime( - hermes_shim_agent_dir, - profiles=["env_local"], + hermes_shim_config(), + base_dir=hermes_shim_agent_dir, ) assert caught.value.stage == "start" +def test_native_run_rejects_multiple_request_sources(hermes_shim_agent_dir: Path): + with pytest.raises(RuntimeError, match="mutually exclusive"): + native.run_config( + json.dumps(hermes_shim_config().model_dump(mode="json", exclude_none=True)), + str(hermes_shim_agent_dir), + "text", + None, + "{}", + None, + ) + + async def smoke(client: Fabric, fixture_agent: Path) -> None: example_config = base_config() - inspected = client.resolve(example_config, base_dir=BASE_DIR) - assert inspected["agent_name"] == "code-review-agent" - assert inspected.profiles == () - assert inspected["config"]["metadata"]["name"] == "code-review-agent" - plan = client.plan(example_config, base_dir=BASE_DIR) assert plan["agent_name"] == "code-review-agent" + assert plan.base_dir == BASE_DIR + assert plan.config.metadata.name == "code-review-agent" assert ( plan["adapter_descriptor"]["descriptor"]["adapter_id"] == "nvidia.fabric.hermes" @@ -71,19 +81,15 @@ async def smoke(client: Fabric, fixture_agent: Path) -> None: assert plan["capability_plan"]["native"]["mcp_servers"]["github"] assert plan["capability_plan"]["native"]["skill_paths"] - multi_plan = client.plan(fixture_agent, profiles=["env_local", "mcp_github"]) - assert multi_plan.profiles == ("env_local", "mcp_github") - assert multi_plan["telemetry_plan"]["relay_enabled"] is True - minimal = FabricConfig.from_mapping( { "metadata": {"name": "minimal-typed-agent"}, "harness": {"adapter_id": "nvidia.fabric.hermes"}, } ) - minimal_resolved = client.resolve(minimal) - assert minimal_resolved.config.runtime.input_schema == "text" - assert minimal_resolved.config.runtime.output_schema == "text" + minimal_plan = client.plan(minimal) + assert minimal_plan.config.runtime.input_schema == "text" + assert minimal_plan.config.runtime.output_schema == "text" typed_config = FabricConfig.from_mapping( { @@ -92,7 +98,10 @@ async def smoke(client: Fabric, fixture_agent: Path) -> None: "harness": { "adapter_id": "test.fabric.hermes_shim", "resolution": "preinstalled", - "settings": {"workspace": "./repos/my-service"}, + "settings": { + "workspace": "./repos/my-service", + "timeout_seconds": 30, + }, }, "models": { "default": { @@ -120,62 +129,45 @@ async def smoke(client: Fabric, fixture_agent: Path) -> None: } } }, - "telemetry": None, + "telemetry": {"providers": {"relay": {}}}, + "relay": {"output_dir": "./artifacts/relay"}, "consumer_extension": { "base": True, - "nested": {"first": 1}, + "custom": True, + "nested": {"first": 1, "second": 2}, }, } ) - typed_profile = FabricProfileConfig( - name="typed_relay", - harness={"settings": {"timeout_seconds": 30}}, - telemetry={"providers": {"relay": {}}}, - relay={"output_dir": "./artifacts/relay"}, - consumer_extension={ - "profile": True, - "nested": {"second": 2}, - }, - ) - typed_config_resolved = client.resolve( - typed_config, - profiles=[typed_profile], - base_dir=fixture_agent, - ) typed_plan = client.plan( typed_config, - profiles=[typed_profile], base_dir=fixture_agent, ) - assert typed_config_resolved.agent_name == "typed-hermes-shim-agent" assert typed_plan["agent_name"] == "typed-hermes-shim-agent" - assert typed_plan.profiles == ("typed_relay",) assert typed_plan["adapter_descriptor"]["source"] == "local" assert typed_plan["telemetry_plan"]["relay_enabled"] is True - resolved_config = typed_config_resolved.config.to_mapping() + resolved_config = typed_plan.config.to_mapping() assert resolved_config["harness"]["adapter_id"] == "test.fabric.hermes_shim" assert resolved_config["harness"]["settings"]["workspace"] == "./repos/my-service" assert resolved_config["harness"]["settings"]["timeout_seconds"] == 30 assert resolved_config["consumer_extension"] == { "base": True, - "profile": True, + "custom": True, "nested": {"first": 1, "second": 2}, } result = await client.run( - fixture_agent, - profiles=["env_local"], + hermes_shim_config(), + base_dir=fixture_agent, input="hello native", ) async with await client.start_runtime( - fixture_agent, - profiles=["env_local"], + hermes_shim_config(), + base_dir=fixture_agent, ) as runtime: first = await runtime.invoke(input="hello runtime one") second = await runtime.invoke(input="hello runtime two") assert result["status"] == "succeeded" - assert result.profiles == ("env_local",) assert result.harness == "hermes" assert result["adapter_kind"] == "python" assert result["metadata"]["adapter_runner"] == "python" @@ -184,7 +176,6 @@ async def smoke(client: Fabric, fixture_agent: Path) -> None: assert any(artifact.name == "stdout" for artifact in result.artifacts.artifacts) assert first["status"] == "succeeded" assert second["status"] == "succeeded" - assert first.profiles == ("env_local",) assert first.harness == "hermes" assert first["runtime_id"] == second["runtime_id"] assert runtime.handle["runtime_id"] == first["runtime_id"] diff --git a/tests/python/test_runtime.py b/tests/python/test_runtime.py index e354b0249..582c351d8 100644 --- a/tests/python/test_runtime.py +++ b/tests/python/test_runtime.py @@ -40,15 +40,7 @@ def _plan() -> dict[str, Any]: } return { "agent_name": "demo", - "profiles": ["typed"], - "effective_config": { - "agent_name": "demo", - "profiles": ["typed"], - "agent_root": ".", - "config_path": "agent.yaml", - "config_root": ".", - "config": config, - }, + "base_dir": ".", "config": config, "adapter_descriptor": { "descriptor": { @@ -91,14 +83,19 @@ def _config() -> FabricConfig: ) +async def _wait_for(event: threading.Event, timeout: float = 2.0) -> bool: + loop = asyncio.get_running_loop() + deadline = loop.time() + timeout + while not event.is_set() and loop.time() < deadline: + await asyncio.sleep(0.001) + return event.is_set() + + @pytest.fixture(name="mock_native") def mock_native_fixture() -> MagicMock: mock_native = MagicMock() mock_native.requests = [] - mock_native.plan.side_effect = lambda path, profiles: json.dumps(_plan()) - mock_native.plan_config.side_effect = ( - lambda config_json, profiles_json, base_dir: json.dumps(_plan()) - ) + mock_native.plan_config.side_effect = lambda config_json, base_dir: json.dumps(_plan()) mock_native.start_runtime.return_value = json.dumps(_runtime()) def invoke(plan_json: str, runtime_json: str, request_json: str) -> str: @@ -109,7 +106,6 @@ def invoke(plan_json: str, runtime_json: str, request_json: str) -> str: return json.dumps( { "agent_name": "demo", - "profiles": ["typed"], "harness": "hermes", "adapter_kind": "python", "adapter_id": "test.fabric.shim", @@ -158,21 +154,17 @@ def _runtime_wrapper( ) -async def test_start_runtime_supports_path_and_typed_sources( +async def test_start_runtime_supports_typed_source_and_base_dir( native_client: Fabric, mock_native: MagicMock, ): - path_runtime = await native_client.start_runtime("agent", profiles=["typed"]) typed_runtime = await native_client.start_runtime( _config(), - profiles=[], base_dir=".", ) - assert path_runtime.runtime_id == "runtime-1" assert typed_runtime.runtime_id == "runtime-1" - assert mock_native.plan.call_args.args == ("agent", ["typed"]) - assert mock_native.plan_config.called + assert mock_native.plan_config.call_args.args[1] == "." async def test_start_runtime_preserves_start_stage( @@ -182,7 +174,7 @@ async def test_start_runtime_preserves_start_stage( mock_native.start_runtime.side_effect = RuntimeError("start failed") with pytest.raises(FabricRuntimeError, match="start failed") as caught: - await native_client.start_runtime("agent") + await native_client.start_runtime(_config()) assert caught.value.stage == "start" @@ -193,7 +185,7 @@ async def test_start_runtime_rejects_invalid_overrides_before_start( ): with pytest.raises(FabricConfigError, match="keys must be strings"): await native_client.start_runtime( - "agent", + _config(), overrides={"nested": {1: "invalid"}}, # type: ignore[dict-item] ) @@ -208,7 +200,7 @@ async def test_start_runtime_rejects_cyclic_overrides_before_start( overrides["cycle"] = overrides with pytest.raises(FabricConfigError, match="JSON-compatible"): - await native_client.start_runtime("agent", overrides=overrides) + await native_client.start_runtime(_config(), overrides=overrides) mock_native.start_runtime.assert_not_called() @@ -333,7 +325,7 @@ def blocking_invoke(*args: Any) -> str: mock_native.invoke_runtime.side_effect = blocking_invoke runtime = _runtime_wrapper(mock_native) turn = asyncio.create_task(runtime.invoke(input="hello")) - assert await asyncio.to_thread(started.wait, 2) + assert await _wait_for(started) with pytest.raises(FabricStateError, match="in flight"): await runtime.stop() @@ -357,7 +349,7 @@ def blocking_invoke(*args: Any) -> str: mock_native.invoke_runtime.side_effect = blocking_invoke runtime = _runtime_wrapper(mock_native) first = asyncio.create_task(runtime.invoke(input="one")) - assert await asyncio.to_thread(started.wait, 2) + assert await _wait_for(started) with pytest.raises(FabricStateError, match="already running"): await runtime.invoke(input="two") @@ -390,7 +382,7 @@ def blocking_invoke(*args: Any) -> str: first = asyncio.create_task(first_runtime.invoke(input="one")) second = asyncio.create_task(second_runtime.invoke(input="two")) - assert await asyncio.to_thread(both_started.wait, 2) + assert await _wait_for(both_started) assert not first.done() assert not second.done() @@ -425,7 +417,7 @@ def blocking_invoke(*args: Any) -> str: mock_native.invoke_runtime.side_effect = blocking_invoke runtime = _runtime_wrapper(mock_native) turn = asyncio.create_task(runtime.invoke(input="hello")) - assert await asyncio.to_thread(started.wait, 2) + assert await _wait_for(started) turn.cancel() await asyncio.sleep(0) @@ -455,8 +447,8 @@ def blocking_start(*args: Any) -> str: return json.dumps(_runtime()) mock_native.start_runtime.side_effect = blocking_start - start = asyncio.create_task(native_client.start_runtime("agent")) - assert await asyncio.to_thread(started.wait, 2) + start = asyncio.create_task(native_client.start_runtime(_config())) + assert await _wait_for(started) start.cancel() await asyncio.sleep(0) @@ -483,8 +475,8 @@ def blocking_invoke(*args: Any) -> str: return invoke(*args) mock_native.invoke_runtime.side_effect = blocking_invoke - run = asyncio.create_task(native_client.run("agent", input="hello")) - assert await asyncio.to_thread(started.wait, 2) + run = asyncio.create_task(native_client.run(_config(), input="hello")) + assert await _wait_for(started) run.cancel() await asyncio.sleep(0) @@ -501,13 +493,13 @@ async def test_run_stops_runtime_after_success_and_failure( native_client: Fabric, mock_native: MagicMock, ): - result = await native_client.run("agent", input="hello") + result = await native_client.run(_config(), input="hello") assert result.status == "succeeded" assert mock_native.stop_runtime.call_count == 1 mock_native.invoke_runtime.side_effect = RuntimeError("invoke failed") with pytest.raises(FabricRuntimeError, match="invoke failed"): - await native_client.run("agent", input="hello") + await native_client.run(_config(), input="hello") assert mock_native.stop_runtime.call_count == 2 @@ -524,8 +516,8 @@ def record_plan(*args: Any, **kwargs: Any): monkeypatch.setattr(native_client, "plan", record_plan) - await native_client.run("agent", input="hello") - runtime = await native_client.start_runtime("agent") + await native_client.run(_config(), input="hello") + runtime = await native_client.start_runtime(_config()) await runtime.stop() assert len(planning_calls) == 2 @@ -538,7 +530,7 @@ async def test_run_surfaces_cleanup_failure_after_success( mock_native.stop_runtime.side_effect = RuntimeError("stop failed") with pytest.raises(FabricRuntimeError, match="stop failed") as caught: - await native_client.run("agent", input="hello") + await native_client.run(_config(), input="hello") assert caught.value.stage == "run" assert mock_native.stop_runtime.call_count == 1 @@ -557,4 +549,4 @@ async def test_native_unavailable_uses_typed_error(monkeypatch: pytest.MonkeyPat monkeypatch.setattr(client_mod, "_native", None) with pytest.raises(FabricNativeUnavailableError, match="native extension"): - Fabric().plan("agent") + Fabric().plan(_config()) diff --git a/tests/python/test_sdk_concurrency.py b/tests/python/test_sdk_concurrency.py index 54761e17f..a1bf01bb1 100644 --- a/tests/python/test_sdk_concurrency.py +++ b/tests/python/test_sdk_concurrency.py @@ -9,18 +9,19 @@ from pathlib import Path from shutil import copytree +from _utils.configs import hermes_shim_config from nemo_fabric import Fabric async def run_runtime(client: Fabric, agent: Path, name: str) -> dict: - async with await client.start_runtime(agent, profiles=["env_local"]) as runtime: + async with await client.start_runtime(hermes_shim_config(), base_dir=agent) as runtime: return await runtime.invoke(input=f"hello from {name}") async def run_copy(client: Fabric, fixture_agent: Path, root: Path, name: str) -> dict: agent = root / name copytree(fixture_agent, agent) - return await client.run(agent, profiles=["env_local"], input=f"hello from {name}") + return await client.run(hermes_shim_config(), base_dir=agent, input=f"hello from {name}") async def test_sdk_concurrency(hermes_shim_agent_dir_src: Path, tmp_path: Path): diff --git a/tests/python/test_sdk_contract.py b/tests/python/test_sdk_contract.py index f66f93692..2b44272c5 100644 --- a/tests/python/test_sdk_contract.py +++ b/tests/python/test_sdk_contract.py @@ -16,7 +16,6 @@ import pytest from nemo_fabric import AdapterInfo from nemo_fabric import DoctorReport -from nemo_fabric import EffectiveConfig from nemo_fabric import EnvironmentConfig from nemo_fabric import Fabric from nemo_fabric import FabricCapabilityError @@ -24,7 +23,6 @@ from nemo_fabric import FabricConfigError from nemo_fabric import FabricError from nemo_fabric import FabricNativeUnavailableError -from nemo_fabric import FabricProfileConfig from nemo_fabric import FabricRuntimeError from nemo_fabric import FabricStateError from nemo_fabric import HarnessConfig @@ -46,7 +44,7 @@ from nemo_fabric import SkillConfig from nemo_fabric import TelemetryConfig from nemo_fabric import ToolsConfig -from nemo_fabric.types import _ResolvedFabricConfig +from nemo_fabric.types import _FabricConfigSnapshot from nemo_fabric.types import _ToolsConfig from pydantic import ValidationError @@ -60,8 +58,9 @@ def test_public_contract_has_no_unreleased_aliases(): for name in ("plan_config", "run_config", "doctor_config", "start", "start_config"): assert not hasattr(Fabric, name) - for name in ("resolve", "plan", "doctor", "run", "start_runtime"): - assert len(get_overloads(getattr(Fabric, name))) == 2, name + assert not hasattr(Fabric, "resolve") + for name in ("plan", "doctor", "run", "start_runtime"): + assert not get_overloads(getattr(Fabric, name)), name assert not hasattr(fabric_errors, "FabricCliError") @@ -201,7 +200,7 @@ def test_typed_tools_config_serializes_blocked_policy(): def test_run_plan_config_block_tools_emits_canonical_shape(): - config = _ResolvedFabricConfig.from_mapping(_plan()["config"]) + config = _FabricConfigSnapshot.from_mapping(_plan()["config"]) config.block_tools("browser", "shell", "browser") @@ -384,18 +383,11 @@ def test_inspection_models_are_typed_read_only_mappings(): plan = RunPlan.from_mapping( { "agent_name": "demo", - "profiles": ["runtime", "telemetry"], - "effective_config": { - "agent_name": "demo", - "profiles": ["runtime", "telemetry"], - "agent_root": ".", - "config_path": "agent.yaml", - "config_root": ".", - "config": { - "metadata": {"name": "demo"}, - "harness": {"adapter_id": "test.fabric.shim"}, - "runtime": {"input_schema": "chat"}, - }, + "base_dir": ".", + "config": { + "metadata": {"name": "demo"}, + "harness": {"adapter_id": "test.fabric.shim"}, + "runtime": {"input_schema": "chat"}, }, "adapter_descriptor": { "descriptor": { @@ -415,21 +407,48 @@ def test_inspection_models_are_typed_read_only_mappings(): } ) - assert isinstance(plan.effective_config, EffectiveConfig) assert isinstance(plan.adapter, AdapterInfo) assert isinstance(plan.capabilities, RuntimeCapabilities) - assert plan.profiles == ("runtime", "telemetry") + assert plan.base_dir == Path(".") assert plan.adapter.harness == "hermes" assert "harness_type" not in plan.adapter assert plan.adapter.extra_fields["future"] == "value" assert plan.capabilities.extra_fields["future_capability"] == "declared" resolved = plan.to_mapping() - plan.effective_config.config.metadata.name = "mutated" + plan.config.metadata.name = "mutated" assert plan.to_mapping() == resolved with pytest.raises(TypeError): plan["agent_name"] = "mutated" # type: ignore[index] +def test_run_plan_config_rejects_removed_profiles_and_missing_base_dir(): + with pytest.raises(FabricConfigError, match="profiles are no longer supported"): + _FabricConfigSnapshot.from_mapping( + { + "metadata": {"name": "demo"}, + "harness": {"adapter_id": "test.fabric.shim"}, + "profiles": {"review": {}}, + } + ) + + with pytest.raises(FabricConfigError, match="base_dir is required"): + RunPlan.from_mapping( + { + "agent_name": "demo", + "config": { + "metadata": {"name": "demo"}, + "harness": {"adapter_id": "test.fabric.shim"}, + }, + "adapter": { + "adapter_id": "test.fabric.shim", + "harness": "shim", + "adapter_kind": "python", + }, + "capabilities": {}, + } + ) + + def test_runtime_handle_distinguishes_contract_and_extension_fields(): handle = RuntimeHandle.from_mapping( { @@ -471,29 +490,8 @@ def test_runtime_handle_requires_native_contract_fields(field): RuntimeHandle.from_mapping(raw) -@pytest.mark.parametrize( - ("model", "payload"), - ( - (EffectiveConfig, {"config": {}}), - (DoctorReport, {}), - (RunResult, {}), - ), -) -def test_snapshot_models_require_profiles(model, payload): - with pytest.raises(FabricConfigError, match="profiles is required"): - model.from_mapping(payload) - - -def test_run_plan_requires_profiles(): - raw = _plan() - del raw["profiles"] - - with pytest.raises(FabricConfigError, match="RunPlan profiles is required"): - RunPlan.from_mapping(raw) - - def test_run_plan_config_enable_relay_preserves_existing_relay_fields(): - config = _ResolvedFabricConfig.from_mapping(_plan()["config"]) + config = _FabricConfigSnapshot.from_mapping(_plan()["config"]) config.enable_relay( output_dir="./artifacts/relay", @@ -509,7 +507,7 @@ def test_run_plan_config_enable_relay_preserves_existing_relay_fields(): def test_run_plan_config_enable_native_preserves_existing_native_config(): - config = _ResolvedFabricConfig.from_mapping(_plan()["config"]) + config = _FabricConfigSnapshot.from_mapping(_plan()["config"]) config.telemetry.enable_native(config={"components": [{"kind": "observability"}]}) config.telemetry.enable_native() @@ -528,7 +526,6 @@ def test_doctor_report_and_errors_expose_typed_contract_fields(): report = DoctorReport.from_mapping( { "agent_name": "demo", - "profiles": [], "status": "warn", "checks": [ { @@ -565,15 +562,7 @@ def _plan() -> dict[str, Any]: } return { "agent_name": "demo", - "profiles": ["typed"], - "effective_config": { - "agent_name": "demo", - "profiles": ["typed"], - "agent_root": ".", - "config_path": "agent.yaml", - "config_root": ".", - "config": config, - }, + "base_dir": ".", "config": config, "adapter_descriptor": { "descriptor": { @@ -611,7 +600,6 @@ def _runtime() -> dict[str, Any]: def _run_result(**updates: Any) -> dict[str, Any]: result = { "agent_name": "demo", - "profiles": [], "harness": "hermes", "adapter_kind": "python", "adapter_id": "test.fabric.shim", @@ -638,39 +626,17 @@ def _fabric_config() -> FabricConfig: class NativeRecorder: def __init__(self) -> None: self.requests: list[dict[str, Any]] = [] - self.path_profile_calls: list[Any] = [] - self.config_profile_calls: list[Any] = [] + self.config_base_dir_calls: list[str | None] = [] self.stopped = 0 self.fail_invoke = False - def plan(self, path: str, profile: Any = None) -> str: - assert path == "agent" - self.path_profile_calls.append(profile) - return json.dumps(_plan()) - - def inspect(self, path: str, profile: Any = None) -> str: - assert path == "agent" - self.path_profile_calls.append(profile) - return json.dumps(_plan()["effective_config"]) - - def resolve_config( - self, - config_json: str, - profiles_json: str | None = None, - base_dir: str | None = None, - ) -> str: - assert json.loads(config_json)["metadata"]["name"] == "demo" - self.config_profile_calls.append(None if profiles_json is None else json.loads(profiles_json)) - return json.dumps(_plan()["effective_config"]) - def plan_config( self, config_json: str, - profiles_json: str | None = None, base_dir: str | None = None, ) -> str: assert json.loads(config_json)["metadata"]["name"] == "demo" - self.config_profile_calls.append(None if profiles_json is None else json.loads(profiles_json)) + self.config_base_dir_calls.append(base_dir) return json.dumps(_plan()) def start_runtime(self, plan_json: str) -> str: @@ -685,7 +651,6 @@ def invoke_runtime(self, plan_json: str, runtime_json: str, request_json: str) - return json.dumps( { "agent_name": "demo", - "profiles": ["typed"], "harness": "hermes", "adapter_kind": "python", "adapter_id": "test.fabric.shim", @@ -995,12 +960,12 @@ def test_run_result_requires_schema_identity_fields(field): RunResult.from_mapping(raw) -async def test_run_accepts_full_run_request_on_native_path(): +async def test_run_accepts_full_run_request(): native = NativeRecorder() client = NativeClient(native) result = await client.run( - "agent", + _fabric_config(), request=RunRequest( input="hello", request_id="request-4", @@ -1171,53 +1136,9 @@ def model_dump(self, *, mode: str, exclude_none: bool) -> dict[str, Any]: metadata={"name": "demo"}, harness={"adapter_id": "test.fabric.shim"}, ) - client.plan(config, profiles=[FabricProfileConfig(name="typed")]) - - assert native.config_profile_calls == [[{"schema_version": "fabric.profile/v1alpha1", "name": "typed"}]] - - -def test_typed_config_profiles_require_profile_models(): - client = NativeClient(NativeRecorder()) - - client.plan( - _fabric_config(), - profiles=[FabricProfileConfig(name="typed_relay")], - ) - - with pytest.raises(FabricConfigError, match="FabricProfileConfig"): - client.plan( - _fabric_config(), - profiles=[{"name": "typed_relay"}], # type: ignore[list-item] - ) - - with pytest.raises(FabricConfigError, match="FabricProfileConfig"): - client.plan(_fabric_config(), profiles="typed_relay") # type: ignore[arg-type] + client.plan(config, base_dir=".") - with pytest.raises(FabricConfigError, match="FabricProfileConfig"): - client.plan( - _fabric_config(), - profiles=["typed_relay"], # type: ignore[list-item] - ) - - -def test_path_source_accepts_single_profile_name(): - native = NativeRecorder() - - NativeClient(native).plan("agent", profiles="hermes_runtime") - - assert native.path_profile_calls == [["hermes_runtime"]] - - -def test_path_source_rejects_mapping_profiles_before_native_planning(): - native = NativeRecorder() - - with pytest.raises(FabricConfigError, match="profile names"): - NativeClient(native).plan( - "agent", - profiles={"name": "hermes_runtime"}, # type: ignore[arg-type] - ) - - assert native.path_profile_calls == [] + assert native.config_base_dir_calls == ["."] def test_fabric_config_constructors_emit_schema_shaped_mappings(): @@ -1243,21 +1164,11 @@ def test_fabric_config_constructors_emit_schema_shaped_mappings(): assert config.harness.settings["workspace"] == "./ws" client = NativeClient(NativeRecorder()) - client.plan(config, profiles=[FabricProfileConfig(name="typed_relay")]) - - -def test_resolve_accepts_path_and_fabric_config_sources(): - client = NativeClient(NativeRecorder()) - - path_config = client.resolve("agent") - typed_config = client.resolve(_fabric_config()) - - assert path_config["config"]["runtime"]["input_schema"] == "chat" - assert typed_config["config"]["runtime"]["input_schema"] == "chat" + client.plan(config) async def test_start_runtime_returns_runtime_with_typed_handle(): - runtime = await NativeClient(NativeRecorder()).start_runtime("agent") + runtime = await NativeClient(NativeRecorder()).start_runtime(_fabric_config()) assert runtime.runtime_id == "runtime-1" assert isinstance(runtime.handle, RuntimeHandle) diff --git a/tests/python/test_sdk_runtimes.py b/tests/python/test_sdk_runtimes.py index ff442c387..a57bc431f 100644 --- a/tests/python/test_sdk_runtimes.py +++ b/tests/python/test_sdk_runtimes.py @@ -22,15 +22,7 @@ def _plan() -> dict[str, Any]: } return { "agent_name": "demo", - "profiles": ["hermes"], - "effective_config": { - "agent_name": "demo", - "profiles": ["hermes"], - "agent_root": ".", - "config_path": "agent.yaml", - "config_root": ".", - "config": config, - }, + "base_dir": ".", "config": config, "adapter_descriptor": { "descriptor": { @@ -80,7 +72,6 @@ def invoke_runtime( return json.dumps( { "agent_name": "demo", - "profiles": ["hermes"], "harness": "hermes", "adapter_kind": "python", "adapter_id": "test.fabric.shim", diff --git a/tests/python/test_typed_config.py b/tests/python/test_typed_config.py index 710ea064f..499460494 100644 --- a/tests/python/test_typed_config.py +++ b/tests/python/test_typed_config.py @@ -1,43 +1,35 @@ # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -"""Smoke test: typed (in-memory) config is first-class, with no agent directory. +"""Smoke test: typed config is the first-class Fabric input. -The unified SDK methods accept a typed config object and resolve, diagnose, and -run it without an on-disk agent package: +The SDK methods accept a complete typed config and an optional base directory: * ``plan`` / ``doctor`` resolve a maintained (repository) adapter - with ``base_dir=None`` -- zero filesystem layout, no ``agent.yaml``. + with ``base_dir=None``. * ``run`` drives a real core runtime run using only a local adapter directory - (still no agent package). + and a typed config. This complements ``test_native_sdk.py``, which exercises ``plan`` with a ``base_dir`` pointed at an agent package. """ from __future__ import annotations -import json -import subprocess import tempfile from pathlib import Path from shutil import copytree -import yaml from nemo_fabric import Fabric from nemo_fabric import FabricConfig -from nemo_fabric import FabricProfileConfig from nemo_fabric import RunRequest from nemo_fabric import RunResult ROOT = Path(__file__).resolve().parents[2] -COMMAND = ("cargo", "run", "-q", "-p", "nemo-fabric-cli", "--") -# The test adapter (needs only python3, no secrets), shipped as a fixture. -SHIM_AGENT = ROOT / "tests" / "fixtures" / "hermes-shim-agent" SHIM_ADAPTERS = ROOT / "tests" / "fixtures" / "hermes-shim-agent" / "adapters" def _repository_adapter_config() -> FabricConfig: - """Config referencing a maintained adapter resolvable without any package.""" + """Config referencing a maintained adapter.""" return FabricConfig.from_mapping( { @@ -85,25 +77,20 @@ def _shim_adapter_config() -> FabricConfig: return FabricConfig.from_mapping(config) -async def resolves_and_diagnoses_without_a_directory(client: Fabric) -> None: - """plan / doctor resolve a maintained adapter with no package.""" +async def resolves_and_diagnoses_typed_config(client: Fabric) -> None: + """Plan and doctor resolve a complete typed config.""" config = _repository_adapter_config() - # base_dir=None: the literal "no path at all" call must still resolve. plan_no_path = client.plan(config) assert plan_no_path["agent_name"] == "typed-only-agent" - # Point base_dir at an EMPTY directory (not an agent package): resolution can - # then only succeed via the baked-in repository adapter dir, so the source is - # deterministic regardless of the process CWD. with tempfile.TemporaryDirectory(prefix="typed-no-dir-") as empty: plan = client.plan(config, base_dir=empty) report = await client.doctor(config, base_dir=empty) descriptor = plan["adapter_descriptor"] assert descriptor["descriptor"]["adapter_id"] == "nvidia.fabric.hermes" - # "repository" (not "local") proves it resolved without any on-disk package. assert descriptor["source"] == "repository", descriptor["source"] assert report["agent_name"] == "typed-only-agent" @@ -111,17 +98,14 @@ async def resolves_and_diagnoses_without_a_directory(client: Fabric) -> None: assert report["status"] in {"pass", "warn", "fail"}, report["status"] -async def runs_without_an_agent_package(client: Fabric) -> None: - """run drives a core run with only an adapter dir (no agent.yaml).""" +async def runs_with_typed_config_and_adapter_directory(client: Fabric) -> None: + """Run with a typed config and local adapter descriptor.""" config = _shim_adapter_config() with tempfile.TemporaryDirectory(prefix="typed-run-") as tmpdir: base = Path(tmpdir) / "scratch" - # Only the adapter lives here -- this is deliberately NOT an agent - # package (no agent.yaml / profiles / repos / skills). copytree(SHIM_ADAPTERS, base / "adapters") (base / "ws").mkdir() - assert not (base / "agent.yaml").exists() result = await client.run( config, base_dir=base, @@ -141,64 +125,7 @@ async def runs_without_an_agent_package(client: Fabric) -> None: assert result["output"]["received"] == "hello typed" -def sdk_and_cli_profile_stacks_match(client: Fabric) -> None: - """The same config/profile stack plans identically through CLI and SDK.""" - - config = FabricConfig.from_mapping(_load_yaml(SHIM_AGENT / "agent.yaml")) - profiles = [ - FabricProfileConfig.model_validate( - _load_yaml(SHIM_AGENT / "profiles" / "env-local.yaml") - ), - FabricProfileConfig.model_validate( - _load_yaml(SHIM_AGENT / "profiles" / "mcp-github.yaml") - ), - ] - - sdk_plan = client.plan(config, profiles=profiles, base_dir=SHIM_AGENT) - cli_plan = _cli_plan(SHIM_AGENT, "env_local", "mcp_github") - - assert ( - sdk_plan.profiles == tuple(cli_plan["profiles"]) == ("env_local", "mcp_github") - ) - assert "profile" not in sdk_plan - assert "profile" not in cli_plan - sdk_mapping = sdk_plan.to_mapping() - assert sdk_mapping["config"] == cli_plan["config"] - assert ( - sdk_mapping["effective_config"]["config"] - == cli_plan["effective_config"]["config"] - ) - assert sdk_mapping["adapter_descriptor"] == cli_plan["adapter_descriptor"] - assert sdk_mapping["capabilities"] == cli_plan["capabilities"] - assert sdk_mapping["capability_plan"] == cli_plan["capability_plan"] - assert sdk_mapping["environment_plan"] == cli_plan["environment_plan"] - assert sdk_mapping["telemetry_plan"] == cli_plan["telemetry_plan"] - assert sdk_mapping["resolution"] == cli_plan["resolution"] - - async def test_typed_config(): client = Fabric() - sdk_and_cli_profile_stacks_match(client) - await resolves_and_diagnoses_without_a_directory(client) - await runs_without_an_agent_package(client) - - -def _load_yaml(path: Path) -> dict: - with path.open(encoding="utf-8") as stream: - return yaml.safe_load(stream) - - -def _cli_plan(agent: Path, *profiles: str) -> dict: - args = [*COMMAND, "plan", str(agent)] - for profile in profiles: - args.extend(["--profile", profile]) - completed = subprocess.run( - args, - cwd=ROOT, - text=True, - capture_output=True, - check=False, - ) - if completed.returncode != 0: - raise AssertionError(completed.stderr) - return json.loads(completed.stdout) + await resolves_and_diagnoses_typed_config(client) + await runs_with_typed_config_and_adapter_directory(client) diff --git a/uv.lock b/uv.lock index 9afbdcb8e..2273c97d6 100644 --- a/uv.lock +++ b/uv.lock @@ -1949,6 +1949,9 @@ wheels = [ name = "nemo-fabric" version = "0.1.0" source = { editable = "." } +dependencies = [ + { name = "nemo-fabric-runtime" }, +] [package.optional-dependencies] adapters-claude = [ @@ -2034,6 +2037,7 @@ requires-dist = [ { name = "nemo-fabric-adapters-deepagents", marker = "extra == 'deepagents'", editable = "adapters/deepagents" }, { name = "nemo-fabric-adapters-hermes", marker = "python_full_version < '3.14' and extra == 'adapters-hermes'", editable = "adapters/hermes" }, { name = "nemo-fabric-adapters-hermes", marker = "python_full_version < '3.14' and extra == 'hermes'", editable = "adapters/hermes" }, + { name = "nemo-fabric-runtime", editable = "python" }, { name = "nemo-fabric-runtime", marker = "extra == 'runtime'", editable = "python" }, { name = "nemo-relay", marker = "extra == 'relay'", specifier = ">=0.5.0,<0.7" }, { name = "pyyaml", marker = "extra == 'harbor'", specifier = ">=6.0" }, @@ -2987,7 +2991,7 @@ name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_full_version < '3.14'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [