agent-sin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +81 -0
  4. package/assets/logo.png +0 -0
  5. package/builtin-skills/_shared/_models_lib.py +227 -0
  6. package/builtin-skills/_shared/_profile_lib.py +98 -0
  7. package/builtin-skills/_shared/_schedules_lib.py +313 -0
  8. package/builtin-skills/_shared/_skill_settings_lib.py +153 -0
  9. package/builtin-skills/_shared/i18n.py +26 -0
  10. package/builtin-skills/memo-delete/main.py +155 -0
  11. package/builtin-skills/memo-delete/skill.yaml +57 -0
  12. package/builtin-skills/memo-index/main.py +178 -0
  13. package/builtin-skills/memo-index/skill.yaml +53 -0
  14. package/builtin-skills/memo-save/README.md +5 -0
  15. package/builtin-skills/memo-save/main.py +74 -0
  16. package/builtin-skills/memo-save/skill.yaml +52 -0
  17. package/builtin-skills/memo-search/README.md +10 -0
  18. package/builtin-skills/memo-search/main.py +97 -0
  19. package/builtin-skills/memo-search/skill.yaml +51 -0
  20. package/builtin-skills/memo-vector-search/main.py +121 -0
  21. package/builtin-skills/memo-vector-search/skill.yaml +53 -0
  22. package/builtin-skills/model-add/main.py +180 -0
  23. package/builtin-skills/model-add/skill.yaml +112 -0
  24. package/builtin-skills/model-list/main.py +93 -0
  25. package/builtin-skills/model-list/skill.yaml +48 -0
  26. package/builtin-skills/model-set/main.py +123 -0
  27. package/builtin-skills/model-set/skill.yaml +69 -0
  28. package/builtin-skills/profile-delete/_profile_lib.py +98 -0
  29. package/builtin-skills/profile-delete/main.py +98 -0
  30. package/builtin-skills/profile-delete/skill.yaml +64 -0
  31. package/builtin-skills/profile-edit/_profile_lib.py +98 -0
  32. package/builtin-skills/profile-edit/main.py +97 -0
  33. package/builtin-skills/profile-edit/skill.yaml +72 -0
  34. package/builtin-skills/profile-save/main.py +52 -0
  35. package/builtin-skills/profile-save/skill.yaml +69 -0
  36. package/builtin-skills/schedule-add/_schedules_lib.py +303 -0
  37. package/builtin-skills/schedule-add/main.py +137 -0
  38. package/builtin-skills/schedule-add/skill.yaml +94 -0
  39. package/builtin-skills/schedule-list/_schedules_lib.py +303 -0
  40. package/builtin-skills/schedule-list/main.py +86 -0
  41. package/builtin-skills/schedule-list/skill.yaml +45 -0
  42. package/builtin-skills/schedule-remove/_schedules_lib.py +303 -0
  43. package/builtin-skills/schedule-remove/main.py +69 -0
  44. package/builtin-skills/schedule-remove/skill.yaml +49 -0
  45. package/builtin-skills/schedule-toggle/_schedules_lib.py +303 -0
  46. package/builtin-skills/schedule-toggle/main.py +78 -0
  47. package/builtin-skills/schedule-toggle/skill.yaml +61 -0
  48. package/builtin-skills/skills-disable/main.py +63 -0
  49. package/builtin-skills/skills-disable/skill.yaml +52 -0
  50. package/builtin-skills/skills-enable/main.py +62 -0
  51. package/builtin-skills/skills-enable/skill.yaml +51 -0
  52. package/builtin-skills/todo-add/main.py +68 -0
  53. package/builtin-skills/todo-add/skill.yaml +53 -0
  54. package/builtin-skills/todo-delete/main.py +65 -0
  55. package/builtin-skills/todo-delete/skill.yaml +47 -0
  56. package/builtin-skills/todo-done/main.py +75 -0
  57. package/builtin-skills/todo-done/skill.yaml +47 -0
  58. package/builtin-skills/todo-list/main.py +91 -0
  59. package/builtin-skills/todo-list/skill.yaml +48 -0
  60. package/builtin-skills/todo-tick/main.py +125 -0
  61. package/builtin-skills/todo-tick/skill.yaml +48 -0
  62. package/dist/builder/build-action-classifier.d.ts +18 -0
  63. package/dist/builder/build-action-classifier.js +142 -0
  64. package/dist/builder/build-commands.d.ts +19 -0
  65. package/dist/builder/build-commands.js +133 -0
  66. package/dist/builder/build-flow.d.ts +72 -0
  67. package/dist/builder/build-flow.js +416 -0
  68. package/dist/builder/builder-session.d.ts +117 -0
  69. package/dist/builder/builder-session.js +1129 -0
  70. package/dist/builder/conversation-router.d.ts +22 -0
  71. package/dist/builder/conversation-router.js +69 -0
  72. package/dist/builder/intent-runtime-store.d.ts +7 -0
  73. package/dist/builder/intent-runtime-store.js +60 -0
  74. package/dist/builder/progress-format.d.ts +7 -0
  75. package/dist/builder/progress-format.js +46 -0
  76. package/dist/cli/index.d.ts +2 -0
  77. package/dist/cli/index.js +2835 -0
  78. package/dist/cli/spinner.d.ts +30 -0
  79. package/dist/cli/spinner.js +164 -0
  80. package/dist/core/ai-provider.d.ts +75 -0
  81. package/dist/core/ai-provider.js +678 -0
  82. package/dist/core/builtin-skills.d.ts +27 -0
  83. package/dist/core/builtin-skills.js +120 -0
  84. package/dist/core/chat-engine.d.ts +70 -0
  85. package/dist/core/chat-engine.js +812 -0
  86. package/dist/core/config.d.ts +127 -0
  87. package/dist/core/config.js +1379 -0
  88. package/dist/core/daily-memory-promotion.d.ts +21 -0
  89. package/dist/core/daily-memory-promotion.js +422 -0
  90. package/dist/core/i18n.d.ts +23 -0
  91. package/dist/core/i18n.js +167 -0
  92. package/dist/core/info-lines.d.ts +5 -0
  93. package/dist/core/info-lines.js +39 -0
  94. package/dist/core/input-schema.d.ts +2 -0
  95. package/dist/core/input-schema.js +156 -0
  96. package/dist/core/intent-router.d.ts +27 -0
  97. package/dist/core/intent-router.js +160 -0
  98. package/dist/core/logger.d.ts +60 -0
  99. package/dist/core/logger.js +240 -0
  100. package/dist/core/memory.d.ts +10 -0
  101. package/dist/core/memory.js +72 -0
  102. package/dist/core/message-utils.d.ts +13 -0
  103. package/dist/core/message-utils.js +104 -0
  104. package/dist/core/notifier.d.ts +17 -0
  105. package/dist/core/notifier.js +424 -0
  106. package/dist/core/output-writer.d.ts +13 -0
  107. package/dist/core/output-writer.js +100 -0
  108. package/dist/core/plan-decision.d.ts +16 -0
  109. package/dist/core/plan-decision.js +88 -0
  110. package/dist/core/profile-memory.d.ts +17 -0
  111. package/dist/core/profile-memory.js +142 -0
  112. package/dist/core/runtime.d.ts +50 -0
  113. package/dist/core/runtime.js +187 -0
  114. package/dist/core/scheduler.d.ts +28 -0
  115. package/dist/core/scheduler.js +155 -0
  116. package/dist/core/secrets.d.ts +31 -0
  117. package/dist/core/secrets.js +214 -0
  118. package/dist/core/service.d.ts +35 -0
  119. package/dist/core/service.js +479 -0
  120. package/dist/core/skill-planner.d.ts +24 -0
  121. package/dist/core/skill-planner.js +100 -0
  122. package/dist/core/skill-registry.d.ts +98 -0
  123. package/dist/core/skill-registry.js +319 -0
  124. package/dist/core/skill-scaffold.d.ts +33 -0
  125. package/dist/core/skill-scaffold.js +256 -0
  126. package/dist/core/skill-settings.d.ts +11 -0
  127. package/dist/core/skill-settings.js +63 -0
  128. package/dist/core/transfer.d.ts +31 -0
  129. package/dist/core/transfer.js +270 -0
  130. package/dist/core/update-notifier.d.ts +2 -0
  131. package/dist/core/update-notifier.js +140 -0
  132. package/dist/discord/bot.d.ts +96 -0
  133. package/dist/discord/bot.js +2424 -0
  134. package/dist/runtimes/codex-app-server.d.ts +53 -0
  135. package/dist/runtimes/codex-app-server.js +305 -0
  136. package/dist/runtimes/python-runner.d.ts +7 -0
  137. package/dist/runtimes/python-runner.js +302 -0
  138. package/dist/runtimes/typescript-runner.d.ts +5 -0
  139. package/dist/runtimes/typescript-runner.js +172 -0
  140. package/dist/skills-sdk/types.d.ts +38 -0
  141. package/dist/skills-sdk/types.js +1 -0
  142. package/dist/telegram/bot.d.ts +94 -0
  143. package/dist/telegram/bot.js +1219 -0
  144. package/install.ps1 +132 -0
  145. package/install.sh +130 -0
  146. package/package.json +60 -0
  147. package/templates/skill-python/main.py +74 -0
  148. package/templates/skill-python/skill.yaml +48 -0
  149. package/templates/skill-typescript/main.ts +87 -0
  150. package/templates/skill-typescript/skill.yaml +42 -0
