cmdbox 0.5.3.1__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cmdbox might be problematic. Click here for more details.

Files changed (188) hide show
  1. cmdbox/app/auth/__init__.py +0 -0
  2. cmdbox/app/auth/azure_signin.py +38 -0
  3. cmdbox/app/auth/azure_signin_saml.py +12 -0
  4. cmdbox/app/auth/github_signin.py +38 -0
  5. cmdbox/app/auth/google_signin.py +32 -0
  6. cmdbox/app/auth/signin.py +490 -287
  7. cmdbox/app/auth/signin_saml.py +61 -0
  8. cmdbox/app/common.py +48 -3
  9. cmdbox/app/edge.py +182 -213
  10. cmdbox/app/edge_tool.py +177 -0
  11. cmdbox/app/feature.py +10 -10
  12. cmdbox/app/features/cli/agent_base.py +477 -0
  13. cmdbox/app/features/cli/audit_base.py +1 -1
  14. cmdbox/app/features/cli/cmdbox_audit_search.py +24 -1
  15. cmdbox/app/features/cli/cmdbox_client_file_download.py +1 -1
  16. cmdbox/app/features/cli/cmdbox_cmd_list.py +105 -0
  17. cmdbox/app/features/cli/cmdbox_cmd_load.py +104 -0
  18. cmdbox/app/features/cli/cmdbox_edge_config.py +21 -7
  19. cmdbox/app/features/cli/cmdbox_edge_start.py +1 -1
  20. cmdbox/app/features/cli/cmdbox_gui_start.py +9 -132
  21. cmdbox/app/features/cli/cmdbox_gui_stop.py +4 -21
  22. cmdbox/app/features/cli/cmdbox_server_start.py +1 -1
  23. cmdbox/app/features/cli/cmdbox_web_apikey_add.py +1 -1
  24. cmdbox/app/features/cli/cmdbox_web_apikey_del.py +1 -1
  25. cmdbox/app/features/cli/cmdbox_web_genpass.py +0 -3
  26. cmdbox/app/features/cli/cmdbox_web_group_add.py +1 -1
  27. cmdbox/app/features/cli/cmdbox_web_group_del.py +1 -1
  28. cmdbox/app/features/cli/cmdbox_web_group_edit.py +1 -1
  29. cmdbox/app/features/cli/cmdbox_web_group_list.py +1 -1
  30. cmdbox/app/features/cli/cmdbox_web_start.py +119 -104
  31. cmdbox/app/features/cli/cmdbox_web_stop.py +1 -1
  32. cmdbox/app/features/cli/cmdbox_web_user_add.py +4 -4
  33. cmdbox/app/features/cli/cmdbox_web_user_del.py +1 -1
  34. cmdbox/app/features/cli/cmdbox_web_user_edit.py +4 -4
  35. cmdbox/app/features/cli/cmdbox_web_user_list.py +1 -1
  36. cmdbox/app/features/web/cmdbox_web_agent.py +250 -0
  37. cmdbox/app/features/web/cmdbox_web_do_signin.py +79 -103
  38. cmdbox/app/features/web/cmdbox_web_exec_cmd.py +8 -3
  39. cmdbox/app/features/web/cmdbox_web_signin.py +26 -4
  40. cmdbox/app/features/web/cmdbox_web_users.py +2 -0
  41. cmdbox/app/options.py +55 -2
  42. cmdbox/app/web.py +155 -27
  43. cmdbox/extensions/features.yml +18 -0
  44. cmdbox/extensions/sample_project/sample/app/features/cli/__init__.py +0 -0
  45. cmdbox/extensions/sample_project/sample/app/features/web/__init__.py +0 -0
  46. cmdbox/extensions/sample_project/sample/extensions/features.yml +23 -0
  47. cmdbox/extensions/sample_project/sample/extensions/user_list.yml +40 -6
  48. cmdbox/extensions/user_list.yml +37 -6
  49. cmdbox/licenses/{LICENSE.starlette.0.41.3(BSD License).txt → LICENSE.Authlib.1.5.2(BSD License).txt } +3 -1
  50. cmdbox/licenses/{LICENSE.pydantic_core.2.33.0(MIT License).txt → LICENSE.Deprecated.1.2.18(MIT License).txt } +2 -2
  51. cmdbox/licenses/{LICENSE.more-itertools.10.6.0(MIT License).txt → LICENSE.SQLAlchemy.2.0.40(MIT License).txt } +1 -1
  52. cmdbox/licenses/LICENSE.aiohttp.3.11.18(Apache Software License).txt +13 -0
  53. cmdbox/licenses/LICENSE.aiosignal.1.3.2(Apache Software License).txt +201 -0
  54. cmdbox/licenses/LICENSE.async-timeout.5.0.1(Apache Software License).txt +13 -0
  55. cmdbox/licenses/{LICENSE.watchfiles.1.0.0(MIT License).txt → LICENSE.attrs.25.3.0(UNKNOWN).txt} +1 -1
  56. cmdbox/licenses/{LICENSE.anyio.4.6.2.post1(MIT License).txt → LICENSE.cachetools.5.5.2(MIT License).txt } +1 -1
  57. cmdbox/licenses/LICENSE.distro.1.9.0(Apache Software License).txt +202 -0
  58. cmdbox/licenses/{LICENSE.pydantic_core.2.33.1(MIT License).txt → LICENSE.docstring_parser.0.16(MIT License).txt } +1 -1
  59. cmdbox/licenses/LICENSE.filelock.3.18.0(The Unlicense (Unlicense)).txt +24 -0
  60. cmdbox/licenses/LICENSE.frozenlist.1.6.0(Apache-2.0).txt +201 -0
  61. cmdbox/licenses/{LICENSE.starlette.0.46.1(BSD License).txt → LICENSE.fsspec.2025.3.2(BSD License).txt } +3 -1
  62. cmdbox/licenses/{LICENSE.argcomplete.3.6.1(Apache Software License).txt → LICENSE.google-adk.0.5.0(Apache Software License).txt } +25 -0
  63. cmdbox/licenses/LICENSE.google-api-python-client.2.169.0(Apache Software License).txt +201 -0
  64. cmdbox/licenses/LICENSE.google-auth-httplib2.0.2.0(Apache Software License).txt +201 -0
  65. cmdbox/licenses/LICENSE.google-auth.2.40.1(Apache Software License).txt +201 -0
  66. cmdbox/licenses/LICENSE.google-cloud-aiplatform.1.92.0(Apache 2.0).txt +202 -0
  67. cmdbox/licenses/LICENSE.google-cloud-bigquery.3.31.0(Apache Software License).txt +202 -0
  68. cmdbox/licenses/LICENSE.google-cloud-core.2.4.3(Apache Software License).txt +202 -0
  69. cmdbox/licenses/LICENSE.google-cloud-resource-manager.1.14.2(Apache Software License).txt +202 -0
  70. cmdbox/licenses/LICENSE.google-cloud-secret-manager.2.23.3(Apache Software License).txt +202 -0
  71. cmdbox/licenses/LICENSE.google-cloud-speech.2.32.0(Apache Software License).txt +202 -0
  72. cmdbox/licenses/LICENSE.google-cloud-storage.2.19.0(Apache Software License).txt +202 -0
  73. cmdbox/licenses/LICENSE.google-cloud-trace.1.16.1(Apache Software License).txt +202 -0
  74. cmdbox/licenses/LICENSE.google-crc32c.1.7.1(Apache 2.0).txt +202 -0
  75. cmdbox/licenses/LICENSE.google-genai.1.14.0(Apache Software License).txt +202 -0
  76. cmdbox/licenses/LICENSE.google-resumable-media.2.7.2(Apache Software License).txt +202 -0
  77. cmdbox/licenses/LICENSE.googleapis-common-protos.1.70.0(Apache Software License).txt +202 -0
  78. cmdbox/licenses/{LICENSE.fastapi.0.115.5(MIT License).txt → LICENSE.graphviz.0.20.3(MIT License).txt } +1 -1
  79. cmdbox/licenses/LICENSE.grpc-google-iam-v1.0.14.2(Apache Software License).txt +202 -0
  80. cmdbox/licenses/LICENSE.grpcio-status.1.71.0(Apache Software License).txt +610 -0
  81. cmdbox/licenses/LICENSE.grpcio.1.71.0(Apache Software License).txt +610 -0
  82. cmdbox/licenses/{LICENSE.uvicorn.0.34.0(BSD License).txt → LICENSE.httpcore.1.0.9(BSD License).txt } +1 -1
  83. cmdbox/licenses/LICENSE.httplib2.0.22.0(MIT License).txt +23 -0
  84. cmdbox/licenses/{LICENSE.tomli.2.1.0(MIT License).txt → LICENSE.httpx-sse.0.4.0(MIT).txt} +1 -1
  85. cmdbox/licenses/LICENSE.httpx.0.28.1(BSD License).txt +12 -0
  86. cmdbox/licenses/LICENSE.huggingface-hub.0.31.1(Apache Software License).txt +201 -0
  87. cmdbox/licenses/{LICENSE.charset-normalizer.3.4.0(MIT License).txt → LICENSE.jsonschema-specifications.2025.4.1(UNKNOWN).txt} +5 -7
  88. cmdbox/licenses/LICENSE.jsonschema.4.23.0(MIT License).txt +19 -0
  89. cmdbox/licenses/{LICENSE.pkginfo.1.10.0(MIT License).txt → LICENSE.litellm.1.69.0(MIT License).txt } +6 -1
  90. cmdbox/licenses/{LICENSE.redis.5.2.1(MIT License).txt → LICENSE.mcp.1.8.0(MIT License).txt } +1 -1
  91. cmdbox/licenses/LICENSE.multidict.6.4.3(Apache Software License).txt +13 -0
  92. cmdbox/licenses/{LICENSE.argcomplete.3.5.1(Apache Software License).txt → LICENSE.openai.1.75.0(Apache Software License).txt } +25 -1
  93. cmdbox/licenses/LICENSE.opentelemetry-api.1.33.0(Apache Software License).txt +201 -0
  94. cmdbox/licenses/LICENSE.opentelemetry-exporter-gcp-trace.1.9.0(Apache Software License).txt +201 -0
  95. cmdbox/licenses/LICENSE.opentelemetry-resourcedetector-gcp.1.9.0a0(Apache Software License).txt +201 -0
  96. cmdbox/licenses/LICENSE.opentelemetry-sdk.1.33.0(Apache Software License).txt +201 -0
  97. cmdbox/licenses/LICENSE.opentelemetry-semantic-conventions.0.54b0(Apache Software License).txt +201 -0
  98. cmdbox/licenses/LICENSE.propcache.0.3.1(Apache Software License).txt +202 -0
  99. cmdbox/licenses/LICENSE.proto-plus.1.26.1(Apache Software License).txt +202 -0
  100. cmdbox/licenses/{LICENSE.Pygments.2.18.0(BSD License).txt → LICENSE.protobuf.5.29.4(3-Clause BSD License).txt } +15 -8
  101. cmdbox/licenses/LICENSE.pyasn1.0.6.1(BSD License).txt +24 -0
  102. cmdbox/licenses/LICENSE.pyasn1_modules.0.4.2(BSD License).txt +24 -0
  103. cmdbox/licenses/LICENSE.pydantic-settings.2.9.1(MIT License).txt +21 -0
  104. cmdbox/licenses/{LICENSE.gevent.25.4.1(MIT).txt → LICENSE.pyparsing.3.2.3(MIT License).txt } +5 -12
  105. cmdbox/licenses/LICENSE.python-dateutil.2.9.0.post0(Apache Software License; BSD License).txt +54 -0
  106. cmdbox/licenses/LICENSE.referencing.0.36.2(UNKNOWN).txt +19 -0
  107. cmdbox/licenses/LICENSE.regex.2024.11.6(Apache Software License).txt +208 -0
  108. cmdbox/licenses/LICENSE.rpds-py.0.24.0(MIT).txt +19 -0
  109. cmdbox/licenses/{LICENSE.python-multipart.0.0.17(Apache Software License).txt → LICENSE.rsa.4.9.1(Apache Software License).txt } +1 -2
  110. cmdbox/licenses/{LICENSE.sphinx-intl.2.3.0(BSD License).txt → LICENSE.shapely.2.1.0(BSD License).txt } +6 -2
  111. cmdbox/licenses/LICENSE.sse-starlette.2.3.4(BSD License).txt +27 -0
  112. cmdbox/licenses/LICENSE.tiktoken.0.9.0(MIT License).txt +21 -0
  113. cmdbox/licenses/LICENSE.tokenizers.0.21.1(Apache Software License).txt +1 -0
  114. cmdbox/licenses/{LICENSE.six.1.16.0(MIT License).txt → LICENSE.tqdm.4.67.1(MIT License; Mozilla Public License 2.0 (MPL 2.0)).txt } +32 -1
  115. cmdbox/licenses/{LICENSE.rich.13.9.4(MIT License).txt → LICENSE.tzlocal.5.3.1(MIT License).txt } +3 -3
  116. cmdbox/licenses/LICENSE.uritemplate.4.1.1(Apache Software License; BSD License).txt +3 -0
  117. cmdbox/licenses/LICENSE.wrapt.1.17.2(BSD License).txt +24 -0
  118. cmdbox/licenses/LICENSE.yarl.1.20.0(Apache Software License).txt +202 -0
  119. cmdbox/licenses/files.txt +111 -17
  120. cmdbox/logconf_agent.yml +38 -0
  121. cmdbox/logconf_audit.yml +13 -5
  122. cmdbox/logconf_client.yml +13 -5
  123. cmdbox/logconf_cmdbox.yml +13 -5
  124. cmdbox/logconf_edge.yml +13 -5
  125. cmdbox/logconf_gui.yml +13 -5
  126. cmdbox/logconf_server.yml +13 -5
  127. cmdbox/logconf_web.yml +13 -5
  128. cmdbox/version.py +3 -2
  129. cmdbox/web/agent.html +263 -0
  130. cmdbox/web/assets/cmdbox/agent.js +335 -0
  131. cmdbox/web/assets/cmdbox/common.js +1111 -1020
  132. cmdbox/web/assets/cmdbox/signin.js +16 -3
  133. cmdbox/web/assets/cmdbox/users.js +1 -1
  134. cmdbox/web/assets/filer/filer.js +4 -2
  135. cmdbox/web/signin.html +10 -6
  136. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/METADATA +132 -35
  137. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/RECORD +161 -123
  138. cmdbox/app/features/web/cmdbox_web_load_pin.py +0 -43
  139. cmdbox/app/features/web/cmdbox_web_save_pin.py +0 -42
  140. cmdbox/licenses/LICENSE.Jinja2.3.1.4(BSD License).txt +0 -28
  141. cmdbox/licenses/LICENSE.Sphinx.8.1.3(BSD License).txt +0 -31
  142. cmdbox/licenses/LICENSE.babel.2.16.0(BSD License).txt +0 -27
  143. cmdbox/licenses/LICENSE.certifi.2025.1.31(Mozilla Public License 2.0 (MPL 2.0)).txt +0 -20
  144. cmdbox/licenses/LICENSE.click.8.1.8(BSD License).txt +0 -28
  145. cmdbox/licenses/LICENSE.cryptography.44.0.2(Apache Software License; BSD License).txt +0 -3
  146. cmdbox/licenses/LICENSE.greenlet.3.2.0(MIT AND Python-2.0).txt +0 -30
  147. cmdbox/licenses/LICENSE.keyring.25.5.0(MIT License).txt +0 -17
  148. cmdbox/licenses/LICENSE.numpy.2.2.4(BSD License).txt +0 -950
  149. cmdbox/licenses/LICENSE.pillow.11.0.0(CMU License (MIT-CMU)).txt +0 -1226
  150. cmdbox/licenses/LICENSE.pillow.11.1.0(CMU License (MIT-CMU)).txt +0 -1213
  151. cmdbox/licenses/LICENSE.prettytable.3.12.0(BSD License).txt +0 -30
  152. cmdbox/licenses/LICENSE.prompt_toolkit.3.0.50(BSD License).txt +0 -27
  153. cmdbox/licenses/LICENSE.psycopg.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +0 -165
  154. cmdbox/licenses/LICENSE.pydantic.2.11.1(MIT License).txt +0 -21
  155. cmdbox/licenses/LICENSE.pydantic.2.11.3(MIT License).txt +0 -21
  156. cmdbox/licenses/LICENSE.python-dotenv.1.0.1(BSD License).txt +0 -27
  157. cmdbox/licenses/LICENSE.twine.5.1.1(Apache Software License).txt +0 -174
  158. cmdbox/licenses/LICENSE.typing_extensions.4.13.0(UNKNOWN).txt +0 -279
  159. cmdbox/licenses/LICENSE.urllib3.2.2.3(MIT License).txt +0 -21
  160. cmdbox/licenses/LICENSE.urllib3.2.3.0(MIT License).txt +0 -21
  161. cmdbox/licenses/LICENSE.uvicorn.0.34.1(BSD License).txt +0 -27
  162. cmdbox/licenses/LICENSE.watchfiles.1.0.4(MIT License).txt +0 -21
  163. cmdbox/licenses/LICENSE.websockets.14.1(BSD License).txt +0 -24
  164. cmdbox/licenses/LICENSE.zope.interface.7.1.1(Zope Public License).txt +0 -44
  165. /cmdbox/licenses/{LICENSE.typing_extensions.4.12.2(Python Software Foundation License).txt → LICENSE.aiohappyeyeballs.2.6.1(Python Software Foundation License).txt} +0 -0
  166. /cmdbox/licenses/{LICENSE.certifi.2024.8.30(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE.certifi.2025.4.26(Mozilla Public License 2.0 (MPL 2.0)).txt} +0 -0
  167. /cmdbox/licenses/{LICENSE.charset-normalizer.3.4.1(MIT License).txt → LICENSE.charset-normalizer.3.4.2(MIT License).txt} +0 -0
  168. /cmdbox/licenses/{LICENSE.click.8.1.7(BSD License).txt → LICENSE.click.8.2.0(UNKNOWN).txt} +0 -0
  169. /cmdbox/licenses/{LICENSE.cryptography.43.0.3(Apache Software License; BSD License).txt → LICENSE.cryptography.44.0.3(Apache Software License; BSD License).txt} +0 -0
  170. /cmdbox/licenses/{LICENSE.gevent.24.11.1(MIT License).txt → LICENSE.gevent.25.4.2(MIT).txt} +0 -0
  171. /cmdbox/licenses/{LICENSE.importlib_metadata.8.5.0(Apache Software License).txt → LICENSE.google-api-core.2.24.2(Apache Software License).txt} +0 -0
  172. /cmdbox/licenses/{LICENSE.greenlet.3.1.1(MIT License).txt → LICENSE.greenlet.3.2.2(MIT AND Python-2.0).txt} +0 -0
  173. /cmdbox/licenses/{LICENSE.h11.0.14.0(MIT License).txt → LICENSE.h11.0.16.0(MIT License).txt} +0 -0
  174. /cmdbox/licenses/{LICENSE.nh3.0.2.18(MIT).txt → LICENSE.jiter.0.9.0(MIT License).txt} +0 -0
  175. /cmdbox/licenses/{LICENSE.more-itertools.10.5.0(MIT License).txt → LICENSE.more-itertools.10.7.0(MIT License).txt} +0 -0
  176. /cmdbox/licenses/{LICENSE.numpy.2.1.3(BSD License).txt → LICENSE.numpy.2.2.5(BSD License).txt} +0 -0
  177. /cmdbox/licenses/{LICENSE.packaging.24.2(Apache Software License; BSD License).txt → LICENSE.packaging.25.0(Apache Software License; BSD License).txt} +0 -0
  178. /cmdbox/licenses/{LICENSE.psycopg-binary.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE.psycopg-binary.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt} +0 -0
  179. /cmdbox/licenses/{LICENSE.psycopg-pool.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE.psycopg.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt} +0 -0
  180. /cmdbox/licenses/{LICENSE.pydantic.2.10.2(MIT License).txt → LICENSE.pydantic.2.11.4(MIT License).txt} +0 -0
  181. /cmdbox/licenses/{LICENSE.pydantic_core.2.27.1(MIT License).txt → LICENSE.pydantic_core.2.33.2(MIT License).txt} +0 -0
  182. /cmdbox/licenses/{LICENSE.redis.5.2.0(MIT License).txt → LICENSE.redis.6.0.0(MIT License).txt} +0 -0
  183. /cmdbox/licenses/{LICENSE.snowballstemmer.2.2.0(BSD License).txt → LICENSE.snowballstemmer.3.0.1(BSD License).txt} +0 -0
  184. /cmdbox/licenses/{LICENSE.uvicorn.0.32.1(BSD License).txt → LICENSE.uvicorn.0.34.2(BSD License).txt} +0 -0
  185. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/LICENSE +0 -0
  186. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/WHEEL +0 -0
  187. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/entry_points.txt +0 -0
  188. {cmdbox-0.5.3.1.dist-info → cmdbox-0.6.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,477 @@
1
+ from cmdbox.app import common, feature
2
+ from cmdbox.app.auth import signin
3
+ from cmdbox.app.features.cli import cmdbox_cmd_list
4
+ from cmdbox.app.options import Options
5
+ from pathlib import Path
6
+ from typing import Any, Callable, Dict, Tuple, List
7
+ import argparse
8
+ import asyncio
9
+ import locale
10
+ import logging
11
+ import json
12
+ import re
13
+ import time
14
+
15
+
16
+ class AgentBase(feature.ResultEdgeFeature):
17
+
18
+ def get_option(self):
19
+ """
20
+ この機能のオプションを返します
21
+
22
+ Returns:
23
+ Dict[str, Any]: オプション
24
+ """
25
+ return dict(
26
+ use_redis=self.USE_REDIS_FALSE, nouse_webmode=False, use_agent=True,
27
+ discription_ja="-",
28
+ discription_en="-",
29
+ choice=[
30
+ dict(opt="agent", type=Options.T_STR, default="no", required=False, multi=False, hide=False, choice=["no", "use"],
31
+ discription_ja="エージェントを使用するかどうかを指定します。",
32
+ discription_en="Specifies whether the agent is used.",
33
+ choice_show=dict(use=["agent_name", "agent_description", "agent_instruction", "agent_session_store", "llmprov"],)),
34
+ dict(opt="agent_name", type=Options.T_STR, default=self.ver.__appid__, required=False, multi=False, hide=False, choice=None,
35
+ discription_ja="エージェント名を指定します。",
36
+ discription_en="Specifies the agent name."),
37
+ dict(opt="agent_description", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
38
+ discription_ja="エージェントの説明を指定します。",
39
+ discription_en="Specify agent description."),
40
+ dict(opt="agent_instruction", type=Options.T_TEXT, default=None, required=False, multi=False, hide=False, choice=None,
41
+ discription_ja="エージェントのシステム指示を指定します。",
42
+ discription_en="Specifies the agent's system instructions."),
43
+ dict(opt="agent_session_store", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=['memory', 'sqlite', 'postgresql'],
44
+ discription_ja="エージェントのセッションを保存する方法を指定します。",
45
+ discription_en="Specify how the agent's session is to be saved.",
46
+ choice_show=dict(postgresql=["pg_host", "pg_port", "pg_user", "pg_password", "pg_dbname"]),),
47
+ dict(opt="mcp_listen_port", type=Options.T_INT, default="9081", required=False, multi=False, hide=False, choice=None,
48
+ discription_ja="省略した時は `9081` を使用します。",
49
+ discription_en="If omitted, `9081` is used."),
50
+ dict(opt="mcp_ssl_listen_port", type=Options.T_INT, default="9443", required=False, multi=False, hide=False, choice=None,
51
+ discription_ja="省略した時は `9443` を使用します。",
52
+ discription_en="If omitted, `9443` is used."),
53
+ dict(opt="pg_host", type=Options.T_STR, default='localhost', required=False, multi=False, hide=True, choice=None, web="mask",
54
+ discription_ja="postgresqlホストを指定する。",
55
+ discription_en="Specify the postgresql host."),
56
+ dict(opt="pg_port", type=Options.T_INT, default=5432, required=False, multi=False, hide=True, choice=None, web="mask",
57
+ discription_ja="postgresqlのポートを指定する。",
58
+ discription_en="Specify the postgresql port."),
59
+ dict(opt="pg_user", type=Options.T_STR, default='postgres', required=False, multi=False, hide=True, choice=None, web="mask",
60
+ discription_ja="postgresqlのユーザー名を指定する。",
61
+ discription_en="Specify the postgresql user name."),
62
+ dict(opt="pg_password", type=Options.T_STR, default='postgres', required=False, multi=False, hide=True, choice=None, web="mask",
63
+ discription_ja="postgresqlのパスワードを指定する。",
64
+ discription_en="Specify the postgresql password."),
65
+ dict(opt="pg_dbname", type=Options.T_STR, default='agent', required=False, multi=False, hide=True, choice=None,
66
+ discription_ja="postgresqlデータベース名を指定します。",
67
+ discription_en="Specify the postgresql database name."),
68
+ dict(opt="llmprov", type=Options.T_STR, default=None, required=False, multi=False, hide=False,
69
+ choice=["", "azureopenai", "openai", "vertexai", "ollama"],
70
+ discription_ja="llmのプロバイダを指定します。",
71
+ discription_en="Specify llm provider.",
72
+ choice_show=dict(azureopenai=["llmapikey", "llmendpoint", "llmmodel", "llmapiversion"],
73
+ openai=["llmapikey", "llmendpoint", "llmmodel"],
74
+ vertexai=["llmprojectid", "llmsvaccountfile", "llmlocation", "llmmodel", "llmseed", "llmtemperature"],
75
+ ollama=["llmendpoint", "llmmodel", "llmtemperature"],),
76
+ ),
77
+ dict(opt="llmprojectid", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
78
+ discription_ja="llmのプロバイダ接続のためのプロジェクトIDを指定します。",
79
+ discription_en="Specify the project ID for llm's provider connection."),
80
+ dict(opt="llmsvaccountfile", type=Options.T_FILE, default=None, required=False, multi=False, hide=False, choice=None,
81
+ discription_ja="llmのプロバイダ接続のためのサービスアカウントファイルを指定します。",
82
+ discription_en="Specifies the service account file for llm's provider connection."),
83
+ dict(opt="llmlocation", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
84
+ discription_ja="llmのプロバイダ接続のためのロケーションを指定します。",
85
+ discription_en="Specifies the location for llm provider connections."),
86
+ dict(opt="llmapikey", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
87
+ discription_ja="llmのプロバイダ接続のためのAPIキーを指定します。",
88
+ discription_en="Specify API key for llm provider connection."),
89
+ dict(opt="llmapiversion", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
90
+ discription_ja="llmのプロバイダ接続のためのAPIバージョンを指定します。",
91
+ discription_en="Specifies the API version for llm provider connections."),
92
+ dict(opt="llmendpoint", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
93
+ discription_ja="llmのプロバイダ接続のためのエンドポイントを指定します。",
94
+ discription_en="Specifies the endpoint for llm provider connections."),
95
+ dict(opt="llmmodel", type=Options.T_STR, default="text-multilingual-embedding-002", required=False, multi=False, hide=False, choice=None,
96
+ discription_ja="llmモデルを指定します。",
97
+ discription_en="Specifies the llm model."),
98
+ dict(opt="llmseed", type=Options.T_INT, default=13, required=False, multi=False, hide=False, choice=None,
99
+ discription_ja="llmモデルを使用するときのシード値を指定します。",
100
+ discription_en="Specifies the seed value when using llm model."),
101
+ dict(opt="llmtemperature", type=Options.T_FLOAT, default=0.1, required=False, multi=False, hide=False, choice=None,
102
+ discription_ja="llmのモデルを使用するときのtemperatureを指定します。",
103
+ discription_en="Specifies the temperature when using llm model."),
104
+ ])
105
+
106
+ def create_mcpserver(self, args:argparse.Namespace) -> Any:
107
+ """
108
+ mcpserverを作成します
109
+
110
+ Args:
111
+ args (argparse.Namespace): 引数
112
+
113
+ Returns:
114
+ Any: FastMCP
115
+ """
116
+ from mcp.server.fastmcp import FastMCP
117
+ mcp = FastMCP(name=self.ver.__appid__)
118
+ return mcp
119
+
120
+ def create_session_service(self, args:argparse.Namespace) -> Any:
121
+ """
122
+ セッションサービスを作成します
123
+
124
+ Args:
125
+ args (argparse.Namespace): 引数
126
+
127
+ Returns:
128
+ BaseSessionService: セッションサービス
129
+ """
130
+ from google.adk.events import Event
131
+ from google.adk.sessions import DatabaseSessionService, InMemorySessionService, session
132
+ from typing_extensions import override
133
+ if hasattr(args, 'agent_session_dburl') and args.agent_session_dburl is not None:
134
+ class _DatabaseSessionService(DatabaseSessionService):
135
+ @override
136
+ async def append_event(self, session: session.Session, event: Event) -> Event:
137
+ # 永続化されるセッションには <important> タグを含めない
138
+ bk_parts = event.content.parts.copy()
139
+ for part in event.content.parts:
140
+ if not part.text: continue
141
+ part.text = re.sub(r"<important>.*</important>", "", part.text)
142
+ for part in bk_parts:
143
+ if not part.text: continue
144
+ part.text = part.text.replace("<important>", "").replace("</important>", "")
145
+ ret = await super().append_event(session, event)
146
+ ret.content.parts = bk_parts
147
+ return ret
148
+ dss = _DatabaseSessionService(db_url=args.agent_session_dburl)
149
+ #dss.db_engine.echo = True
150
+ return dss
151
+ else:
152
+ return InMemorySessionService()
153
+
154
+ def create_agent(self, logger:logging.Logger, args:argparse.Namespace, tools:List[Callable]) -> Any:
155
+ """
156
+ エージェントを作成します
157
+
158
+ Args:
159
+ logger (logging.Logger): ロガー
160
+ args (argparse.Namespace): 引数
161
+ tools (List[Callable]): 関数
162
+
163
+ Returns:
164
+ Agent: エージェント
165
+ """
166
+ if logger.level == logging.DEBUG:
167
+ logger.debug(f"create_agent processing..")
168
+ language, _ = locale.getlocale()
169
+ is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
170
+ description = f"{self.ver.__appid__}に登録されているコマンド提供"
171
+ instruction = f"あなたはコマンドの意味を熟知しているエキスパートです。" + \
172
+ f"ユーザーがコマンドを実行したいとき、あなたは以下の手順に従ってコマンドを確実に実行してください。\n" + \
173
+ f"1. ユーザーのクエリからが実行したいコマンドを特定します。\n" + \
174
+ f"2. コマンド実行に必要なパラメータのなかで、ユーザーのクエリから取得できないものは、コマンド定義にあるデフォルト値を指定して実行してください。\n" + \
175
+ f"3. もしエラーが発生した場合は、ユーザーにコマンド名とパラメータとエラー内容を提示してください。\n"
176
+ """
177
+ f"2. コマンド実行に必要なパラメータを特定します。\n" + \
178
+ f"3. ユーザーのクエリから指定しているパラメータを取得します。\n" + \
179
+ f"4. ユーザーが指定しているパラメータと、コマンド実行に必要なパラメータを比較し、不足しているパラメータを取得します。\n" + \
180
+ f"5. 以下に「パラメータ = デフォルト値」を示しているので、不足しているパラメータはデフォルト値を使用します。\n" + \
181
+ f" 但しコマンドが実行に必要のないパラメータは指定しないようにしてください。\n" + \
182
+ f" host = {args.host if hasattr(args, 'host') and args.host else self.default_host}\n" + \
183
+ f" port = {args.port if hasattr(args, 'port') and args.port else self.default_port}\n" + \
184
+ f" password = {args.password if hasattr(args, 'password') and args.password else self.default_pass}\n" + \
185
+ f" svname = {args.svname if hasattr(args, 'svname') and args.svname else self.default_svname}\n" + \
186
+ f" data = {args.data if hasattr(args, 'data') and args.data else self.default_data}\n" + \
187
+ f" retry_count = {args.retry_count if hasattr(args, 'retry_count') and args.retry_count else 3}\n" + \
188
+ f" retry_interval = {args.retry_interval if hasattr(args, 'retry_interval') and args.retry_interval else 3}\n" + \
189
+ f" timeout = {args.timeout if hasattr(args, 'timeout') and args.timeout else 15}\n" + \
190
+ f" output_json = {args.output_json if hasattr(args, 'output_json') and args.output_json else None}\n" + \
191
+ f" output_json_append = {args.output_json_append if hasattr(args, 'output_json_append') and args.output_json_append else False}\n" + \
192
+ f" stdout_log = {args.stdout_log if hasattr(args, 'stdout_log') and args.stdout_log else False}\n" + \
193
+ f" capture_stdout = {args.capture_stdout if hasattr(args, 'capture_stdout') and args.capture_stdout else False}\n" + \
194
+ f" capture_maxsize = {args.capture_maxsize if hasattr(args, 'capture_maxsize') and args.capture_maxsize else 100}\n" + \
195
+ f" tag = {args.tag if hasattr(args, 'tag') and args.tag else None}\n" + \
196
+ f" clmsg_id = {args.clmsg_id if hasattr(args, 'clmsg_id') and args.clmsg_id else None}\n" + \
197
+ f" signin_file = {args.signin_file if hasattr(args, 'signin_file') and args.signin_file else f'.{self.ver.__appid__}/user_list.yml'}\n" + \
198
+ f"6. 以上のパラメータを使用しても不足するパラメータは、Noneを使用します。\n" + \
199
+ f"7. 以上のパラメータを使用してコマンドを実行して、コマンドの結果はJSONでユーザーに提示してください。\n" + \
200
+ f"8. もし予期しないパラメータを受け取ったという旨のエラーが発生した場合は、そのパラメータを指定せずに再実行してください。\n" + \
201
+ f"9. もしエラーが発生した場合は、ユーザーにコマンド名とパラメータとエラー内容を提示してください。\n"
202
+ """
203
+
204
+ description = description if is_japan else \
205
+ f"Command offer registered in {self.ver.__appid__}."
206
+ instruction = instruction if is_japan else \
207
+ f"You are the expert who knows what the commands mean." + \
208
+ f"When a user wants to execute a command, you follow these steps to ensure that the command is executed.\n" + \
209
+ f"1. Identify the command you want to execute from the user's query.\n" + \
210
+ 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" + \
211
+ f"3. If an error occurs, provide the user with the command name, parameters, and error description.\n"
212
+ """
213
+ f"2. Identify the parameters required to execute the command.\n" + \
214
+ f"3. Retrieve the specified parameters from the user's query.\n" + \
215
+ f"4. It compares the parameters specified by the user with those required to execute the command and obtains the missing parameters.\n" + \
216
+ f"5. The “Parameter = Default Value” is shown below, so use default values for missing parameters.\n" + \
217
+ f" However, do not specify parameters that the command does not require for execution.\n" + \
218
+ f" host = {args.host if hasattr(args, 'host') and args.host else self.default_host}\n" + \
219
+ f" port = {args.port if hasattr(args, 'port') and args.port else self.default_port}\n" + \
220
+ f" password = {args.password if hasattr(args, 'password') and args.password else self.default_pass}\n" + \
221
+ f" svname = {args.svname if hasattr(args, 'svname') and args.svname else self.default_svname}\n" + \
222
+ f" data = {args.data if hasattr(args, 'data') and args.data else self.default_data}\n" + \
223
+ f" retry_count = {args.retry_count if hasattr(args, 'retry_count') and args.retry_count else 3}\n" + \
224
+ f" retry_interval = {args.retry_interval if hasattr(args, 'retry_interval') and args.retry_interval else 3}\n" + \
225
+ f" timeout = {args.timeout if hasattr(args, 'timeout') and args.timeout else 15}\n" + \
226
+ f" output_json = {args.output_json if hasattr(args, 'output_json') and args.output_json else None}\n" + \
227
+ f" output_json_append = {args.output_json_append if hasattr(args, 'output_json_append') and args.output_json_append else False}\n" + \
228
+ f" stdout_log = {args.stdout_log if hasattr(args, 'stdout_log') and args.stdout_log else False}\n" + \
229
+ f" capture_stdout = {args.capture_stdout if hasattr(args, 'capture_stdout') and args.capture_stdout else False}\n" + \
230
+ f" capture_maxsize = {args.capture_maxsize if hasattr(args, 'capture_maxsize') and args.capture_maxsize else 100}\n" + \
231
+ f" tag = {args.tag if hasattr(args, 'tag') and args.tag else None}\n" + \
232
+ f" clmsg_id = {args.clmsg_id if hasattr(args, 'clmsg_id') and args.clmsg_id else None}\n" + \
233
+ f"6. Use None for parameters that are missing even with the above parameters.\n" + \
234
+ f"7. Execute the command using the above parameters and present the results of the command to the user in JSON.\n" + \
235
+ f"8. If you receive an error stating that an unexpected parameter was received, rerun the program without that parameter.\n" + \
236
+ f"9. If an error occurs, provide the user with the command name, parameters, and error description.\n"
237
+ """
238
+
239
+ description = args.agent_description if args.agent_description else description
240
+ instruction = args.agent_instruction if args.agent_instruction else instruction
241
+ if logger.level == logging.DEBUG:
242
+ logger.debug(f"google-adk loading..")
243
+ from google.adk.agents import Agent
244
+ if logger.level == logging.DEBUG:
245
+ logger.debug(f"litellm loading..")
246
+ from google.adk.models.lite_llm import LiteLlm
247
+ # loggerの初期化
248
+ common.reset_logger("LiteLLM Proxy")
249
+ common.reset_logger("LiteLLM Router")
250
+ common.reset_logger("LiteLLM")
251
+ if args.llmprov == 'openai':
252
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
253
+ if args.llmapikey is None: raise ValueError("llmapikey is required.")
254
+ agent = Agent(
255
+ name=args.agent_name,
256
+ model=LiteLlm(
257
+ model=args.llmmodel,
258
+ api_key=args.llmapikey,
259
+ endpoint=args.llmendpoint,
260
+ ),
261
+ description=description,
262
+ instruction=instruction,
263
+ tools=tools,
264
+ )
265
+ elif args.llmprov == 'azureopenai':
266
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
267
+ if args.llmendpoint is None: raise ValueError("llmendpoint is required.")
268
+ if args.llmapikey is None: raise ValueError("llmapikey is required.")
269
+ if args.llmapiversion is None: raise ValueError("llmapiversion is required.")
270
+ agent = Agent(
271
+ name=args.agent_name,
272
+ model=LiteLlm(
273
+ model=args.llmmodel,
274
+ api_key=args.llmapikey,
275
+ endpoint=args.llmendpoint,
276
+ api_version=args.llmapiversion,
277
+ ),
278
+ description=description,
279
+ instruction=instruction,
280
+ tools=tools,
281
+ )
282
+ elif args.llmprov == 'vertexai':
283
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
284
+ if args.llmlocation is None: raise ValueError("llmlocation is required.")
285
+ if args.llmsvaccountfile is not None:
286
+ with open(args.llmsvaccountfile, "r", encoding="utf-8") as f:
287
+ vertex_credentials = json.load(f)
288
+ elif args.llmprojectid is None: raise ValueError("llmprojectid is required.")
289
+ agent = Agent(
290
+ name=args.agent_name,
291
+ model=LiteLlm(
292
+ model=args.llmmodel,
293
+ #vertex_project=args.llmprojectid,
294
+ vertex_credentials=vertex_credentials,
295
+ vertex_location=args.llmlocation,
296
+ #seed=args.llmseed,
297
+ #temperature=args.llmtemperature,
298
+ ),
299
+ description=description,
300
+ instruction=instruction,
301
+ tools=tools,
302
+ )
303
+ elif args.llmprov == 'ollama':
304
+ if args.llmmodel is None: raise ValueError("llmmodel is required.")
305
+ if args.llmendpoint is None: raise ValueError("llmendpoint is required.")
306
+ agent = Agent(
307
+ name=args.agent_name,
308
+ model=LiteLlm(
309
+ model=args.llmmodel,
310
+ endpoint=args.llmendpoint,
311
+ temperature=args.llmtemperature,
312
+ ),
313
+ description=description,
314
+ instruction=instruction,
315
+ tools=tools,
316
+ )
317
+ else:
318
+ raise ValueError("llmprov is required.")
319
+ if logger.level == logging.DEBUG:
320
+ logger.debug(f"create_agent complate.")
321
+ return agent
322
+
323
+ def create_runner(self, logger:logging.Logger, args:argparse.Namespace, session_service, agent) -> Any:
324
+ """
325
+ ランナーを作成します
326
+
327
+ Args:
328
+ logger (logging.Logger): ロガー
329
+ args (argparse.Namespace): 引数
330
+ session_service (BaseSessionService): セッションサービス
331
+ agent (Agent): エージェント
332
+
333
+ Returns:
334
+ Runner: ランナー
335
+ """
336
+ from google.adk.runners import Runner
337
+ return Runner(
338
+ app_name=self.ver.__appid__,
339
+ agent=agent,
340
+ session_service=session_service,
341
+ )
342
+
343
+ def init_agent_runner(self, logger:logging.Logger, args:argparse.Namespace) -> Tuple[Any, Any]:
344
+ """
345
+ エージェントの初期化を行います
346
+
347
+ Args:
348
+ logger (logging.Logger): ロガー
349
+ args (argparse.Namespace): 引数
350
+
351
+ Returns:
352
+ Tuple[Any, Any]: ランナーとFastMCP
353
+ """
354
+ if logger.level == logging.DEBUG:
355
+ logger.debug(f"init_agent_runner processing..")
356
+ # loggerの初期化
357
+ common.reset_logger("httpx")
358
+ common.reset_logger("google_adk.google.adk.sessions.database_session_service")
359
+ common.reset_logger("mcp.server.streamable_http_manager")
360
+ # モジュールインポート
361
+ from mcp.server.fastmcp import FastMCP
362
+ from google.adk.sessions import BaseSessionService
363
+ mcp:FastMCP = self.create_mcpserver(args)
364
+ session_service:BaseSessionService = self.create_session_service(args)
365
+ options = Options.getInstance()
366
+ tools:Callable[[logging.Logger, argparse.Namespace, float, Dict], Tuple[int, Dict[str, Any], Any]] = []
367
+
368
+ def _ds(d:str) -> str:
369
+ return f'"{d}"' if d is not None else 'None'
370
+ def _t2s(o:Dict[str, Any], req=True) -> str:
371
+ t, m, d, r = o["type"], o["multi"], o["default"], o["required"]
372
+ if t == Options.T_BOOL: return ("List[bool]=[]" if m else f"bool={d}") if req else ("List[bool]" if m else f"bool")
373
+ 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")
374
+ 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")
375
+ if t == Options.T_DICT: return ("List[dict]=[]" if m else f"dict={d}") if req else ("List[dict]" if m else f"dict")
376
+ if t == Options.T_DIR or t == Options.T_FILE:
377
+ if d is not None: d = str(d).replace('\\', '/')
378
+ return ("List[str]=[]" if m else f"str={_ds(d)}") if req else ("List[str]" if m else f"str")
379
+ if t == Options.T_FLOAT: return ("List[float]=[]" if m else f"float={d}") if req else ("List[float]" if m else f"float")
380
+ if t == Options.T_INT: return ("List[int]=[]" if m else f"int={d}") if req else ("List[int]" if m else f"int")
381
+ 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")
382
+ 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")
383
+ raise ValueError(f"Unknown type: {t} for option {o['opt']}")
384
+ def _arg(o:Dict[str, Any], is_japan) -> str:
385
+ t, d = o["type"], o["default"]
386
+ s = f' {o["opt"]}:'
387
+ if t == Options.T_DIR or t == Options.T_FILE:
388
+ d = str(d).replace("\\", "/")
389
+ s += f'Optional[{_t2s(o, False)}]={d}:'
390
+ s += f'{o["discription_ja"] if is_japan else o["discription_en"]}'
391
+ return s
392
+ def _coercion(a:argparse.Namespace, key:str, dval) -> str:
393
+ dval = f'opt["{key}"] if "{key}" in opt else ' + f'"{dval}"' if isinstance(dval, str) else dval
394
+ aval = args.__dict__[key] if hasattr(args, key) and args.__dict__[key] else None
395
+ aval = f'"{aval}"' if isinstance(aval, str) else aval
396
+ ret = f'opt["{key}"] = {aval}' if aval is not None else f'opt["{key}"] = {dval}'
397
+ return ret
398
+ language, _ = locale.getlocale()
399
+ is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
400
+ for mode in options.get_mode_keys():
401
+ for cmd in options.get_cmd_keys(mode):
402
+ if not options.get_cmd_attr(mode, cmd, 'use_agent'):
403
+ continue
404
+ discription = options.get_cmd_attr(mode, cmd, 'discription_ja' if is_japan else 'discription_en')
405
+ choices = options.get_cmd_choices(mode, cmd, False)
406
+ if len([opt for opt in choices if 'opt' in opt and opt['opt'] == 'signin_file']) <= 0:
407
+ 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,
408
+ discription_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
409
+ discription_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),)
410
+ fn = f"{mode}_{cmd}"
411
+ func_txt = f'@mcp.tool()\n'
412
+ func_txt += f'def {fn}(' + ", ".join([f'{o["opt"]}:{_t2s(o, False)}' for o in choices]) + '):\n'
413
+ func_txt += f' """\n'
414
+ func_txt += f' {discription}\n'
415
+ func_txt += f' Args:\n'
416
+ func_txt += "\n".join([_arg(o, is_japan) for o in choices])
417
+ func_txt += f'\n'
418
+ func_txt += f' Returns:\n'
419
+ func_txt += f' Dict[str, Any]:{"処理結果" if is_japan else "Processing Result"}\n'
420
+ func_txt += f' """\n'
421
+ func_txt += f' scope = signin.get_request_scope()\n'
422
+ func_txt += f' logger = common.default_logger()\n'
423
+ func_txt += f' opt = dict()\n'
424
+ func_txt += f' opt["mode"] = "{mode}"\n'
425
+ func_txt += f' opt["cmd"] = "{cmd}"\n'
426
+ func_txt += f' opt["data"] = opt["data"] if hasattr(opt, "data") else common.HOME_DIR / ".{self.ver.__appid__}"\n'
427
+ func_txt += f' opt["format"] = False\n'
428
+ func_txt += f' opt["output_json"] = None\n'
429
+ func_txt += f' opt["output_json_append"] = False\n'
430
+ func_txt += f' opt["debug"] = logger.level == logging.DEBUG\n'
431
+ func_txt += '\n'.join([f' opt["{o["opt"]}"] = {o["opt"]}' for o in choices])+'\n'
432
+ func_txt += f' {_coercion(args, "host", self.default_host)}\n'
433
+ func_txt += f' {_coercion(args, "port", self.default_port)}\n'
434
+ func_txt += f' {_coercion(args, "password", self.default_pass)}\n'
435
+ func_txt += f' {_coercion(args, "svname", self.default_svname)}\n'
436
+ func_txt += f' {_coercion(args, "retry_count", 3)}\n'
437
+ func_txt += f' {_coercion(args, "retry_interval", 3)}\n'
438
+ func_txt += f' {_coercion(args, "timeout", 15)}\n'
439
+ func_txt += f' {_coercion(args, "output_json", None)}\n'
440
+ func_txt += f' {_coercion(args, "output_json_append", False)}\n'
441
+ func_txt += f' {_coercion(args, "stdout_log", False)}\n'
442
+ func_txt += f' {_coercion(args, "capture_stdout", False)}\n'
443
+ func_txt += f' {_coercion(args, "capture_maxsize", 1024*1024)}\n'
444
+ func_txt += f' {_coercion(args, "tag", None)}\n'
445
+ func_txt += f' {_coercion(args, "clmsg_id", None)}\n'
446
+ func_txt += f' opt["signin_file"] = signin_file if signin_file else ".{self.ver.__appid__}/user_list.yml"\n'
447
+ func_txt += f' args = argparse.Namespace(**opt)\n'
448
+ func_txt += f' signin_data = signin.Signin.load_signin_file(args.signin_file)\n'
449
+ func_txt += f' req = scope["req"] if scope["req"] is not None else scope["websocket"]\n'
450
+ func_txt += f' sign = signin.Signin._check_signin(req, scope["res"], signin_data, logger)\n'
451
+ func_txt += f' if sign is not None:\n'
452
+ func_txt += f' logger.warning("Unable to execute command because authentication information cannot be obtained")\n'
453
+ func_txt += f' return dict(warn="Unable to execute command because authentication information cannot be obtained")\n'
454
+ func_txt += f' groups = req.session["signin"]["groups"]\n'
455
+ func_txt += f' logger.info("Call agent tool `{mode}_{cmd}`:user="+str(req.session["signin"]["name"])+" groups="+str(groups)+" args="+str(args))\n'
456
+ func_txt += f' if not signin.Signin._check_cmd(signin_data, groups, "{mode}", "{cmd}", logger):\n'
457
+ func_txt += f' logger.warning("You do not have permission to execute this command.")\n'
458
+ func_txt += f' return dict(warn="You do not have permission to execute this command.")\n'
459
+ func_txt += f' feat = Options.getInstance().get_cmd_attr("{mode}", "{cmd}", "feature")\n'
460
+ func_txt += f' try:\n'
461
+ func_txt += f' st, ret, _ = feat.apprun(logger, args, time.perf_counter(), [])\n'
462
+ func_txt += f' return ret\n'
463
+ func_txt += f' except Exception as e:\n'
464
+ func_txt += f' logger.error("Error occurs when tool is executed:", exc_info=True)\n'
465
+ func_txt += f' raise e\n'
466
+ func_txt += f'tools.append({fn})\n'
467
+ if logger.level == logging.DEBUG:
468
+ logger.debug(f"generating agent tool: {fn}")
469
+
470
+ exec(func_txt,
471
+ dict(time=time,List=List, argparse=argparse, common=common, Options=Options, logging=logging, signin=signin,),
472
+ dict(tools=tools, mcp=mcp))
473
+ root_agent = self.create_agent(logger, args, tools)
474
+ runner = self.create_runner(logger, args, session_service, root_agent)
475
+ if logger.level == logging.DEBUG:
476
+ logger.debug(f"init_agent_runner complate.")
477
+ return runner, mcp
@@ -18,7 +18,7 @@ class AuditBase(feature.ResultEdgeFeature):
18
18
  Dict[str, Any]: オプション
