cmdbox 0.6.0.4__py3-none-any.whl → 0.6.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cmdbox might be problematic. Click here for more details.
- cmdbox/app/app.py +2 -2
- cmdbox/app/auth/azure_signin.py +5 -1
- cmdbox/app/auth/signin.py +144 -28
- cmdbox/app/common.py +40 -3
- cmdbox/app/edge.py +1 -1
- cmdbox/app/edge_tool.py +1 -1
- cmdbox/app/features/cli/agent_base.py +1 -335
- cmdbox/app/features/cli/cmdbox_audit_search.py +0 -2
- cmdbox/app/features/cli/cmdbox_audit_write.py +9 -0
- cmdbox/app/features/cli/cmdbox_cmd_list.py +1 -1
- cmdbox/app/features/cli/cmdbox_cmd_load.py +1 -1
- cmdbox/app/features/cli/cmdbox_mcp_proxy.py +90 -0
- cmdbox/app/features/cli/cmdbox_web_gencert.py +25 -2
- cmdbox/app/features/cli/cmdbox_web_start.py +5 -2
- cmdbox/app/features/web/cmdbox_web_signin.py +1 -1
- cmdbox/app/mcp.py +375 -0
- cmdbox/app/options.py +2 -0
- cmdbox/app/web.py +34 -6
- cmdbox/autoload.py +10 -0
- cmdbox/extensions/user_list.yml +25 -1
- cmdbox/licenses/{LICENSE.Deprecated.1.2.18(MIT License).txt → LICENSE_PyJWT_2_10_1_MIT_License.txt} +2 -2
- cmdbox/licenses/LICENSE_exceptiongroup_1_3_0_MIT_License.txt +73 -0
- cmdbox/licenses/LICENSE_fastmcp_2_9_2_Apache_Software_License.txt +201 -0
- cmdbox/licenses/{LICENSE.graphviz.0.20.3(MIT License).txt → LICENSE_graphviz_0_21_UNKNOWN.txt} +1 -1
- cmdbox/licenses/LICENSE_jaraco_functools_4_2_1_UNKNOWN.txt +18 -0
- cmdbox/licenses/{LICENSE.numpy.2.2.5(BSD License).txt → LICENSE_numpy_2_3_1_BSD_License.txt} +8 -8
- cmdbox/licenses/LICENSE_openapi-pydantic_0_5_1_MIT_License.txt +40 -0
- cmdbox/licenses/LICENSE_propcache_0_3_2_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_proto-plus_1_26_1_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_shellingham_1_5_4_ISC_License-ISCL.txt +13 -0
- cmdbox/licenses/LICENSE_sphinx-last-updated-by-git_0_3_8_BSD_License.txt +22 -0
- cmdbox/licenses/LICENSE_tenacity_8_5_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_tokenizers_0_21_2_Apache_Software_License.txt +1 -0
- cmdbox/licenses/LICENSE_typer_0_16_0_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_typing-inspection_0_4_1_UNKNOWN.txt +21 -0
- cmdbox/licenses/LICENSE_yarl_1_20_1_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_zipp_3_23_0_UNKNOWN.txt +18 -0
- cmdbox/licenses/files.txt +176 -166
- cmdbox/logconf_mcp.yml +43 -0
- cmdbox/version.py +2 -2
- cmdbox/web/agent.html +1 -33
- cmdbox/web/assets/cmdbox/audit.js +1 -1
- cmdbox/web/assets/cmdbox/common.js +47 -4
- cmdbox/web/assets/cmdbox/svgicon.js +122 -0
- cmdbox/web/assets/cmdbox/users.js +4 -3
- cmdbox/web/audit.html +1 -35
- cmdbox/web/filer.html +1 -13
- cmdbox/web/gui.html +2 -50
- cmdbox/web/result.html +2 -46
- cmdbox/web/signin.html +30 -32
- cmdbox/web/users.html +1 -41
- {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.1.dist-info}/METADATA +31 -6
- cmdbox-0.6.1.1.dist-info/RECORD +383 -0
- cmdbox/licenses/LICENSE.keyring.25.6.0(MIT License).txt +0 -17
- cmdbox/licenses/LICENSE.typing-inspection.0.4.0(MIT License).txt +0 -21
- cmdbox/licenses/LICENSE.wrapt.1.17.2(BSD License).txt +0 -24
- cmdbox/licenses/LICENSE.zipp.3.21.0(MIT License).txt +0 -17
- cmdbox-0.6.0.4.dist-info/RECORD +0 -368
- /cmdbox/licenses/{LICENSE.Authlib.1.5.2(BSD License).txt → LICENSE_Authlib_1_6_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.Jinja2.3.1.6(BSD License).txt → LICENSE_Jinja2_3_1_6_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.MarkupSafe.3.0.2(BSD License).txt → LICENSE_MarkupSafe_3_0_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.PyYAML.6.0.2(MIT License).txt → LICENSE_PyYAML_6_0_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.Pygments.2.19.1(BSD License).txt → LICENSE_Pygments_2_19_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.SQLAlchemy.2.0.40(MIT License).txt → LICENSE_SQLAlchemy_2_0_41_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE.Sphinx.8.2.3(UNKNOWN).txt → LICENSE_Sphinx_8_2_3_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.aiohappyeyeballs.2.6.1(Python Software Foundation License).txt → LICENSE_aiohappyeyeballs_2_6_1_Python_Software_Foundation_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.aiohttp.3.11.18(Apache Software License).txt → LICENSE_aiohttp_3_12_13_Apache-2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.aiosignal.1.3.2(Apache Software License).txt → LICENSE_aiosignal_1_3_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.alabaster.1.0.0(BSD License).txt → LICENSE_alabaster_1_0_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.annotated-types.0.7.0(MIT License).txt → LICENSE_annotated-types_0_7_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.anyio.4.9.0(MIT License).txt → LICENSE_anyio_4_9_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.argcomplete.3.6.2(Apache Software License).txt → LICENSE_argcomplete_3_6_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.async-timeout.5.0.1(Apache Software License).txt → LICENSE_async-timeout_5_0_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.attrs.25.3.0(UNKNOWN).txt → LICENSE_attrs_25_3_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.babel.2.17.0(BSD License).txt → LICENSE_babel_2_17_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.backports.tarfile.1.2.0(MIT License).txt → LICENSE_backports_tarfile_1_2_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.cachetools.5.5.2(MIT License).txt → LICENSE_cachetools_5_5_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.certifi.2025.4.26(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE_certifi_2025_6_15_Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.cffi.1.17.1(MIT License).txt → LICENSE_cffi_1_17_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.charset-normalizer.3.4.2(MIT License).txt → LICENSE_charset-normalizer_3_4_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.click.8.2.0(UNKNOWN).txt → LICENSE_click_8_2_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.jiter.0.9.0(MIT License).txt → LICENSE_cloudpickle_3_1_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.colorama.0.4.6(BSD License).txt → LICENSE_colorama_0_4_6_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.cryptography.44.0.3(Apache Software License; BSD License).txt → LICENSE_cryptography_45_0_4_Apache-2_0_OR_BSD-3-Clause.txt} +0 -0
- /cmdbox/licenses/{LICENSE.distro.1.9.0(Apache Software License).txt → LICENSE_distro_1_9_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.docstring_parser.0.16(MIT License).txt → LICENSE_docstring_parser_0_16_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.docutils.0.21.2(BSD License; GNU General Public License (GPL); Public Domain; Python Software Foundation License).txt → LICENSE_docutils_0_21_2_BSD_License-GNU_General_Public_License-GPL-Public_Domain-Python_Software_Foundation_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.fastapi.0.115.12(MIT License).txt → LICENSE_fastapi_0_115_14_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.filelock.3.18.0(The Unlicense (Unlicense)).txt → LICENSE_filelock_3_18_0_The_Unlicense-Unlicense.txt} +0 -0
- /cmdbox/licenses/{LICENSE.frozenlist.1.6.0(Apache-2.0).txt → LICENSE_frozenlist_1_7_0_Apache-2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.fsspec.2025.3.2(BSD License).txt → LICENSE_fsspec_2025_5_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.gevent.25.4.2(MIT).txt → LICENSE_gevent_25_5_1_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-adk.0.5.0(Apache Software License).txt → LICENSE_google-adk_1_5_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-api-core.2.24.2(Apache Software License).txt → LICENSE_google-api-core_2_25_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-api-python-client.2.169.0(Apache Software License).txt → LICENSE_google-api-python-client_2_174_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-auth-httplib2.0.2.0(Apache Software License).txt → LICENSE_google-auth-httplib2_0_2_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-auth.2.40.1(Apache Software License).txt → LICENSE_google-auth_2_40_3_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-aiplatform.1.92.0(Apache 2.0).txt → LICENSE_google-cloud-aiplatform_1_100_0_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-bigquery.3.31.0(Apache Software License).txt → LICENSE_google-cloud-appengine-logging_1_6_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-core.2.4.3(Apache Software License).txt → LICENSE_google-cloud-audit-log_0_3_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-resource-manager.1.14.2(Apache Software License).txt → LICENSE_google-cloud-bigquery_3_34_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-secret-manager.2.23.3(Apache Software License).txt → LICENSE_google-cloud-core_2_4_3_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-speech.2.32.0(Apache Software License).txt → LICENSE_google-cloud-logging_3_12_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-storage.2.19.0(Apache Software License).txt → LICENSE_google-cloud-resource-manager_1_14_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-cloud-trace.1.16.1(Apache Software License).txt → LICENSE_google-cloud-secret-manager_2_24_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-crc32c.1.7.1(Apache 2.0).txt → LICENSE_google-cloud-speech_2_33_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-genai.1.14.0(Apache Software License).txt → LICENSE_google-cloud-storage_2_19_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.google-resumable-media.2.7.2(Apache Software License).txt → LICENSE_google-cloud-trace_1_16_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.googleapis-common-protos.1.70.0(Apache Software License).txt → LICENSE_google-crc32c_1_7_1_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.grpc-google-iam-v1.0.14.2(Apache Software License).txt → LICENSE_google-genai_1_23_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.id.1.5.0(Apache Software License).txt → LICENSE_google-resumable-media_2_7_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.importlib_metadata.8.6.1(Apache Software License).txt → LICENSE_googleapis-common-protos_1_70_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.greenlet.3.2.2(MIT AND Python-2.0).txt → LICENSE_greenlet_3_2_3_MIT_AND_Python-2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.propcache.0.3.1(Apache Software License).txt → LICENSE_grpc-google-iam-v1_0_14_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.grpcio-status.1.71.0(Apache Software License).txt → LICENSE_grpcio-status_1_73_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.grpcio.1.71.0(Apache Software License).txt → LICENSE_grpcio_1_73_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.gunicorn.23.0.0(MIT License).txt → LICENSE_gunicorn_23_0_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.h11.0.16.0(MIT License).txt → LICENSE_h11_0_16_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.httpcore.1.0.9(BSD License).txt → LICENSE_httpcore_1_0_9_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.httplib2.0.22.0(MIT License).txt → LICENSE_httplib2_0_22_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.httptools.0.6.4(MIT License).txt → LICENSE_httptools_0_6_4_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.httpx-sse.0.4.0(MIT).txt → LICENSE_httpx-sse_0_4_1_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE.httpx.0.28.1(BSD License).txt → LICENSE_httpx_0_28_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.huggingface-hub.0.31.1(Apache Software License).txt → LICENSE_huggingface-hub_0_33_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.proto-plus.1.26.1(Apache Software License).txt → LICENSE_id_1_5_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.idna.3.10(BSD License).txt → LICENSE_idna_3_10_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.imagesize.1.4.1(MIT License).txt → LICENSE_imagesize_1_4_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.yarl.1.20.0(Apache Software License).txt → LICENSE_importlib_metadata_8_7_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.itsdangerous.2.2.0(BSD License).txt → LICENSE_itsdangerous_2_2_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.jaraco.classes.3.4.0(MIT License).txt → LICENSE_jaraco_classes_3_4_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.jaraco.context.6.0.1(MIT License).txt → LICENSE_jaraco_context_6_0_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-applehelp.2.0.0(BSD License).txt → LICENSE_jiter_0_10_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.jsonschema-specifications.2025.4.1(UNKNOWN).txt → LICENSE_jsonschema-specifications_2025_4_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.jsonschema.4.23.0(MIT License).txt → LICENSE_jsonschema_4_24_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.jaraco.functools.4.1.0(MIT License).txt → LICENSE_keyring_25_6_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.litellm.1.69.0(MIT License).txt → LICENSE_litellm_1_73_6_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.markdown-it-py.3.0.0(MIT License).txt → LICENSE_markdown-it-py_3_0_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.mcp.1.8.0(MIT License).txt → LICENSE_mcp_1_9_4_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.mdurl.0.1.2(MIT License).txt → LICENSE_mdurl_0_1_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.more-itertools.10.7.0(MIT License).txt → LICENSE_more-itertools_10_7_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.multidict.6.4.3(Apache Software License).txt → LICENSE_multidict_6_6_2_Apache_License_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.nh3.0.2.21(MIT).txt → LICENSE_nh3_0_2_21_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE.openai.1.75.0(Apache Software License).txt → LICENSE_openai_1_93_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.opentelemetry-api.1.33.0(Apache Software License).txt → LICENSE_opentelemetry-api_1_34_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.opentelemetry-exporter-gcp-trace.1.9.0(Apache Software License).txt → LICENSE_opentelemetry-exporter-gcp-trace_1_9_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.opentelemetry-resourcedetector-gcp.1.9.0a0(Apache Software License).txt → LICENSE_opentelemetry-resourcedetector-gcp_1_9_0a0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.opentelemetry-sdk.1.33.0(Apache Software License).txt → LICENSE_opentelemetry-sdk_1_34_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.opentelemetry-semantic-conventions.0.54b0(Apache Software License).txt → LICENSE_opentelemetry-semantic-conventions_0_55b1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.packaging.25.0(Apache Software License; BSD License).txt → LICENSE_packaging_25_0_Apache_Software_License-BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pillow.11.2.1(UNKNOWN).txt → LICENSE_pillow_11_2_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pip.24.0(MIT License).txt → LICENSE_pip_24_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.plyer.2.1.0(MIT License).txt → LICENSE_plyer_2_1_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.prettytable.3.16.0(UNKNOWN).txt → LICENSE_prettytable_3_16_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.prompt_toolkit.3.0.51(BSD License).txt → LICENSE_prompt_toolkit_3_0_51_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.protobuf.5.29.4(3-Clause BSD License).txt → LICENSE_protobuf_6_31_1_3-Clause_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.psycopg-binary.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_psycopg-binary_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE.psycopg.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_psycopg_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pyasn1.0.6.1(BSD License).txt → LICENSE_pyasn1_0_6_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pyasn1_modules.0.4.2(BSD License).txt → LICENSE_pyasn1_modules_0_4_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pycparser.2.22(BSD License).txt → LICENSE_pycparser_2_22_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pycryptodome.3.22.0(BSD License; Public Domain).txt → LICENSE_pycryptodome_3_23_0_BSD_License-Public_Domain.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic-settings.2.9.1(MIT License).txt → LICENSE_pydantic-settings_2_10_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic.2.11.4(MIT License).txt → LICENSE_pydantic_2_11_7_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic_core.2.33.2(MIT License).txt → LICENSE_pydantic_core_2_33_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pyparsing.3.2.3(MIT License).txt → LICENSE_pyparsing_3_2_3_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pystray.0.19.5(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE_pystray_0_19_5_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-dateutil.2.9.0.post0(Apache Software License; BSD License).txt → LICENSE_python-dateutil_2_9_0_post0_Apache_Software_License-BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-dotenv.1.1.0(BSD License).txt → LICENSE_python-dotenv_1_1_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-multipart.0.0.20(Apache Software License).txt → LICENSE_python-multipart_0_0_20_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.pywin32-ctypes.0.2.3(BSD-3-Clause).txt → LICENSE_pywin32-ctypes_0_2_3_BSD-3-Clause.txt} +0 -0
- /cmdbox/licenses/{LICENSE.questionary.2.1.0(MIT License).txt → LICENSE_questionary_2_1_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.readme_renderer.44.0(Apache Software License).txt → LICENSE_readme_renderer_44_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.redis.6.0.0(MIT License).txt → LICENSE_redis_6_2_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.referencing.0.36.2(UNKNOWN).txt → LICENSE_referencing_0_36_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.regex.2024.11.6(Apache Software License).txt → LICENSE_regex_2024_11_6_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.requests-toolbelt.1.0.0(Apache Software License).txt → LICENSE_requests-toolbelt_1_0_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.requests.2.32.3(Apache Software License).txt → LICENSE_requests_2_32_4_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.rfc3986.2.0.0(Apache Software License).txt → LICENSE_rfc3986_2_0_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.rich.14.0.0(MIT License).txt → LICENSE_rich_14_0_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.roman-numerals-py.3.1.0(CC0 1.0 Universal (CC0 1.0) Public Domain Dedication; Zero-Clause BSD (0BSD)).txt → LICENSE_roman-numerals-py_3_1_0_CC0_1_0_Universal-CC0_1_0-Public_Domain_Dedication-Zero-Clause_BSD-0BSD.txt} +0 -0
- /cmdbox/licenses/{LICENSE.rpds-py.0.24.0(MIT).txt → LICENSE_rpds-py_0_25_1_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE.rsa.4.9.1(Apache Software License).txt → LICENSE_rsa_4_9_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.setuptools.65.5.0(MIT License).txt → LICENSE_setuptools_65_5_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.shapely.2.1.0(BSD License).txt → LICENSE_shapely_2_1_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.six.1.17.0(MIT License).txt → LICENSE_six_1_17_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sniffio.1.3.1(Apache Software License; MIT License).txt → LICENSE_sniffio_1_3_1_Apache_Software_License-MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.snowballstemmer.3.0.1(BSD License).txt → LICENSE_snowballstemmer_3_0_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinx-intl.2.3.1(BSD License).txt → LICENSE_sphinx-intl_2_3_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinx-rtd-theme.3.0.2(MIT License).txt → LICENSE_sphinx-rtd-theme_3_0_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinx-sitemap.2.6.0(MIT License).txt → LICENSE_sphinx-sitemap_2_7_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinx_fontawesome.0.0.6(GNU General Public License v2 (GPLv2)).txt → LICENSE_sphinx_fontawesome_0_0_6_GNU_General_Public_License_v2-GPLv2.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-devhelp.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-applehelp_2_0_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-htmlhelp.2.1.0(BSD License).txt → LICENSE_sphinxcontrib-devhelp_2_0_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-jquery.4.1(BSD License).txt → LICENSE_sphinxcontrib-htmlhelp_2_1_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-qthelp.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-jquery_4_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-jsmath.1.0.1(BSD License).txt → LICENSE_sphinxcontrib-jsmath_1_0_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinxcontrib-serializinghtml.2.0.0(BSD License).txt → LICENSE_sphinxcontrib-qthelp_2_0_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tokenizers.0.21.1(Apache Software License).txt → LICENSE_sphinxcontrib-serializinghtml_2_0_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.sse-starlette.2.3.4(BSD License).txt → LICENSE_sse-starlette_2_3_6_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.starlette.0.46.2(BSD License).txt → LICENSE_starlette_0_46_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tabulate.0.9.0(MIT License).txt → LICENSE_tabulate_0_9_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tiktoken.0.9.0(MIT License).txt → LICENSE_tiktoken_0_9_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_pers.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tomli.2.2.1(MIT License).txt → LICENSE_tomli_2_2_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tqdm.4.67.1(MIT License; Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE_tqdm_4_67_1_MIT_License-Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.twine.6.1.0(Apache Software License).txt → LICENSE_twine_6_1_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.typing_extensions.4.13.2(UNKNOWN).txt → LICENSE_typing_extensions_4_14_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tzdata.2025.2(Apache Software License).txt → LICENSE_tzdata_2025_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.tzlocal.5.3.1(MIT License).txt → LICENSE_tzlocal_5_3_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.uritemplate.4.1.1(Apache Software License; BSD License).txt → LICENSE_uritemplate_4_2_0_BSD_3-Clause_OR_Apache-2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE.urllib3.2.4.0(UNKNOWN).txt → LICENSE_urllib3_2_5_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE.uvicorn.0.34.2(BSD License).txt → LICENSE_uvicorn_0_35_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.watchfiles.1.0.5(MIT License).txt → LICENSE_watchfiles_1_1_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.wcwidth.0.2.13(MIT License).txt → LICENSE_wcwidth_0_2_13_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.websockets.15.0.1(BSD License).txt → LICENSE_websockets_15_0_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.wheel.0.45.1(MIT License).txt → LICENSE_wheel_0_45_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.zope.event.5.0(Zope Public License).txt → LICENSE_zope_event_5_1_Zope_Public_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE.zope.interface.7.2(Zope Public License).txt → LICENSE_zope_interface_7_2_Zope_Public_License.txt} +0 -0
- {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.1.dist-info}/LICENSE +0 -0
- {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.1.dist-info}/WHEEL +0 -0
- {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.1.dist-info}/entry_points.txt +0 -0
- {cmdbox-0.6.0.4.dist-info → cmdbox-0.6.1.1.dist-info}/top_level.txt +0 -0
cmdbox/app/mcp.py
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
from cmdbox.app import common, options
|
|
2
|
+
from cmdbox.app.options import Options
|
|
3
|
+
from cmdbox.app.auth import signin
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Callable, List, Dict, Any, Tuple
|
|
6
|
+
import argparse
|
|
7
|
+
import logging
|
|
8
|
+
import locale
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
import re
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Mcp:
|
|
16
|
+
default_host:str = os.environ.get('REDIS_HOST', 'localhost')
|
|
17
|
+
default_port:int = int(os.environ.get('REDIS_PORT', '6379'))
|
|
18
|
+
default_pass:str = os.environ.get('REDIS_PASSWORD', 'password')
|
|
19
|
+
default_svname:str = os.environ.get('SVNAME', 'server')
|
|
20
|
+
|
|
21
|
+
def __init__(self, logger:logging.Logger, data:Path, sign:signin.Signin, appcls=None, ver=None,):
|
|
22
|
+
"""
|
|
23
|
+
MCP (Multi-Channel Protocol) クラスの初期化
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
logger (logging.Logger): ロガー
|
|
27
|
+
data (Path): データのパス
|
|
28
|
+
sign (signin.Signin): サインインオブジェクト
|
|
29
|
+
appcls (type, optional): アプリケーションクラス. Defaults to None.
|
|
30
|
+
ver (module, optional): バージョンモジュール. Defaults to None.
|
|
31
|
+
"""
|
|
32
|
+
self.logger = logger
|
|
33
|
+
self.data = data
|
|
34
|
+
self.appcls = appcls
|
|
35
|
+
self.ver = ver
|
|
36
|
+
self.signin = sign
|
|
37
|
+
|
|
38
|
+
def create_mcpserver(self, args:argparse.Namespace) -> Any:
|
|
39
|
+
"""
|
|
40
|
+
mcpserverを作成します
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
args (argparse.Namespace): 引数
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Any: FastMCP
|
|
47
|
+
"""
|
|
48
|
+
from fastmcp import FastMCP
|
|
49
|
+
from fastmcp.server.auth import BearerAuthProvider
|
|
50
|
+
cls = self.signin.__class__
|
|
51
|
+
publickey_str = cls.verify_jwt_publickey_str if hasattr(cls, 'verify_jwt_publickey_str') else None
|
|
52
|
+
issuer = cls.verify_jwt_issuer if hasattr(cls, 'verify_jwt_issuer') else None
|
|
53
|
+
audience = cls.verify_jwt_audience if hasattr(cls, 'verify_jwt_audience') else None
|
|
54
|
+
if publickey_str is not None and issuer is not None and audience is not None:
|
|
55
|
+
self.logger.info(f"Using BearerAuthProvider with public key, issuer: {issuer}, audience: {audience}")
|
|
56
|
+
auth = BearerAuthProvider(
|
|
57
|
+
public_key=publickey_str,
|
|
58
|
+
issuer=issuer,
|
|
59
|
+
audience=audience
|
|
60
|
+
)
|
|
61
|
+
mcp = FastMCP(name=self.ver.__appid__, auth=auth)
|
|
62
|
+
else:
|
|
63
|
+
self.logger.info(f"Using BearerAuthProvider without public key, issuer, or audience.")
|
|
64
|
+
mcp = FastMCP(name=self.ver.__appid__)
|
|
65
|
+
return mcp
|
|
66
|
+
|
|
67
|
+
def create_session_service(self, args:argparse.Namespace) -> Any:
|
|
68
|
+
"""
|
|
69
|
+
セッションサービスを作成します
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
args (argparse.Namespace): 引数
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
BaseSessionService: セッションサービス
|
|
76
|
+
"""
|
|
77
|
+
from google.adk.events import Event
|
|
78
|
+
from google.adk.sessions import DatabaseSessionService, InMemorySessionService, session
|
|
79
|
+
from typing_extensions import override
|
|
80
|
+
if hasattr(args, 'agent_session_dburl') and args.agent_session_dburl is not None:
|
|
81
|
+
class _DatabaseSessionService(DatabaseSessionService):
|
|
82
|
+
@override
|
|
83
|
+
async def append_event(self, session: session.Session, event: Event) -> Event:
|
|
84
|
+
# 永続化されるセッションには <important> タグを含めない
|
|
85
|
+
bk_parts = event.content.parts.copy()
|
|
86
|
+
for part in event.content.parts:
|
|
87
|
+
if not part.text: continue
|
|
88
|
+
part.text = re.sub(r"<important>.*</important>", "", part.text)
|
|
89
|
+
for part in bk_parts:
|
|
90
|
+
if not part.text: continue
|
|
91
|
+
part.text = part.text.replace("<important>", "").replace("</important>", "")
|
|
92
|
+
ret = await super().append_event(session, event)
|
|
93
|
+
ret.content.parts = bk_parts
|
|
94
|
+
return ret
|
|
95
|
+
dss = _DatabaseSessionService(db_url=args.agent_session_dburl)
|
|
96
|
+
#dss.db_engine.echo = True
|
|
97
|
+
return dss
|
|
98
|
+
else:
|
|
99
|
+
return InMemorySessionService()
|
|
100
|
+
|
|
101
|
+
def create_agent(self, logger:logging.Logger, args:argparse.Namespace, tools:List[Callable]) -> Any:
|
|
102
|
+
"""
|
|
103
|
+
エージェントを作成します
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
logger (logging.Logger): ロガー
|
|
107
|
+
args (argparse.Namespace): 引数
|
|
108
|
+
tools (List[Callable]): 関数
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
Agent: エージェント
|
|
112
|
+
"""
|
|
113
|
+
if logger.level == logging.DEBUG:
|
|
114
|
+
logger.debug(f"create_agent processing..")
|
|
115
|
+
language, _ = locale.getlocale()
|
|
116
|
+
is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
|
|
117
|
+
description = f"{self.ver.__appid__}に登録されているコマンド提供"
|
|
118
|
+
instruction = f"あなたはコマンドの意味を熟知しているエキスパートです。" + \
|
|
119
|
+
f"ユーザーがコマンドを実行したいとき、あなたは以下の手順に従ってコマンドを確実に実行してください。\n" + \
|
|
120
|
+
f"1. ユーザーのクエリからが実行したいコマンドを特定します。\n" + \
|
|
121
|
+
f"2. コマンド実行に必要なパラメータのなかで、ユーザーのクエリから取得できないものは、コマンド定義にあるデフォルト値を指定して実行してください。\n" + \
|
|
122
|
+
f"3. もしエラーが発生した場合は、ユーザーにコマンド名とパラメータとエラー内容を提示してください。\n"
|
|
123
|
+
|
|
124
|
+
description = description if is_japan else \
|
|
125
|
+
f"Command offer registered in {self.ver.__appid__}."
|
|
126
|
+
instruction = instruction if is_japan else \
|
|
127
|
+
f"You are the expert who knows what the commands mean." + \
|
|
128
|
+
f"When a user wants to execute a command, you follow these steps to ensure that the command is executed.\n" + \
|
|
129
|
+
f"1. Identify the command you want to execute from the user's query.\n" + \
|
|
130
|
+
f"2. Any parameters required to execute the command that cannot be obtained from the user's query should be executed with the default values provided in the command definition.\n" + \
|
|
131
|
+
f"3. If an error occurs, provide the user with the command name, parameters, and error description.\n"
|
|
132
|
+
|
|
133
|
+
description = args.agent_description if args.agent_description else description
|
|
134
|
+
instruction = args.agent_instruction if args.agent_instruction else instruction
|
|
135
|
+
if logger.level == logging.DEBUG:
|
|
136
|
+
logger.debug(f"google-adk loading..")
|
|
137
|
+
from google.adk.agents import Agent
|
|
138
|
+
if logger.level == logging.DEBUG:
|
|
139
|
+
logger.debug(f"litellm loading..")
|
|
140
|
+
from google.adk.models.lite_llm import LiteLlm
|
|
141
|
+
# loggerの初期化
|
|
142
|
+
common.reset_logger("LiteLLM Proxy")
|
|
143
|
+
common.reset_logger("LiteLLM Router")
|
|
144
|
+
common.reset_logger("LiteLLM")
|
|
145
|
+
if args.llmprov == 'openai':
|
|
146
|
+
if args.llmmodel is None: raise ValueError("llmmodel is required.")
|
|
147
|
+
if args.llmapikey is None: raise ValueError("llmapikey is required.")
|
|
148
|
+
agent = Agent(
|
|
149
|
+
name=args.agent_name,
|
|
150
|
+
model=LiteLlm(
|
|
151
|
+
model=args.llmmodel,
|
|
152
|
+
api_key=args.llmapikey,
|
|
153
|
+
endpoint=args.llmendpoint,
|
|
154
|
+
),
|
|
155
|
+
description=description,
|
|
156
|
+
instruction=instruction,
|
|
157
|
+
tools=tools,
|
|
158
|
+
)
|
|
159
|
+
elif args.llmprov == 'azureopenai':
|
|
160
|
+
if args.llmmodel is None: raise ValueError("llmmodel is required.")
|
|
161
|
+
if args.llmendpoint is None: raise ValueError("llmendpoint is required.")
|
|
162
|
+
if args.llmapikey is None: raise ValueError("llmapikey is required.")
|
|
163
|
+
if args.llmapiversion is None: raise ValueError("llmapiversion is required.")
|
|
164
|
+
agent = Agent(
|
|
165
|
+
name=args.agent_name,
|
|
166
|
+
model=LiteLlm(
|
|
167
|
+
model=args.llmmodel,
|
|
168
|
+
api_key=args.llmapikey,
|
|
169
|
+
endpoint=args.llmendpoint,
|
|
170
|
+
api_version=args.llmapiversion,
|
|
171
|
+
),
|
|
172
|
+
description=description,
|
|
173
|
+
instruction=instruction,
|
|
174
|
+
tools=tools,
|
|
175
|
+
)
|
|
176
|
+
elif args.llmprov == 'vertexai':
|
|
177
|
+
if args.llmmodel is None: raise ValueError("llmmodel is required.")
|
|
178
|
+
if args.llmlocation is None: raise ValueError("llmlocation is required.")
|
|
179
|
+
if args.llmsvaccountfile is not None:
|
|
180
|
+
with open(args.llmsvaccountfile, "r", encoding="utf-8") as f:
|
|
181
|
+
vertex_credentials = json.load(f)
|
|
182
|
+
elif args.llmprojectid is None: raise ValueError("llmprojectid is required.")
|
|
183
|
+
agent = Agent(
|
|
184
|
+
name=args.agent_name,
|
|
185
|
+
model=LiteLlm(
|
|
186
|
+
model=args.llmmodel,
|
|
187
|
+
#vertex_project=args.llmprojectid,
|
|
188
|
+
vertex_credentials=vertex_credentials,
|
|
189
|
+
vertex_location=args.llmlocation,
|
|
190
|
+
#seed=args.llmseed,
|
|
191
|
+
#temperature=args.llmtemperature,
|
|
192
|
+
),
|
|
193
|
+
description=description,
|
|
194
|
+
instruction=instruction,
|
|
195
|
+
tools=tools,
|
|
196
|
+
)
|
|
197
|
+
elif args.llmprov == 'ollama':
|
|
198
|
+
if args.llmmodel is None: raise ValueError("llmmodel is required.")
|
|
199
|
+
if args.llmendpoint is None: raise ValueError("llmendpoint is required.")
|
|
200
|
+
agent = Agent(
|
|
201
|
+
name=args.agent_name,
|
|
202
|
+
model=LiteLlm(
|
|
203
|
+
model=f"ollama/{args.llmmodel}",
|
|
204
|
+
api_base=args.llmendpoint,
|
|
205
|
+
temperature=args.llmtemperature,
|
|
206
|
+
stream=True
|
|
207
|
+
),
|
|
208
|
+
description=description,
|
|
209
|
+
instruction=instruction,
|
|
210
|
+
tools=tools,
|
|
211
|
+
)
|
|
212
|
+
else:
|
|
213
|
+
raise ValueError("llmprov is required.")
|
|
214
|
+
if logger.level == logging.DEBUG:
|
|
215
|
+
logger.debug(f"create_agent complate.")
|
|
216
|
+
return agent
|
|
217
|
+
|
|
218
|
+
def create_runner(self, logger:logging.Logger, args:argparse.Namespace, session_service, agent) -> Any:
|
|
219
|
+
"""
|
|
220
|
+
ランナーを作成します
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
logger (logging.Logger): ロガー
|
|
224
|
+
args (argparse.Namespace): 引数
|
|
225
|
+
session_service (BaseSessionService): セッションサービス
|
|
226
|
+
agent (Agent): エージェント
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Runner: ランナー
|
|
230
|
+
"""
|
|
231
|
+
from google.adk.runners import Runner
|
|
232
|
+
return Runner(
|
|
233
|
+
app_name=self.ver.__appid__,
|
|
234
|
+
agent=agent,
|
|
235
|
+
session_service=session_service,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
def init_agent_runner(self, logger:logging.Logger, args:argparse.Namespace) -> Tuple[Any, Any]:
|
|
239
|
+
"""
|
|
240
|
+
エージェントの初期化を行います
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
logger (logging.Logger): ロガー
|
|
244
|
+
args (argparse.Namespace): 引数
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Tuple[Any, Any]: ランナーとFastMCP
|
|
248
|
+
"""
|
|
249
|
+
if logger.level == logging.DEBUG:
|
|
250
|
+
logger.debug(f"init_agent_runner processing..")
|
|
251
|
+
# loggerの初期化
|
|
252
|
+
common.reset_logger("httpx")
|
|
253
|
+
common.reset_logger("google_adk.google.adk.sessions.database_session_service")
|
|
254
|
+
common.reset_logger("mcp.server.streamable_http_manager")
|
|
255
|
+
# モジュールインポート
|
|
256
|
+
from fastmcp import FastMCP
|
|
257
|
+
from google.adk.sessions import BaseSessionService
|
|
258
|
+
mcp:FastMCP = self.create_mcpserver(args)
|
|
259
|
+
session_service:BaseSessionService = self.create_session_service(args)
|
|
260
|
+
options = Options.getInstance()
|
|
261
|
+
tools:Callable[[logging.Logger, argparse.Namespace, float, Dict], Tuple[int, Dict[str, Any], Any]] = []
|
|
262
|
+
|
|
263
|
+
def _ds(d:str) -> str:
|
|
264
|
+
return f'"{d}"' if d is not None else 'None'
|
|
265
|
+
def _t2s(o:Dict[str, Any], req=True) -> str:
|
|
266
|
+
t, m, d, r = o["type"], o["multi"], o["default"], o["required"]
|
|
267
|
+
if t == Options.T_BOOL: return ("List[bool]=[]" if m else f"bool={d}") if req else ("List[bool]" if m else f"bool")
|
|
268
|
+
if t == Options.T_DATE: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
|
|
269
|
+
if t == Options.T_DATETIME: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
|
|
270
|
+
if t == Options.T_DICT: return ("List[dict]=[]" if m else f"dict={d}") if req else ("List[dict]" if m else f"dict")
|
|
271
|
+
if t == Options.T_DIR or t == Options.T_FILE:
|
|
272
|
+
if d is not None: d = str(d).replace('\\', '/')
|
|
273
|
+
return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
|
|
274
|
+
if t == Options.T_FLOAT: return ("List[float]=[]" if m else f"float={d}") if req else ("List[float]" if m else f"float")
|
|
275
|
+
if t == Options.T_INT: return ("List[int]=[]" if m else f"int={d}") if req else ("List[int]" if m else f"int")
|
|
276
|
+
if t == Options.T_STR: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
|
|
277
|
+
if t == Options.T_TEXT: return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
|
|
278
|
+
raise ValueError(f"Unknown type: {t} for option {o['opt']}")
|
|
279
|
+
def _arg(o:Dict[str, Any], is_japan) -> str:
|
|
280
|
+
t, d = o["type"], o["default"]
|
|
281
|
+
s = f' {o["opt"]}:'
|
|
282
|
+
if t == Options.T_DIR or t == Options.T_FILE:
|
|
283
|
+
d = str(d).replace("\\", "/")
|
|
284
|
+
s += f'{_t2s(o, False)}={d}:'
|
|
285
|
+
#s += f'Optional[{_t2s(o, False)}]={d}:'
|
|
286
|
+
s += f'{o["discription_ja"] if is_japan else o["discription_en"]}'
|
|
287
|
+
return s
|
|
288
|
+
def _coercion(a:argparse.Namespace, key:str, dval) -> str:
|
|
289
|
+
dval = f'opt["{key}"] if "{key}" in opt else ' + f'"{dval}"' if isinstance(dval, str) else dval
|
|
290
|
+
aval = args.__dict__[key] if hasattr(args, key) and args.__dict__[key] else None
|
|
291
|
+
aval = f'"{aval}"' if isinstance(aval, str) else aval
|
|
292
|
+
ret = f'opt["{key}"] = {aval}' if aval is not None else f'opt["{key}"] = {dval}'
|
|
293
|
+
return ret
|
|
294
|
+
language, _ = locale.getlocale()
|
|
295
|
+
is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
|
|
296
|
+
for mode in options.get_mode_keys():
|
|
297
|
+
for cmd in options.get_cmd_keys(mode):
|
|
298
|
+
if not options.get_cmd_attr(mode, cmd, 'use_agent'):
|
|
299
|
+
continue
|
|
300
|
+
discription = options.get_cmd_attr(mode, cmd, 'discription_ja' if is_japan else 'discription_en')
|
|
301
|
+
choices = options.get_cmd_choices(mode, cmd, False)
|
|
302
|
+
if len([opt for opt in choices if 'opt' in opt and opt['opt'] == 'signin_file']) <= 0:
|
|
303
|
+
choices.append(dict(opt="signin_file", type=Options.T_FILE, default=f'.{self.ver.__appid__}/user_list.yml', required=True, multi=False, hide=True, choice=None,
|
|
304
|
+
discription_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
|
|
305
|
+
discription_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),)
|
|
306
|
+
fn = f"{mode}_{cmd}"
|
|
307
|
+
func_txt = f'def {fn}(' + ", ".join([f'{o["opt"]}:{_t2s(o, False)}' for o in choices]) + '):\n'
|
|
308
|
+
func_txt += f' """\n'
|
|
309
|
+
func_txt += f' {discription}\n'
|
|
310
|
+
func_txt += f' Args:\n'
|
|
311
|
+
func_txt += "\n".join([_arg(o, is_japan) for o in choices])
|
|
312
|
+
func_txt += f'\n'
|
|
313
|
+
func_txt += f' Returns:\n'
|
|
314
|
+
func_txt += f' Dict[str, Any]:{"処理結果" if is_japan else "Processing Result"}\n'
|
|
315
|
+
func_txt += f' """\n'
|
|
316
|
+
func_txt += f' scope = signin.get_request_scope()\n'
|
|
317
|
+
func_txt += f' logger = common.default_logger()\n'
|
|
318
|
+
func_txt += f' opt = dict()\n'
|
|
319
|
+
func_txt += f' opt["mode"] = "{mode}"\n'
|
|
320
|
+
func_txt += f' opt["cmd"] = "{cmd}"\n'
|
|
321
|
+
func_txt += f' opt["data"] = opt["data"] if hasattr(opt, "data") else common.HOME_DIR / ".{self.ver.__appid__}"\n'
|
|
322
|
+
func_txt += f' opt["format"] = False\n'
|
|
323
|
+
func_txt += f' opt["output_json"] = None\n'
|
|
324
|
+
func_txt += f' opt["output_json_append"] = False\n'
|
|
325
|
+
func_txt += f' opt["debug"] = logger.level == logging.DEBUG\n'
|
|
326
|
+
func_txt += '\n'.join([f' opt["{o["opt"]}"] = {o["opt"]}' for o in choices])+'\n'
|
|
327
|
+
func_txt += f' {_coercion(args, "host", self.default_host)}\n'
|
|
328
|
+
func_txt += f' {_coercion(args, "port", self.default_port)}\n'
|
|
329
|
+
func_txt += f' {_coercion(args, "password", self.default_pass)}\n'
|
|
330
|
+
func_txt += f' {_coercion(args, "svname", self.default_svname)}\n'
|
|
331
|
+
func_txt += f' {_coercion(args, "retry_count", 3)}\n'
|
|
332
|
+
func_txt += f' {_coercion(args, "retry_interval", 3)}\n'
|
|
333
|
+
func_txt += f' {_coercion(args, "timeout", 15)}\n'
|
|
334
|
+
func_txt += f' {_coercion(args, "output_json", None)}\n'
|
|
335
|
+
func_txt += f' {_coercion(args, "output_json_append", False)}\n'
|
|
336
|
+
func_txt += f' {_coercion(args, "stdout_log", False)}\n'
|
|
337
|
+
func_txt += f' {_coercion(args, "capture_stdout", False)}\n'
|
|
338
|
+
func_txt += f' {_coercion(args, "capture_maxsize", 1024*1024)}\n'
|
|
339
|
+
func_txt += f' {_coercion(args, "tag", None)}\n'
|
|
340
|
+
func_txt += f' {_coercion(args, "clmsg_id", None)}\n'
|
|
341
|
+
func_txt += f' opt["signin_file"] = signin_file if signin_file else ".{self.ver.__appid__}/user_list.yml"\n'
|
|
342
|
+
func_txt += f' args = argparse.Namespace(**opt)\n'
|
|
343
|
+
func_txt += f' signin_data = signin.Signin.load_signin_file(args.signin_file)\n'
|
|
344
|
+
func_txt += f' req = scope["req"] if scope["req"] is not None else scope["websocket"]\n'
|
|
345
|
+
func_txt += f' sign = signin.Signin._check_signin(req, scope["res"], signin_data, logger)\n'
|
|
346
|
+
func_txt += f' if sign is not None:\n'
|
|
347
|
+
func_txt += f' logger.warning("Unable to execute command because authentication information cannot be obtained")\n'
|
|
348
|
+
func_txt += f' return dict(warn="Unable to execute command because authentication information cannot be obtained")\n'
|
|
349
|
+
func_txt += f' groups = req.session["signin"]["groups"]\n'
|
|
350
|
+
func_txt += f' logger.info("Call agent tool `{mode}_{cmd}`:user="+str(req.session["signin"]["name"])+" groups="+str(groups)+" args="+str(args))\n'
|
|
351
|
+
func_txt += f' if not signin.Signin._check_cmd(signin_data, groups, "{mode}", "{cmd}", logger):\n'
|
|
352
|
+
func_txt += f' logger.warning("You do not have permission to execute this command.")\n'
|
|
353
|
+
func_txt += f' return dict(warn="You do not have permission to execute this command.")\n'
|
|
354
|
+
func_txt += f' feat = Options.getInstance().get_cmd_attr("{mode}", "{cmd}", "feature")\n'
|
|
355
|
+
func_txt += f' try:\n'
|
|
356
|
+
func_txt += f' st, ret, _ = feat.apprun(logger, args, time.perf_counter(), [])\n'
|
|
357
|
+
func_txt += f' return ret\n'
|
|
358
|
+
func_txt += f' except Exception as e:\n'
|
|
359
|
+
func_txt += f' logger.error("Error occurs when tool is executed:", exc_info=True)\n'
|
|
360
|
+
func_txt += f' raise e\n'
|
|
361
|
+
func_txt += f'tools.append({fn})\n'
|
|
362
|
+
if logger.level == logging.DEBUG:
|
|
363
|
+
logger.debug(f"generating agent tool: {fn}")
|
|
364
|
+
|
|
365
|
+
exec(func_txt,
|
|
366
|
+
dict(time=time,List=List, argparse=argparse, common=common, Options=Options, logging=logging, signin=signin,),
|
|
367
|
+
dict(tools=tools, mcp=mcp))
|
|
368
|
+
exec(f"@mcp.tool\n{func_txt}",
|
|
369
|
+
dict(time=time,List=List, argparse=argparse, common=common, Options=Options, logging=logging, signin=signin,),
|
|
370
|
+
dict(tools=[], mcp=mcp))
|
|
371
|
+
root_agent = self.create_agent(logger, args, tools)
|
|
372
|
+
runner = self.create_runner(logger, args, session_service, root_agent)
|
|
373
|
+
if logger.level == logging.DEBUG:
|
|
374
|
+
logger.debug(f"init_agent_runner complate.")
|
|
375
|
+
return runner, mcp
|
cmdbox/app/options.py
CHANGED
|
@@ -832,11 +832,13 @@ class Options:
|
|
|
832
832
|
if hasattr(arg, 'redis_password'): opt['password'] = arg.redis_password
|
|
833
833
|
if hasattr(arg, 'svname'): opt['svname'] = arg.svname
|
|
834
834
|
if hasattr(arg, 'clmsg_id'): opt['clmsg_id'] = arg.clmsg_id
|
|
835
|
+
if hasattr(arg, 'client_only'): opt['client_only'] = arg.client_only
|
|
835
836
|
elif isinstance(arg, web.Web):
|
|
836
837
|
opt['host'] = arg.redis_host
|
|
837
838
|
opt['port'] = arg.redis_port
|
|
838
839
|
opt['password'] = arg.redis_password
|
|
839
840
|
opt['svname'] = arg.svname
|
|
841
|
+
opt['client_only'] = arg.client_only
|
|
840
842
|
elif isinstance(arg, feature.Feature):
|
|
841
843
|
func_feature = arg
|
|
842
844
|
opt['clmsg_src'] = func_feature.__class__.__name__
|
cmdbox/app/web.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from cmdbox.app import common, options
|
|
2
|
-
from cmdbox.app.auth import signin, signin_saml
|
|
3
2
|
from cmdbox.app.commons import module
|
|
4
3
|
from fastapi import FastAPI, Request, Response
|
|
5
4
|
from pathlib import Path
|
|
@@ -12,6 +11,7 @@ import copy
|
|
|
12
11
|
import ctypes
|
|
13
12
|
import datetime
|
|
14
13
|
import gevent
|
|
14
|
+
import jwt
|
|
15
15
|
import logging
|
|
16
16
|
import multiprocessing
|
|
17
17
|
import os
|
|
@@ -120,7 +120,8 @@ class Web:
|
|
|
120
120
|
self.cb_queue = queue.Queue(1000)
|
|
121
121
|
self.options = options.Options.getInstance()
|
|
122
122
|
self.webcap_client = requests.Session()
|
|
123
|
-
|
|
123
|
+
from cmdbox.app.auth import signin, signin_saml
|
|
124
|
+
signin_file_data = signin.Signin.load_signin_file(self.signin_file, self=self)
|
|
124
125
|
self.signin = signin.Signin(self.logger, self.signin_file, signin_file_data, self.appcls, self.ver)
|
|
125
126
|
self.signin_saml = signin_saml.SigninSAML(self.logger, self.signin_file, signin_file_data, self.appcls, self.ver)
|
|
126
127
|
|
|
@@ -247,7 +248,25 @@ class Web:
|
|
|
247
248
|
for u in copy.deepcopy(signin_data['users']):
|
|
248
249
|
u['password'] = '********'
|
|
249
250
|
if 'apikeys' in u:
|
|
250
|
-
|
|
251
|
+
for an, ak in u['apikeys'].items():
|
|
252
|
+
exp = '-'
|
|
253
|
+
try:
|
|
254
|
+
cls = self.signin.__class__
|
|
255
|
+
publickey = None
|
|
256
|
+
if cls.verify_jwt_certificate is not None:
|
|
257
|
+
publickey = cls.verify_jwt_certificate.public_key()
|
|
258
|
+
if publickey is None and cls.verify_jwt_publickey is not None:
|
|
259
|
+
publickey = cls.verify_jwt_publickey
|
|
260
|
+
t = jwt.decode(ak, publickey, algorithms=[cls.verify_jwt_algorithm],
|
|
261
|
+
issuer=cls.verify_jwt_issuer, audience=cls.verify_jwt_audience,
|
|
262
|
+
options={'verify_iss': cls.verify_jwt_issuer is not None,
|
|
263
|
+
'verify_aud': cls.verify_jwt_audience is not None})
|
|
264
|
+
exp = datetime.datetime.fromtimestamp(t['exp']).strftime('%Y-%m-%d %H:%M:%S')
|
|
265
|
+
u['apikeys'][an] = (ak, exp, '-')
|
|
266
|
+
except jwt.exceptions.InvalidTokenError as e:
|
|
267
|
+
u['apikeys'][an] = (ak, '-', str(e))
|
|
268
|
+
except Exception as e:
|
|
269
|
+
u['apikeys'][an] = (ak, '-', '-')
|
|
251
270
|
if u['name'] == name:
|
|
252
271
|
return [u]
|
|
253
272
|
signin_last = self.user_data(None, u['uid'], u['name'], 'signin', 'last_update')
|
|
@@ -289,10 +308,19 @@ class Web:
|
|
|
289
308
|
if user['apikey_name'] in u['apikeys']:
|
|
290
309
|
raise ValueError(f"ApiKey name is already exists. ({user})")
|
|
291
310
|
apikey = common.random_string(64)
|
|
292
|
-
u['apikeys'][user['apikey_name']] =
|
|
311
|
+
u['apikeys'][user['apikey_name']] = apikey
|
|
312
|
+
if signin_data['apikey']['gen_jwt']['enabled']:
|
|
313
|
+
cls = self.signin.__class__
|
|
314
|
+
claims = cls.gen_jwt_claims.copy() if cls.gen_jwt_claims is not None else dict()
|
|
315
|
+
claims['exp'] = int(time.time()) + int(claims.get('exp', 3600))
|
|
316
|
+
claims['uid'] = u['uid']
|
|
317
|
+
claims['name'] = u['name']
|
|
318
|
+
claims['groups'] = u['groups']
|
|
319
|
+
claims['email'] = u['email']
|
|
320
|
+
claims['apikey_name'] = user['apikey_name']
|
|
321
|
+
apikey = jwt.encode(claims, cls.gen_jwt_privatekey, algorithm=cls.gen_jwt_algorithm)
|
|
322
|
+
u['apikeys'][user['apikey_name']] = apikey
|
|
293
323
|
|
|
294
|
-
if self.signin_file is None:
|
|
295
|
-
raise ValueError(f"signin_file is None.")
|
|
296
324
|
if self.logger.level == logging.DEBUG:
|
|
297
325
|
self.logger.debug(f"apikey_add: {user} -> {self.signin_file}")
|
|
298
326
|
common.save_yml(self.signin_file, signin_data)
|
cmdbox/autoload.py
ADDED
cmdbox/extensions/user_list.yml
CHANGED
|
@@ -74,7 +74,7 @@ pathrule: # List of RESTAPI rules, rules that determine whe
|
|
|
74
74
|
- groups: [user]
|
|
75
75
|
paths: [/signin, /assets, /bbforce_cmd, /copyright, /dosignin, /dosignout, /password/change,
|
|
76
76
|
/gui/user_data/load, /gui/user_data/save, /gui/user_data/delete,
|
|
77
|
-
/agent, /
|
|
77
|
+
/agent, /mcpsv,
|
|
78
78
|
/exec_cmd, /exec_pipe, /filer, /result, /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]
|
|
79
79
|
rule: allow
|
|
80
80
|
- groups: [readonly]
|
|
@@ -102,6 +102,30 @@ password: # Password settings.
|
|
|
102
102
|
enabled: true # Specify whether or not to enable account lockout.
|
|
103
103
|
threshold: 5 # Specify the number of failed login attempts before the account is locked.
|
|
104
104
|
reset: 30 # Specify the number of minutes after which the failed login count will be reset.
|
|
105
|
+
apikey:
|
|
106
|
+
gen_cert: # Specify whether to generate a certificate for API key.
|
|
107
|
+
enabled: true # Specify whether to enable certificate generation for API key.
|
|
108
|
+
privatekey: idp_private.pem # Specify the destination file for the generated private key.
|
|
109
|
+
certificate: idp_cert.pem # Specify the destination file for the generated certificate.
|
|
110
|
+
publickey: idp_public.pem # Specify the destination file for the generated public key.
|
|
111
|
+
gen_jwt: # Specify whether to generate JWT for API key.
|
|
112
|
+
enabled: true # Specify whether to enable JWT generation for API key.
|
|
113
|
+
privatekey: idp_private.pem # Specify the private key file for JWT generation.
|
|
114
|
+
privatekey_passphrase: # Specify the passphrase for the private key file.
|
|
115
|
+
# If the private key is encrypted, specify the passphrase here.
|
|
116
|
+
algorithm: RS256 # Specify the algorithm used to generate the JWT. The value can be RS256, PS256, or ES256.
|
|
117
|
+
claims: # Specify the claims to be included in the JWT.
|
|
118
|
+
iss: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider.
|
|
119
|
+
sub: app_user # Specify the subject of the JWT. This is usually the name of the application.
|
|
120
|
+
aud: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application.
|
|
121
|
+
exp: 31536000 # Specify the expiration time of the JWT in seconds. The default is 31536000 seconds (1 year).
|
|
122
|
+
verify_jwt: # Specify whether to verify JWT for API key.
|
|
123
|
+
enabled: true # Specify whether to enable JWT verification for API key.
|
|
124
|
+
certificate: idp_cert.pem # Specify the certificate file for JWT verification.
|
|
125
|
+
publickey: idp_public.pem # Specify the public key file for JWT verification. Not required if certificate exists.
|
|
126
|
+
issuer: identity_provider # Specify the issuer of the JWT. This is usually the name of the identity provider. (If not specified, no verification)
|
|
127
|
+
audience: app_organization # Specify the audience of the JWT. This is usually the name of the organization that will use the application. (If not specified, no verification)
|
|
128
|
+
algorithm: RS256 # Specify the algorithm used to verify the JWT. The value can be RS256, PS256, or ES256.
|
|
105
129
|
oauth2: # OAuth2 settings.
|
|
106
130
|
providers: # This is a per-provider setting for OAuth2.
|
|
107
131
|
google: # Google's OAuth2 configuration.
|
cmdbox/licenses/{LICENSE.Deprecated.1.2.18(MIT License).txt → LICENSE_PyJWT_2_10_1_MIT_License.txt}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2015-2022 José Padilla
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Alex Grönholm
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
This project contains code copied from the Python standard library.
|
|
24
|
+
The following is the required license notice for those parts.
|
|
25
|
+
|
|
26
|
+
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
|
27
|
+
--------------------------------------------
|
|
28
|
+
|
|
29
|
+
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
|
30
|
+
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
|
31
|
+
otherwise using this software ("Python") in source or binary form and
|
|
32
|
+
its associated documentation.
|
|
33
|
+
|
|
34
|
+
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
|
35
|
+
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
|
36
|
+
analyze, test, perform and/or display publicly, prepare derivative works,
|
|
37
|
+
distribute, and otherwise use Python alone or in any derivative version,
|
|
38
|
+
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
|
39
|
+
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
|
40
|
+
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Python Software Foundation;
|
|
41
|
+
All Rights Reserved" are retained in Python alone or in any derivative version
|
|
42
|
+
prepared by Licensee.
|
|
43
|
+
|
|
44
|
+
3. In the event Licensee prepares a derivative work that is based on
|
|
45
|
+
or incorporates Python or any part thereof, and wants to make
|
|
46
|
+
the derivative work available to others as provided herein, then
|
|
47
|
+
Licensee hereby agrees to include in any such work a brief summary of
|
|
48
|
+
the changes made to Python.
|
|
49
|
+
|
|
50
|
+
4. PSF is making Python available to Licensee on an "AS IS"
|
|
51
|
+
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
|
52
|
+
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
|
53
|
+
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
54
|
+
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
|
55
|
+
INFRINGE ANY THIRD PARTY RIGHTS.
|
|
56
|
+
|
|
57
|
+
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
|
58
|
+
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
|
59
|
+
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
|
60
|
+
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
|
61
|
+
|
|
62
|
+
6. This License Agreement will automatically terminate upon a material
|
|
63
|
+
breach of its terms and conditions.
|
|
64
|
+
|
|
65
|
+
7. Nothing in this License Agreement shall be deemed to create any
|
|
66
|
+
relationship of agency, partnership, or joint venture between PSF and
|
|
67
|
+
Licensee. This License Agreement does not grant permission to use PSF
|
|
68
|
+
trademarks or trade name in a trademark sense to endorse or promote
|
|
69
|
+
products or services of Licensee, or any third party.
|
|
70
|
+
|
|
71
|
+
8. By copying, installing or otherwise using Python, Licensee
|
|
72
|
+
agrees to be bound by the terms and conditions of this License
|
|
73
|
+
Agreement.
|