@@ -0,0 +1,53 @@
1
+ # Builtin: memo-vector-search
2
+ # memo-index で索引化した Chroma DB を意味検索する (multilingual MiniLM L12 経由)。
3
+ # memo-search (substring grep) との使い分け:
4
+ # memo-search → 完全一致・タグ検索向き、軽量
5
+ # memo-vector-search → 意味検索 (類義語・別表現を拾える)、要索引化
6
+
7
+ id: memo-vector-search
8
+ name: Memo Vector Search
9
+ name_i18n:
10
+ en: Memo Vector Search
11
+ ja: メモ意味検索
12
+ description: 索引化されたメモを意味検索する (Chroma)
13
+ description_i18n:
14
+ en: Semantically search indexed memos with Chroma
15
+ ja: 索引化されたメモを意味検索する (Chroma)
16
+ runtime: python
17
+
18
+ invocation:
19
+ command: memo.vsearch
20
+ phrases:
21
+ - 意味検索
22
+ - ベクター検索
23
+ phrases_i18n:
24
+ en:
25
+ - semantic memo search
26
+ - vector search
27
+ ja:
28
+ - 意味検索
29
+ - ベクター検索
30
+
31
+ input:
32
+ schema:
33
+ type: object
34
+ additionalProperties: false
35
+ properties:
36
+ query:
37
+ type: string
38
+ minLength: 1
39
+ limit:
40
+ type: integer
41
+ minimum: 1
42
+ maximum: 50
43
+ default: 5
44
+ collection:
45
+ type: string
46
+ default: memo
47
+ required:
48
+ - query
49
+
50
+ memory:
51
+ namespace: memo-index
52
+ read: true
53
+ write: false
@@ -0,0 +1,180 @@
1
+ """Builtin: model-add
2
+
3
+ models.yaml にモデル定義を1件追加する。set_as が指定されていれば、
4
+ 追加と同時に chat / builder ロールの既定モデルにする。
5
+ 同じIDが既に同等の内容で登録されていれば idempotent に「登録済み」を返す。
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ import sys
12
+
13
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
14
+ from i18n import localizer # noqa: E402
15
+ from _models_lib import ( # noqa: E402
16
+ build_entry,
17
+ default_effort_for,
18
+ derive_id,
19
+ entries_equivalent,
20
+ entry_summary,
21
+ find_provider,
22
+ load_models,
23
+ models_path,
24
+ normalize_effort,
25
+ save_models,
26
+ unique_id,
27
+ )
28
+
29
+
30
+ async def run(ctx, input):
31
+ loc = localizer(input)
32
+ args = input.get("args", {}) or {}
33
+ workspace = input.get("sources", {}).get("workspace", "")
34
+ if not workspace:
35
+ return _err(loc.t("Workspace unavailable", "ワークスペース不明"),
36
+ loc.t("The workspace path is unavailable.", "workspace パスが取得できません"))
37
+
38
+ provider_raw = str(args.get("provider", "")).strip()
39
+ if not provider_raw:
40
+ return _err(loc.t("Provider missing", "プロバイダ未指定"),
41
+ loc.t("Specify provider (codex / claude-code / openai / gemini / anthropic / ollama).",
42
+ "provider を指定してください (codex / claude-code / openai / gemini / anthropic / ollama)"))
43
+ catalog = find_provider(provider_raw)
44
+ if not catalog:
45
+ return _err(loc.t("Unknown provider", "不明なプロバイダ"),
46
+ loc.t(f"Unknown provider: {provider_raw}", f"不明なプロバイダです: {provider_raw}"))
47
+
48
+ model_raw = str(args.get("model", "")).strip()
49
+ model = model_raw or catalog.get("default_model")
50
+
51
+ set_as = str(args.get("set_as", "")).strip().lower() or None
52
+ if set_as and set_as not in ("chat", "builder"):
53
+ return _err(loc.t("Invalid set_as", "set_as 不正"),
54
+ loc.t('set_as must be "chat" or "builder".', 'set_as は "chat" か "builder" を指定してください'))
55
+
56
+ try:
57
+ effort = normalize_effort(args.get("effort"))
58
+ except ValueError as e:
59
+ return _err(loc.t("Invalid effort", "effort 不正"), str(e))
60
+ if catalog.get("needs_effort") and not effort:
61
+ # ロール優先度: set_as があればそれ、無ければ chat の既定を使う
62
+ effort = default_effort_for(catalog, set_as or "chat")
63
+ if not catalog.get("needs_effort") and effort:
64
+ effort = None # API 系では effort を持たない
65
+
66
+ try:
67
+ models = load_models(workspace)
68
+ except Exception as e:
69
+ return _err(loc.t("Load failed", "読込失敗"),
70
+ loc.t(f"Could not read models.yaml: {e}", f"models.yaml を読めませんでした: {e}"))
71
+
72
+ existing_ids = set(models["models"].keys())
73
+ requested_id = str(args.get("id", "")).strip() or None
74
+ new_entry = build_entry(catalog, model, effort)
75
+
76
+ # 冪等性: 既存のエントリに内容一致するものがあれば、それを再利用する。
77
+ # requested_id があるときは、その ID が等価エントリでない限り別物として扱う。
78
+ equivalent_id = None
79
+ for eid, e in models["models"].items():
80
+ if entries_equivalent(e, new_entry):
81
+ equivalent_id = eid
82
+ break
83
+
84
+ if equivalent_id and (not requested_id or requested_id == equivalent_id):
85
+ existing = models["models"][equivalent_id]
86
+ roles_changed = False
87
+ if set_as and models["roles"].get(set_as) != equivalent_id:
88
+ models["roles"][set_as] = equivalent_id
89
+ roles_changed = True
90
+ if roles_changed:
91
+ try:
92
+ save_models(workspace, models)
93
+ except Exception as e:
94
+ return _err(loc.t("Save failed", "保存失敗"),
95
+ loc.t(f"Failed to write models.yaml: {e}", f"models.yaml への書き込みに失敗しました: {e}"))
96
+ summary = loc.t(
97
+ f"{equivalent_id} already existed; set as {set_as} model.",
98
+ f"{equivalent_id} は既に登録済みでした。{set_as} の既定モデルに設定しました。")
99
+ else:
100
+ summary = loc.t(
101
+ f"Already registered: {entry_summary(equivalent_id, existing)}",
102
+ f"登録済みです: {entry_summary(equivalent_id, existing)}")
103
+ ctx.log.info(f"model-add: equivalent entry exists id={equivalent_id} set_as={set_as}")
104
+ return {
105
+ "status": "ok",
106
+ "title": loc.t("Already registered", "登録済み"),
107
+ "summary": summary,
108
+ "outputs": {},
109
+ "data": {
110
+ "id": equivalent_id,
111
+ "entry": existing,
112
+ "set_as": set_as,
113
+ "already_registered": True,
114
+ "path": models_path(workspace),
115
+ },
116
+ "suggestions": [],
117
+ }
118
+
119
+ # ID 決定: 明示指定があればそれを使う。なければ provider/effort から導出。
120
+ if requested_id:
121
+ new_id = requested_id
122
+ if new_id in existing_ids:
123
+ # 等価なら上で return 済み。ここに来るのは「同じIDで内容違い」のケース
124
+ return _err(
125
+ loc.t("ID conflict", "ID重複"),
126
+ loc.t(
127
+ f'Model ID "{new_id}" already exists with different settings. Remove it first or use a different id.',
128
+ f'モデルID "{new_id}" は別の内容で既に登録されています。先に削除するか、別の id を指定してください'),
129
+ )
130
+ else:
131
+ base = derive_id(catalog["id"], effort, catalog["type"])
132
+ new_id = unique_id(base, existing_ids)
133
+
134
+ models["models"][new_id] = new_entry
135
+ if set_as:
136
+ models["roles"][set_as] = new_id
137
+
138
+ try:
139
+ path = save_models(workspace, models)
140
+ except Exception as e:
141
+ return _err(loc.t("Save failed", "保存失敗"),
142
+ loc.t(f"Failed to write models.yaml: {e}", f"models.yaml への書き込みに失敗しました: {e}"))
143
+
144
+ ctx.log.info(f"model-add: id={new_id} provider={catalog['id']} model={model} effort={effort} set_as={set_as}")
145
+
146
+ if set_as:
147
+ summary = loc.t(
148
+ f"Added {entry_summary(new_id, new_entry)} and set as {set_as} model.",
149
+ f"追加しました: {entry_summary(new_id, new_entry)}。{set_as} の既定モデルに設定しました。",
150
+ )
151
+ else:
152
+ summary = loc.t(
153
+ f"Added {entry_summary(new_id, new_entry)}.",
154
+ f"追加しました: {entry_summary(new_id, new_entry)}",
155
+ )
156
+
157
+ return {
158
+ "status": "ok",
159
+ "title": loc.t("Added", "追加"),
160
+ "summary": summary,
161
+ "outputs": {},
162
+ "data": {
163
+ "id": new_id,
164
+ "entry": new_entry,
165
+ "set_as": set_as,
166
+ "path": path,
167
+ },
168
+ "suggestions": [],
169
+ }
170
+
171
+
172
+ def _err(title, summary):
173
+ return {
174
+ "status": "error",
175
+ "title": title,
176
+ "summary": summary,
177
+ "outputs": {},
178
+ "data": {},
179
+ "suggestions": [],
180
+ }
@@ -0,0 +1,112 @@
1
+ # Builtin: model-add
2
+ # ~/.agent-sin/models.yaml にモデル定義を1件追加する。set_as を渡せば
3
+ # chat / builder のロールにも同時に割り当てる。
4
+
5
+ id: model-add
6
+ name: Model Add
7
+ name_i18n:
8
+ en: Model Add
9
+ ja: モデル追加
10
+ description: >-
11
+ AIモデル定義を models.yaml に追加する。provider は codex / claude-code /
12
+ openai / gemini / anthropic / ollama のいずれか。model 名を省略すると
13
+ 各プロバイダの既定値を使う。codex / claude-code は effort
14
+ (low/medium/high/xhigh) を受け付ける。set_as=chat または builder を渡すと
15
+ 追加と同時にそのロールの既定モデルにする。
16
+ description_i18n:
17
+ en: >-
18
+ Add an AI model definition to models.yaml. provider must be one of
19
+ codex / claude-code / openai / gemini / anthropic / ollama. When model
20
+ is omitted, the per-provider default is used. codex / claude-code
21
+ accept an effort (low/medium/high/xhigh). When set_as=chat or builder
22
+ is given, the new model is also assigned to that role.
23
+ ja: >-
24
+ AIモデル定義を models.yaml に追加する。provider は codex / claude-code /
25
+ openai / gemini / anthropic / ollama のいずれか。model 名を省略すると
26
+ 各プロバイダの既定値を使う。codex / claude-code は effort
27
+ (low/medium/high/xhigh) を受け付ける。set_as=chat または builder を渡すと
28
+ 追加と同時にそのロールの既定モデルにする。
29
+ runtime: python
30
+ entry: main.py
31
+ handler: run
32
+ output_mode: raw
33
+ side_effect: true
34
+
35
+ invocation:
36
+ command: model.add
37
+ phrases:
38
+ - モデルを追加
39
+ - モデル追加
40
+ - openaiモデルを追加して
41
+ - anthropicを使えるようにして
42
+ - geminiを追加
43
+ - ollamaモデルを登録
44
+ phrases_i18n:
45
+ en:
46
+ - add a model
47
+ - register a model
48
+ - enable openai
49
+ - add anthropic
50
+ - add gemini
51
+ - register ollama model
52
+ ja:
53
+ - モデルを追加
54
+ - モデル追加
55
+ - openaiモデルを追加して
56
+ - anthropicを使えるようにして
57
+ - geminiを追加
58
+ - ollamaモデルを登録
59
+
60
+ input:
61
+ schema:
62
+ type: object
63
+ additionalProperties: false
64
+ properties:
65
+ provider:
66
+ type: string
67
+ enum:
68
+ - codex
69
+ - claude-code
70
+ - openai
71
+ - gemini
72
+ - anthropic
73
+ - ollama
74
+ description: 追加するモデルのプロバイダ
75
+ description_i18n:
76
+ en: Provider of the model to add
77
+ ja: 追加するモデルのプロバイダ
78
+ model:
79
+ type: string
80
+ description: モデル名 (省略時はプロバイダ既定値)
81
+ description_i18n:
82
+ en: Model name (uses provider default when omitted)
83
+ ja: モデル名 (省略時はプロバイダ既定値)
84
+ effort:
85
+ type: string
86
+ enum:
87
+ - low
88
+ - medium
89
+ - high
90
+ - xhigh
91
+ description: effort 設定 (codex / claude-code のみ)
92
+ description_i18n:
93
+ en: effort setting (codex / claude-code only)
94
+ ja: effort 設定 (codex / claude-code のみ)
95
+ id:
96
+ type: string
97
+ minLength: 1
98
+ description: 任意のエントリID (省略時は自動生成)
99
+ description_i18n:
100
+ en: Optional entry ID (auto-derived when omitted)
101
+ ja: 任意のエントリID (省略時は自動生成)
102
+ set_as:
103
+ type: string
104
+ enum:
105
+ - chat
106
+ - builder
107
+ description: 追加後にこのロールの既定モデルに設定する
108
+ description_i18n:
109
+ en: Also set as the default for this role after adding
110
+ ja: 追加後にこのロールの既定モデルに設定する
111
+ required:
112
+ - provider
@@ -0,0 +1,93 @@
1
+ """Builtin: model-list
2
+
3
+ models.yaml の登録モデル一覧と、chat / builder ロールの現在の割当を返す。
4
+ 副作用なし。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import sys
11
+
12
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
13
+ from i18n import localizer # noqa: E402
14
+ from _models_lib import load_models, models_path # noqa: E402
15
+
16
+
17
+ async def run(ctx, input):
18
+ loc = localizer(input)
19
+ workspace = input.get("sources", {}).get("workspace", "")
20
+ if not workspace:
21
+ return _err(loc.t("Workspace unavailable", "ワークスペース不明"),
22
+ loc.t("The workspace path is unavailable.", "workspace パスが取得できません"))
23
+
24
+ try:
25
+ models = load_models(workspace)
26
+ except Exception as e:
27
+ return _err(loc.t("Load failed", "読込失敗"),
28
+ loc.t(f"Could not read models.yaml: {e}", f"models.yaml を読めませんでした: {e}"))
29
+
30
+ chat_id = models["roles"].get("chat")
31
+ builder_id = models["roles"].get("builder")
32
+
33
+ items = []
34
+ lines = []
35
+ for entry_id, entry in models["models"].items():
36
+ roles = []
37
+ if entry_id == chat_id:
38
+ roles.append("chat")
39
+ if entry_id == builder_id:
40
+ roles.append("builder")
41
+ item = {
42
+ "id": entry_id,
43
+ "type": entry.get("type"),
44
+ "provider": entry.get("provider"),
45
+ "model": entry.get("model"),
46
+ "effort": entry.get("effort"),
47
+ "enabled": entry.get("enabled", True),
48
+ "roles": roles,
49
+ }
50
+ items.append(item)
51
+ parts = []
52
+ parts.append(entry.get("provider") or entry.get("type") or "-")
53
+ if entry.get("model"):
54
+ parts.append(str(entry["model"]))
55
+ if entry.get("effort"):
56
+ parts.append(f"effort={entry['effort']}")
57
+ if entry.get("enabled") is False:
58
+ parts.append("disabled")
59
+ suffix = f" <- {','.join(roles)}" if roles else ""
60
+ lines.append(f"- {entry_id}: {' / '.join(parts)}{suffix}")
61
+
62
+ role_summary = loc.t(
63
+ f"chat: {chat_id or '-'} / builder: {builder_id or '-'}",
64
+ f"chat: {chat_id or '-'} / builder: {builder_id or '-'}",
65
+ )
66
+ if items:
67
+ summary = role_summary + "\n" + "\n".join(lines)
68
+ else:
69
+ summary = loc.t("No models registered.", "登録モデルはありません")
70
+
71
+ return {
72
+ "status": "ok",
73
+ "title": loc.t("Models", "モデル一覧"),
74
+ "summary": summary,
75
+ "outputs": {},
76
+ "data": {
77
+ "roles": {"chat": chat_id, "builder": builder_id},
78
+ "models": items,
79
+ "path": models_path(workspace),
80
+ },
81
+ "suggestions": [],
82
+ }
83
+
84
+
85
+ def _err(title, summary):
86
+ return {
87
+ "status": "error",
88
+ "title": title,
89
+ "summary": summary,
90
+ "outputs": {},
91
+ "data": {},
92
+ "suggestions": [],
93
+ }
@@ -0,0 +1,48 @@
1
+ # Builtin: model-list
2
+ # models.yaml の登録モデル一覧と、chat / builder の現在の割当を返す。
3
+
4
+ id: model-list
5
+ name: Model List
6
+ name_i18n:
7
+ en: Model List
8
+ ja: モデル一覧
9
+ description: >-
10
+ models.yaml に登録されているモデル一覧と、chat / builder ロールの現在の
11
+ 割当を返す。「今のモデルは何?」「使えるモデルは?」に答えるのに使う。
12
+ description_i18n:
13
+ en: >-
14
+ Returns the list of models registered in models.yaml and the
15
+ current chat / builder role bindings.
16
+ ja: >-
17
+ models.yaml に登録されているモデル一覧と、chat / builder ロールの現在の
18
+ 割当を返す。「今のモデルは何?」「使えるモデルは?」に答えるのに使う。
19
+ runtime: python
20
+ entry: main.py
21
+ handler: run
22
+ output_mode: raw
23
+ side_effect: false
24
+
25
+ invocation:
26
+ command: model.list
27
+ phrases:
28
+ - 今のモデルは
29
+ - 使えるモデル
30
+ - モデル一覧
31
+ - 登録モデル
32
+ phrases_i18n:
33
+ en:
34
+ - which model
35
+ - available models
36
+ - list models
37
+ - registered models
38
+ ja:
39
+ - 今のモデルは
40
+ - 使えるモデル
41
+ - モデル一覧
42
+ - 登録モデル
43
+
44
+ input:
45
+ schema:
46
+ type: object
47
+ additionalProperties: false
48
+ properties: {}
@@ -0,0 +1,123 @@
1
+ """Builtin: model-set
2
+
3
+ models.yaml.roles の chat / builder ロールに、登録済みのモデルIDを割り当てる。
4
+ 未登録IDが渡された場合は候補一覧をエラーで返す。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import sys
11
+
12
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "_shared"))
13
+ from i18n import localizer # noqa: E402
14
+ from _models_lib import ( # noqa: E402
15
+ ALLOWED_ROLES,
16
+ entry_summary,
17
+ load_models,
18
+ models_path,
19
+ save_models,
20
+ )
21
+
22
+
23
+ async def run(ctx, input):
24
+ loc = localizer(input)
25
+ args = input.get("args", {}) or {}
26
+ workspace = input.get("sources", {}).get("workspace", "")
27
+ if not workspace:
28
+ return _err(loc.t("Workspace unavailable", "ワークスペース不明"),
29
+ loc.t("The workspace path is unavailable.", "workspace パスが取得できません"))
30
+
31
+ role = str(args.get("role", "")).strip().lower()
32
+ if role not in ALLOWED_ROLES:
33
+ return _err(loc.t("Invalid role", "role 不正"),
34
+ loc.t('role must be "chat" or "builder".', 'role は "chat" か "builder" を指定してください'))
35
+
36
+ target_id = str(args.get("id", "")).strip()
37
+ if not target_id:
38
+ return _err(loc.t("ID missing", "ID未指定"),
39
+ loc.t("Specify the model id to assign.", "割り当てるモデルIDを指定してください"))
40
+
41
+ try:
42
+ models = load_models(workspace)
43
+ except Exception as e:
44
+ return _err(loc.t("Load failed", "読込失敗"),
45
+ loc.t(f"Could not read models.yaml: {e}", f"models.yaml を読めませんでした: {e}"))
46
+
47
+ if target_id not in models["models"]:
48
+ known = ", ".join(models["models"].keys()) or "-"
49
+ return _err(
50
+ loc.t("Unknown model", "未登録モデル"),
51
+ loc.t(
52
+ f"Model id not found: {target_id}. Available: {known}. Call model-add first to register it.",
53
+ f"未登録のモデルIDです: {target_id}。登録済み: {known}。先に model-add で登録してください",
54
+ ),
55
+ )
56
+
57
+ current_id = models["roles"].get(role)
58
+ entry = models["models"][target_id]
59
+
60
+ if current_id == target_id:
61
+ return {
62
+ "status": "ok",
63
+ "title": loc.t("No change", "変更なし"),
64
+ "summary": loc.t(
65
+ f"{role} model is already {entry_summary(target_id, entry)}.",
66
+ f"{role} は既に {entry_summary(target_id, entry)} です",
67
+ ),
68
+ "outputs": {},
69
+ "data": {
70
+ "role": role,
71
+ "id": target_id,
72
+ "entry": entry,
73
+ "changed": False,
74
+ "path": models_path(workspace),
75
+ },
76
+ "suggestions": [],
77
+ }
78
+
79
+ # 該当エントリが disabled だった場合、ロール割当と同時に enabled=true にする
80
+ # (setRoleModel の TS 実装と挙動を合わせる)
81
+ if entry.get("enabled") is False:
82
+ entry["enabled"] = True
83
+ models["models"][target_id] = entry
84
+
85
+ models["roles"][role] = target_id
86
+
87
+ try:
88
+ path = save_models(workspace, models)
89
+ except Exception as e:
90
+ return _err(loc.t("Save failed", "保存失敗"),
91
+ loc.t(f"Failed to write models.yaml: {e}", f"models.yaml への書き込みに失敗しました: {e}"))
92
+
93
+ ctx.log.info(f"model-set: role={role} id={target_id} (was {current_id or '-'})")
94
+
95
+ return {
96
+ "status": "ok",
97
+ "title": loc.t("Switched", "切り替え"),
98
+ "summary": loc.t(
99
+ f"{role} model -> {entry_summary(target_id, entry)}",
100
+ f"{role} のモデルを {entry_summary(target_id, entry)} に切り替えました",
101
+ ),
102
+ "outputs": {},
103
+ "data": {
104
+ "role": role,
105
+ "id": target_id,
106
+ "previous_id": current_id,
107
+ "entry": entry,
108
+ "changed": True,
109
+ "path": path,
110
+ },
111
+ "suggestions": [],
112
+ }
113
+
114
+
115
+ def _err(title, summary):
116
+ return {
117
+ "status": "error",
118
+ "title": title,
119
+ "summary": summary,
120
+ "outputs": {},
121
+ "data": {},
122
+ "suggestions": [],
123
+ }
@@ -0,0 +1,69 @@
1
+ # Builtin: model-set
2
+ # models.yaml.roles の chat / builder を既存のモデルIDに付け替える。
3
+
4
+ id: model-set
5
+ name: Model Set
6
+ name_i18n:
7
+ en: Model Set
8
+ ja: モデル切替
9
+ description: >-
10
+ chat または builder のロールに、models.yaml に登録済みのモデルIDを割り当てる。
11
+ まだ登録されていないモデルを使いたい場合は model-add を先に呼ぶこと。
12
+ description_i18n:
13
+ en: >-
14
+ Assign an already-registered model ID to the chat or builder role.
15
+ For a not-yet-registered provider, call model-add first.
16
+ ja: >-
17
+ chat または builder のロールに、models.yaml に登録済みのモデルIDを割り当てる。
18
+ まだ登録されていないモデルを使いたい場合は model-add を先に呼ぶこと。
19
+ runtime: python
20
+ entry: main.py
21
+ handler: run
22
+ output_mode: raw
23
+ side_effect: true
24
+
25
+ invocation:
26
+ command: model.set
27
+ phrases:
28
+ - モデルを切り替えて
29
+ - chatをXに
30
+ - builderをXに
31
+ - 既定モデルを変更
32
+ - モデル変更
33
+ phrases_i18n:
34
+ en:
35
+ - switch the model
36
+ - set chat model
37
+ - set builder model
38
+ - change default model
39
+ ja:
40
+ - モデルを切り替えて
41
+ - chatをXに
42
+ - builderをXに
43
+ - 既定モデルを変更
44
+ - モデル変更
45
+
46
+ input:
47
+ schema:
48
+ type: object
49
+ additionalProperties: false
50
+ properties:
51
+ role:
52
+ type: string
53
+ enum:
54
+ - chat
55
+ - builder
56
+ description: 切り替え対象のロール
57
+ description_i18n:
58
+ en: Role to switch
59
+ ja: 切り替え対象のロール
60
+ id:
61
+ type: string
62
+ minLength: 1
63
+ description: 割り当てる既存のモデルID
64
+ description_i18n:
65
+ en: Existing model ID to assign
66
+ ja: 割り当てる既存のモデルID
67
+ required:
68
+ - role
69
+ - id