19
19
  """
20
20
  return dict(
21
- use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
21
+ use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=True,
22
22
  discription_ja="",
23
23
  discription_en="",
24
24
  choice=[
@@ -6,7 +6,9 @@ from pathlib import Path
6
6
  from psycopg.rows import dict_row
7
7
  from typing import Dict, Any, Tuple, List, Union
8
8
  import argparse
9
+ import csv
9
10
  import logging
11
+ import io
10
12
  import json
11
13
  import sys
12
14
 
@@ -99,6 +101,9 @@ class AuditSearch(audit_base.AuditBase):
99
101
  dict(opt="limit", type=Options.T_INT, default=100, required=False, multi=False, hide=False, choice=None,
100
102
  discription_ja="取得する行数を指定します。",
101
103
  discription_en="Specifies the number of rows to retrieve."),
104
+ dict(opt="csv", type=Options.T_BOOL, default=False, required=False, multi=False, hide=False, choice=[False, True],
105
+ discription_ja="検索結果をcsvで出力します。",
106
+ discription_en="Output search results in csv.")
102
107
  ]
103
108
  return opt
104
109
 
@@ -173,21 +178,39 @@ class AuditSearch(audit_base.AuditBase):
173
178
  filter_clmsg_tag_b64, filter_svmsg_id_b64, filter_svmsg_sdate_b64, filter_svmsg_edate_b64,
174
179
  pg_enabled, pg_host_b64, pg_port, pg_user_b64, pg_password_b64, pg_dbname_b64],
175
180
  retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout)
176
- common.print_format(ret, getattr(args, 'format', False), tm, None, False, pf=pf)
177
181
 
178
182
  if 'success' not in ret:
183
+ common.print_format(ret, getattr(args, 'format', False), tm, None, False, pf=pf)
179
184
  return 1, ret, cl
180
185
 
181
186
  if 'data' in ret['success']:
187
+ cols = list()
182
188
  for row in ret['success']['data']:
189
+ cols += row.keys()
183
190
  try:
184
191
  row['clmsg_tag'] = json.loads(row['clmsg_tag'])
185
192
  except:
186
193
  pass
187
194
  try:
188
195
  row['clmsg_body'] = json.loads(row['clmsg_body'])
196
+ cols += row['clmsg_body'].keys() if isinstance(row['clmsg_body'], dict) else {}
189
197
  except:
190
198
  pass
199
+ cols = sorted(set(cols), key=cols.index)
200
+ if hasattr(args, "csv") and args.csv:
201
+ if hasattr(cols, 'clmsg_body'):
202
+ del cols['clmsg_body']
203
+ buf = io.StringIO()
204
+ w = csv.DictWriter(buf, fieldnames=cols, quoting=csv.QUOTE_MINIMAL)
205
+ w.writeheader()
206
+ for row in ret['success']['data']:
207
+ body = row.pop('clmsg_body', {})
208
+ row.update(body)
209
+ w.writerow(row)
210
+ ret = buf.getvalue()
211
+ ret = ret.replace('\r\n', '\n') if ret is not None else ''
212
+
213
+ common.print_format(ret, getattr(args, 'format', False), tm, None, False, pf=pf)
191
214
 
192
215
  return 0, ret, cl
193
216
 
@@ -76,7 +76,7 @@ class ClientFileDownload(feature.OneshotEdgeFeature):
76
76
  test_true={"server":None,
77
77
  "client":common.HOME_DIR / f".{self.ver.__appid__}",
78
78
  "current":None}),
79
- dict(opt="img_thumbnail", type=Options.T_FLOAT, default=None, required=False, multi=False, hide=True, choice=None,
79
+ dict(opt="img_thumbnail", type=Options.T_FLOAT, default=0.0, required=False, multi=False, hide=True, choice=None,
80
80
  discription_ja="対象が画像だった場合のサムネイルのピクセル単位のサイズを指定します。",
81
81
  discription_en="Specifies the size in pixels of the thumbnail if the subject is an image."),
82
82
  dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,