comisai 1.0.25 → 1.0.27

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 (145) hide show
  1. package/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +130 -10
  2. package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.d.ts +1 -1
  3. package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +9 -2
  4. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +8 -0
  5. package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +2 -0
  6. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +29 -0
  7. package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +242 -2
  8. package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.d.ts +210 -0
  9. package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.js +566 -0
  10. package/node_modules/@comis/agent/dist/context-engine/context-engine.js +8 -6
  11. package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +51 -30
  12. package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +109 -36
  13. package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.js +5 -1
  14. package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +22 -20
  15. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +2 -0
  16. package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +111 -15
  17. package/node_modules/@comis/agent/dist/executor/executor-response-filter.d.ts +20 -17
  18. package/node_modules/@comis/agent/dist/executor/executor-response-filter.js +132 -52
  19. package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +16 -3
  20. package/node_modules/@comis/agent/dist/executor/model-retry.d.ts +14 -0
  21. package/node_modules/@comis/agent/dist/executor/model-retry.js +72 -1
  22. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +3 -0
  23. package/node_modules/@comis/agent/dist/executor/pi-executor.js +68 -9
  24. package/node_modules/@comis/agent/dist/executor/post-batch-continuation.d.ts +82 -0
  25. package/node_modules/@comis/agent/dist/executor/post-batch-continuation.js +200 -0
  26. package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +1 -9
  27. package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +37 -2
  28. package/node_modules/@comis/agent/dist/executor/tool-deferral.js +45 -3
  29. package/node_modules/@comis/agent/dist/executor/tool-parallelism.js +0 -1
  30. package/node_modules/@comis/agent/dist/executor/types.d.ts +11 -2
  31. package/node_modules/@comis/agent/dist/index.d.ts +3 -1
  32. package/node_modules/@comis/agent/dist/index.js +2 -0
  33. package/node_modules/@comis/agent/dist/model/last-known-model.d.ts +36 -0
  34. package/node_modules/@comis/agent/dist/model/last-known-model.js +49 -0
  35. package/node_modules/@comis/agent/dist/model/model-registry-adapter.d.ts +16 -4
  36. package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +65 -21
  37. package/node_modules/@comis/agent/dist/planner/types.d.ts +0 -2
  38. package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +10 -0
  39. package/node_modules/@comis/agent/dist/session/comis-session-manager.js +5 -0
  40. package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.js +7 -0
  41. package/node_modules/@comis/agent/package.json +1 -1
  42. package/node_modules/@comis/channels/package.json +1 -1
  43. package/node_modules/@comis/cli/dist/client/rpc-client.js +6 -1
  44. package/node_modules/@comis/cli/dist/commands/doctor.js +5 -3
  45. package/node_modules/@comis/cli/dist/commands/health.js +5 -2
  46. package/node_modules/@comis/cli/dist/wizard/json-output.js +7 -3
  47. package/node_modules/@comis/cli/dist/wizard/steps/11-daemon-start.js +130 -0
  48. package/node_modules/@comis/cli/package.json +1 -1
  49. package/node_modules/@comis/core/dist/config/immutable-keys.d.ts +2 -2
  50. package/node_modules/@comis/core/dist/config/immutable-keys.js +8 -3
  51. package/node_modules/@comis/core/dist/config/managed-sections.d.ts +43 -4
  52. package/node_modules/@comis/core/dist/config/managed-sections.js +100 -6
  53. package/node_modules/@comis/core/dist/config/schema-agent.d.ts +39 -0
  54. package/node_modules/@comis/core/dist/config/schema-agent.js +14 -0
  55. package/node_modules/@comis/core/dist/config/schema.d.ts +4 -0
  56. package/node_modules/@comis/core/dist/config/schema.js +14 -0
  57. package/node_modules/@comis/core/dist/domain/execution-graph.d.ts +1 -1
  58. package/node_modules/@comis/core/dist/event-bus/events-agent.d.ts +17 -2
  59. package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
  60. package/node_modules/@comis/core/dist/exports/config.js +1 -1
  61. package/node_modules/@comis/core/package.json +1 -1
  62. package/node_modules/@comis/daemon/dist/daemon.d.ts +22 -0
  63. package/node_modules/@comis/daemon/dist/daemon.js +42 -0
  64. package/node_modules/@comis/daemon/dist/rpc/agent-handlers.d.ts +5 -2
  65. package/node_modules/@comis/daemon/dist/rpc/agent-handlers.js +80 -1
  66. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.d.ts +67 -0
  67. package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +139 -0
  68. package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +3 -0
  69. package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +29 -5
  70. package/node_modules/@comis/daemon/dist/rpc/probe-provider-auth.d.ts +30 -0
  71. package/node_modules/@comis/daemon/dist/rpc/probe-provider-auth.js +59 -0
  72. package/node_modules/@comis/daemon/dist/rpc/provider-handlers.d.ts +37 -0
  73. package/node_modules/@comis/daemon/dist/rpc/provider-handlers.js +330 -0
  74. package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.js +18 -1
  75. package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.d.ts +4 -0
  76. package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.js +30 -0
  77. package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +3 -1
  78. package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +28 -2
  79. package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +1 -0
  80. package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +7 -4
  81. package/node_modules/@comis/daemon/package.json +1 -1
  82. package/node_modules/@comis/gateway/package.json +1 -1
  83. package/node_modules/@comis/infra/dist/index.d.ts +1 -0
  84. package/node_modules/@comis/infra/dist/index.js +2 -0
  85. package/node_modules/@comis/infra/dist/runtime/is-docker.d.ts +1 -0
  86. package/node_modules/@comis/infra/dist/runtime/is-docker.js +25 -0
  87. package/node_modules/@comis/infra/package.json +1 -1
  88. package/node_modules/@comis/memory/package.json +1 -1
  89. package/node_modules/@comis/scheduler/package.json +1 -1
  90. package/node_modules/@comis/shared/package.json +1 -1
  91. package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +1 -3
  92. package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.js +24 -1
  93. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +53 -7
  94. package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +218 -24
  95. package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +4 -1
  96. package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +16 -1
  97. package/node_modules/@comis/skills/dist/builtin/platform/index.d.ts +1 -1
  98. package/node_modules/@comis/skills/dist/builtin/platform/index.js +1 -1
  99. package/node_modules/@comis/skills/dist/builtin/platform/providers-manage-tool.d.ts +56 -0
  100. package/node_modules/@comis/skills/dist/builtin/platform/providers-manage-tool.js +203 -0
  101. package/node_modules/@comis/skills/dist/index.d.ts +1 -1
  102. package/node_modules/@comis/skills/dist/index.js +2 -2
  103. package/node_modules/@comis/skills/dist/policy/tool-policy.js +0 -1
  104. package/node_modules/@comis/skills/package.json +1 -1
  105. package/node_modules/@comis/web/dist/assets/{agent-detail-ru-AhppM.js → agent-detail-DqL6Artv.js} +1 -1
  106. package/node_modules/@comis/web/dist/assets/{agent-editor-hjwRuFVp.js → agent-editor-CNM_h94Y.js} +1 -1
  107. package/node_modules/@comis/web/dist/assets/{agent-list-6Uotjatr.js → agent-list-Dbh-xD_F.js} +1 -1
  108. package/node_modules/@comis/web/dist/assets/{billing-view-CxysXH0p.js → billing-view-C1DmtyzK.js} +1 -1
  109. package/node_modules/@comis/web/dist/assets/{channel-detail-BBCKtmne.js → channel-detail-CtCH22N1.js} +1 -1
  110. package/node_modules/@comis/web/dist/assets/{channel-list-FkfeOLBQ.js → channel-list-C7xXn-60.js} +1 -1
  111. package/node_modules/@comis/web/dist/assets/{chat-console-BumBaIgO.js → chat-console-C51pjFwk.js} +1 -1
  112. package/node_modules/@comis/web/dist/assets/{config-editor-C9BSwHGy.js → config-editor-BLArYRB7.js} +1 -1
  113. package/node_modules/@comis/web/dist/assets/{context-dag-browser-BHm00mJD.js → context-dag-browser-fuyMinNI.js} +1 -1
  114. package/node_modules/@comis/web/dist/assets/{context-engine-BENY3pWE.js → context-engine-Bngf2bH0.js} +1 -1
  115. package/node_modules/@comis/web/dist/assets/{delivery-view-BCnkPsAp.js → delivery-view-C80hucxX.js} +1 -1
  116. package/node_modules/@comis/web/dist/assets/{diagnostics-view-C_jQFG2H.js → diagnostics-view-Cl4VbHZ6.js} +1 -1
  117. package/node_modules/@comis/web/dist/assets/{ic-chat-message-FdQcZsSQ.js → ic-chat-message-ByFUoMm6.js} +1 -1
  118. package/node_modules/@comis/web/dist/assets/{ic-connection-dot-BgYiK2N4.js → ic-connection-dot-C4nDHgY2.js} +1 -1
  119. package/node_modules/@comis/web/dist/assets/{ic-tool-call-DMPHsLyx.js → ic-tool-call-Bh5kq-yY.js} +1 -1
  120. package/node_modules/@comis/web/dist/assets/{index-FLPhHz8p.js → index-BBkuC-EU.js} +2 -2
  121. package/node_modules/@comis/web/dist/assets/{mcp-management-5jyScQis.js → mcp-management-DB-phOo7.js} +1 -1
  122. package/node_modules/@comis/web/dist/assets/{media-config-J9oT9PPs.js → media-config-CRqZ1ZUH.js} +1 -1
  123. package/node_modules/@comis/web/dist/assets/{media-test-DGTCtM8-.js → media-test-C9vE20Oy.js} +1 -1
  124. package/node_modules/@comis/web/dist/assets/{memory-inspector-D5Re9ptG.js → memory-inspector-CeqfnxMZ.js} +1 -1
  125. package/node_modules/@comis/web/dist/assets/{message-center-cRLK6ZmG.js → message-center-Daup7Mof.js} +1 -1
  126. package/node_modules/@comis/web/dist/assets/{models-D5vu07MR.js → models-DLYnEU8E.js} +1 -1
  127. package/node_modules/@comis/web/dist/assets/{observe-view-CalNNEmd.js → observe-view-BTSt_PO5.js} +1 -1
  128. package/node_modules/@comis/web/dist/assets/{pipeline-builder-DUYDGwZf.js → pipeline-builder-DknfzyLt.js} +1 -1
  129. package/node_modules/@comis/web/dist/assets/{pipeline-history-BAO8brOe.js → pipeline-history-JnHZdeU_.js} +1 -1
  130. package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-DectIoQt.js → pipeline-history-detail-Dg4knsEb.js} +1 -1
  131. package/node_modules/@comis/web/dist/assets/{pipeline-list-BHlaBKww.js → pipeline-list-AEnibjsp.js} +1 -1
  132. package/node_modules/@comis/web/dist/assets/{pipeline-monitor-BhtpNEHf.js → pipeline-monitor-DG7RbIOO.js} +1 -1
  133. package/node_modules/@comis/web/dist/assets/{scheduler-VafN_8xi.js → scheduler-uL1fYKAT.js} +1 -1
  134. package/node_modules/@comis/web/dist/assets/{security-QQXMRTlo.js → security-C3DywRLH.js} +1 -1
  135. package/node_modules/@comis/web/dist/assets/{session-detail-BpZ_8Yih.js → session-detail-BtqCNWXV.js} +1 -1
  136. package/node_modules/@comis/web/dist/assets/{session-list-DfCm8Cec.js → session-list-CJXWa2XT.js} +1 -1
  137. package/node_modules/@comis/web/dist/assets/{setup-wizard-C-z477CG.js → setup-wizard-ywn7oJvu.js} +1 -1
  138. package/node_modules/@comis/web/dist/assets/{skills-BCOGPf6s.js → skills-DX0KYnWD.js} +1 -1
  139. package/node_modules/@comis/web/dist/assets/{subagents-l-auUraL.js → subagents-B8p5YJEB.js} +1 -1
  140. package/node_modules/@comis/web/dist/assets/{workspace-manager-DlvBixiq.js → workspace-manager-CgzNIrw1.js} +1 -1
  141. package/node_modules/@comis/web/dist/index.html +1 -1
  142. package/node_modules/@comis/web/package.json +1 -1
  143. package/package.json +14 -14
  144. package/node_modules/@comis/skills/dist/builtin/platform/agents-list-tool.d.ts +0 -19
  145. package/node_modules/@comis/skills/dist/builtin/platform/agents-list-tool.js +0 -39
@@ -0,0 +1,330 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Provider management RPC handler module.
4
+ * Provides 7 handlers for runtime LLM provider management:
5
+ * providers.list - List all providers with summary and apiKeyConfigured state
6
+ * providers.get - Retrieve full provider config plus agentsUsing list
7
+ * providers.create - Register a new provider entry with validation
8
+ * providers.update - Patch an existing provider config with merge semantics
9
+ * providers.delete - Remove a provider (blocked if agents reference it)
10
+ * providers.enable - Set enabled:true on a disabled provider
11
+ * providers.disable - Set enabled:false (warns but does not block on references)
12
+ *
13
+ * Follows the same factory pattern as agent-handlers.ts. Each handler validates
14
+ * input, operates on the runtime providerEntries map, and returns structured results.
15
+ * API key values are NEVER exposed -- only apiKeyName references and apiKeyConfigured state.
16
+ * @module
17
+ */
18
+ import { ProviderEntrySchema } from "@comis/core";
19
+ import { persistToConfig } from "./persist-to-config.js";
20
+ import { probeProviderAuth } from "./probe-provider-auth.js";
21
+ // ---------------------------------------------------------------------------
22
+ // Helpers
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * Sweep all agents for references to a given provider across three slots:
26
+ * 1. Primary provider (agent.provider === providerId)
27
+ * 2. Fallback models (agent.modelFailover.fallbackModels[].provider)
28
+ * 3. Auth profiles (agent.modelFailover.authProfiles[].provider)
29
+ *
30
+ * Returns a structured breakdown of referencing agents by slot.
31
+ */
32
+ function findAgentReferences(agents, providerId) {
33
+ const primary = [];
34
+ const fallback = [];
35
+ const authProfile = [];
36
+ for (const [agentId, agent] of Object.entries(agents)) {
37
+ if (agent.provider === providerId) {
38
+ primary.push(agentId);
39
+ }
40
+ if (agent.modelFailover?.fallbackModels?.some((f) => f.provider === providerId)) {
41
+ fallback.push(agentId);
42
+ }
43
+ if (agent.modelFailover?.authProfiles?.some((a) => a.provider === providerId)) {
44
+ authProfile.push(agentId);
45
+ }
46
+ }
47
+ return { primary, fallback, authProfile };
48
+ }
49
+ /**
50
+ * Check whether any agent references exist across the three slots.
51
+ */
52
+ function hasAnyReferences(refs) {
53
+ return refs.primary.length > 0 || refs.fallback.length > 0 || refs.authProfile.length > 0;
54
+ }
55
+ /**
56
+ * Format agent references into a human-readable message.
57
+ */
58
+ function formatReferenceMessage(refs) {
59
+ const parts = [];
60
+ if (refs.primary.length > 0) {
61
+ parts.push(`primary provider: ${refs.primary.join(", ")}`);
62
+ }
63
+ if (refs.fallback.length > 0) {
64
+ parts.push(`fallbackModels: ${refs.fallback.join(", ")}`);
65
+ }
66
+ if (refs.authProfile.length > 0) {
67
+ parts.push(`authProfiles: ${refs.authProfile.join(", ")}`);
68
+ }
69
+ return parts.join("; ");
70
+ }
71
+ // ---------------------------------------------------------------------------
72
+ // Factory
73
+ // ---------------------------------------------------------------------------
74
+ /**
75
+ * Create a record of provider management RPC handlers bound to the given deps.
76
+ */
77
+ export function createProviderHandlers(deps) {
78
+ return {
79
+ "providers.list": async (params) => {
80
+ const trustLevel = params._trustLevel;
81
+ if (trustLevel !== "admin") {
82
+ throw new Error("Admin access required for provider listing");
83
+ }
84
+ const summaries = Object.entries(deps.providerEntries).map(([id, entry]) => ({
85
+ id,
86
+ type: entry.type,
87
+ name: entry.name,
88
+ enabled: entry.enabled,
89
+ baseUrl: entry.baseUrl,
90
+ apiKeyName: entry.apiKeyName,
91
+ modelCount: entry.models.length,
92
+ apiKeyConfigured: entry.apiKeyName
93
+ ? (deps.secretManager?.has(entry.apiKeyName) ?? false)
94
+ : null,
95
+ }));
96
+ return { providers: summaries };
97
+ },
98
+ "providers.get": async (params) => {
99
+ const trustLevel = params._trustLevel;
100
+ if (trustLevel !== "admin") {
101
+ throw new Error("Admin access required for provider retrieval");
102
+ }
103
+ const providerId = params.providerId;
104
+ if (!providerId) {
105
+ throw new Error("Missing required parameter: providerId");
106
+ }
107
+ const entry = deps.providerEntries[providerId];
108
+ if (entry === undefined) {
109
+ throw new Error(`Provider not found: ${providerId}`);
110
+ }
111
+ // Build agentsUsing list by scanning all three reference slots
112
+ const refs = findAgentReferences(deps.agents, providerId);
113
+ const agentsUsing = [
114
+ ...new Set([...refs.primary, ...refs.fallback, ...refs.authProfile]),
115
+ ];
116
+ return {
117
+ providerId,
118
+ config: {
119
+ type: entry.type,
120
+ name: entry.name,
121
+ baseUrl: entry.baseUrl,
122
+ apiKeyName: entry.apiKeyName,
123
+ enabled: entry.enabled,
124
+ timeoutMs: entry.timeoutMs,
125
+ maxRetries: entry.maxRetries,
126
+ headers: entry.headers,
127
+ capabilities: entry.capabilities,
128
+ models: entry.models,
129
+ },
130
+ apiKeyConfigured: entry.apiKeyName
131
+ ? (deps.secretManager?.has(entry.apiKeyName) ?? false)
132
+ : null,
133
+ agentsUsing,
134
+ };
135
+ },
136
+ "providers.create": async (params) => {
137
+ const trustLevel = params._trustLevel;
138
+ if (trustLevel !== "admin") {
139
+ throw new Error("Admin access required for provider creation");
140
+ }
141
+ const providerId = params.providerId;
142
+ if (!providerId) {
143
+ throw new Error("Missing required parameter: providerId");
144
+ }
145
+ // Reserved name check -- "default" collides with PerAgentConfig.provider schema default
146
+ if (providerId === "default") {
147
+ throw new Error('Provider ID "default" is reserved. The name "default" collides with the agent schema default -- ' +
148
+ "every agent that never set its provider explicitly would match this entry. " +
149
+ "Choose a descriptive name instead (e.g., 'my-ollama', 'nvidia-nim', 'groq-cloud').");
150
+ }
151
+ if (deps.providerEntries[providerId] !== undefined) {
152
+ throw new Error(`Provider already exists: ${providerId}`);
153
+ }
154
+ const config = params.config ?? {};
155
+ const parsedConfig = ProviderEntrySchema.parse(config);
156
+ // Probe provider API key before committing config
157
+ if (parsedConfig.apiKeyName && deps.secretManager) {
158
+ const apiKey = deps.secretManager.get(parsedConfig.apiKeyName);
159
+ if (apiKey) {
160
+ const probeResult = await probeProviderAuth(parsedConfig.baseUrl, apiKey, parsedConfig.models[0]?.id);
161
+ if (!probeResult.ok) {
162
+ throw new Error(`Provider "${providerId}" API key validation failed: ${probeResult.error}`);
163
+ }
164
+ }
165
+ }
166
+ deps.providerEntries[providerId] = parsedConfig;
167
+ // Best-effort persistence to config.yaml
168
+ if (deps.persistDeps) {
169
+ const ctx = params._context;
170
+ const persistResult = await persistToConfig(deps.persistDeps, {
171
+ patch: { providers: { entries: { [providerId]: config } } },
172
+ actionType: "providers.create",
173
+ entityId: providerId,
174
+ actingUser: ctx?.userId ?? params._agentId,
175
+ traceId: ctx?.traceId ?? params._traceId,
176
+ });
177
+ if (!persistResult.ok) {
178
+ deps.persistDeps.logger.warn({ method: "providers.create", providerId, err: persistResult.error, hint: "Provider created in memory but config persistence failed", errorKind: "config" }, "Provider config persistence failed");
179
+ }
180
+ }
181
+ return { providerId, config: parsedConfig, created: true };
182
+ },
183
+ "providers.update": async (params) => {
184
+ const trustLevel = params._trustLevel;
185
+ if (trustLevel !== "admin") {
186
+ throw new Error("Admin access required for provider modification");
187
+ }
188
+ const providerId = params.providerId;
189
+ if (!providerId) {
190
+ throw new Error("Missing required parameter: providerId");
191
+ }
192
+ const existing = deps.providerEntries[providerId];
193
+ if (existing === undefined) {
194
+ throw new Error(`Provider not found: ${providerId}`);
195
+ }
196
+ const config = params.config ?? {};
197
+ // Capture user-provided fields BEFORE merge -- persistToConfig does deepMerge internally,
198
+ // so we only persist the user's partial patch (not the fully merged config).
199
+ const userPatch = params.config ? structuredClone(params.config) : {};
200
+ // Headers: shallow merge per-key (preserve existing keys, overlay new ones)
201
+ if (config.headers && existing.headers) {
202
+ config.headers = { ...existing.headers, ...config.headers };
203
+ }
204
+ // models[] and capabilities: replaced wholesale via spread (no merge needed)
205
+ const merged = { ...existing, ...config };
206
+ const parsedConfig = ProviderEntrySchema.parse(merged);
207
+ deps.providerEntries[providerId] = parsedConfig;
208
+ // Best-effort persistence to config.yaml -- persist userPatch NOT merged config
209
+ if (deps.persistDeps) {
210
+ const ctx = params._context;
211
+ const persistResult = await persistToConfig(deps.persistDeps, {
212
+ patch: { providers: { entries: { [providerId]: userPatch } } },
213
+ actionType: "providers.update",
214
+ entityId: providerId,
215
+ actingUser: ctx?.userId ?? params._agentId,
216
+ traceId: ctx?.traceId ?? params._traceId,
217
+ });
218
+ if (!persistResult.ok) {
219
+ deps.persistDeps.logger.warn({ method: "providers.update", providerId, err: persistResult.error, hint: "Provider updated in memory but config persistence failed", errorKind: "config" }, "Provider config persistence failed");
220
+ }
221
+ }
222
+ return { providerId, config: parsedConfig, updated: true };
223
+ },
224
+ "providers.delete": async (params) => {
225
+ const trustLevel = params._trustLevel;
226
+ if (trustLevel !== "admin") {
227
+ throw new Error("Admin access required for provider deletion");
228
+ }
229
+ const providerId = params.providerId;
230
+ if (!providerId) {
231
+ throw new Error("Missing required parameter: providerId");
232
+ }
233
+ const existing = deps.providerEntries[providerId];
234
+ if (existing === undefined) {
235
+ throw new Error(`Provider not found: ${providerId}`);
236
+ }
237
+ // Three-slot reference check: block deletion if any agent references this provider
238
+ const refs = findAgentReferences(deps.agents, providerId);
239
+ if (hasAnyReferences(refs)) {
240
+ throw new Error(`Cannot delete provider "${providerId}": referenced by agents -- ${formatReferenceMessage(refs)}. ` +
241
+ "Remove agent references first, then retry deletion.");
242
+ }
243
+ delete deps.providerEntries[providerId];
244
+ // Best-effort persistence with removePaths
245
+ if (deps.persistDeps) {
246
+ const ctx = params._context;
247
+ const persistResult = await persistToConfig(deps.persistDeps, {
248
+ patch: {},
249
+ removePaths: [["providers", "entries", providerId]],
250
+ actionType: "providers.delete",
251
+ entityId: providerId,
252
+ actingUser: ctx?.userId ?? params._agentId,
253
+ traceId: ctx?.traceId ?? params._traceId,
254
+ });
255
+ if (!persistResult.ok) {
256
+ deps.persistDeps.logger.warn({ method: "providers.delete", providerId, err: persistResult.error, hint: "Provider deleted in memory but config persistence failed", errorKind: "config" }, "Provider config persistence failed");
257
+ }
258
+ }
259
+ return { providerId, deleted: true };
260
+ },
261
+ "providers.enable": async (params) => {
262
+ const trustLevel = params._trustLevel;
263
+ if (trustLevel !== "admin") {
264
+ throw new Error("Admin access required for provider enable");
265
+ }
266
+ const providerId = params.providerId;
267
+ if (!providerId) {
268
+ throw new Error("Missing required parameter: providerId");
269
+ }
270
+ const existing = deps.providerEntries[providerId];
271
+ if (existing === undefined) {
272
+ throw new Error(`Provider not found: ${providerId}`);
273
+ }
274
+ deps.providerEntries[providerId].enabled = true;
275
+ // Best-effort persistence
276
+ if (deps.persistDeps) {
277
+ const ctx = params._context;
278
+ const persistResult = await persistToConfig(deps.persistDeps, {
279
+ patch: { providers: { entries: { [providerId]: { enabled: true } } } },
280
+ actionType: "providers.enable",
281
+ entityId: providerId,
282
+ actingUser: ctx?.userId ?? params._agentId,
283
+ traceId: ctx?.traceId ?? params._traceId,
284
+ });
285
+ if (!persistResult.ok) {
286
+ deps.persistDeps.logger.warn({ method: "providers.enable", providerId, err: persistResult.error, hint: "Provider enabled in memory but config persistence failed", errorKind: "config" }, "Provider config persistence failed");
287
+ }
288
+ }
289
+ return { providerId, enabled: true };
290
+ },
291
+ "providers.disable": async (params) => {
292
+ const trustLevel = params._trustLevel;
293
+ if (trustLevel !== "admin") {
294
+ throw new Error("Admin access required for provider disable");
295
+ }
296
+ const providerId = params.providerId;
297
+ if (!providerId) {
298
+ throw new Error("Missing required parameter: providerId");
299
+ }
300
+ const existing = deps.providerEntries[providerId];
301
+ if (existing === undefined) {
302
+ throw new Error(`Provider not found: ${providerId}`);
303
+ }
304
+ // Three-slot reference sweep: warn but do NOT reject
305
+ const refs = findAgentReferences(deps.agents, providerId);
306
+ let warning;
307
+ if (hasAnyReferences(refs)) {
308
+ warning =
309
+ `Provider "${providerId}" is referenced by agents (${formatReferenceMessage(refs)}). ` +
310
+ "Disabling will prevent these agents from using this provider until re-enabled.";
311
+ }
312
+ deps.providerEntries[providerId].enabled = false;
313
+ // Best-effort persistence
314
+ if (deps.persistDeps) {
315
+ const ctx = params._context;
316
+ const persistResult = await persistToConfig(deps.persistDeps, {
317
+ patch: { providers: { entries: { [providerId]: { enabled: false } } } },
318
+ actionType: "providers.disable",
319
+ entityId: providerId,
320
+ actingUser: ctx?.userId ?? params._agentId,
321
+ traceId: ctx?.traceId ?? params._traceId,
322
+ });
323
+ if (!persistResult.ok) {
324
+ deps.persistDeps.logger.warn({ method: "providers.disable", providerId, err: persistResult.error, hint: "Provider disabled in memory but config persistence failed", errorKind: "config" }, "Provider config persistence failed");
325
+ }
326
+ }
327
+ return { providerId, enabled: false, ...(warning ? { warning } : {}) };
328
+ },
329
+ };
330
+ }
@@ -30,6 +30,7 @@ import { createHeartbeatHandlers } from "./heartbeat-handlers.js";
30
30
  import { createSkillHandlers } from "./skill-handlers.js";
31
31
  import { createNotificationHandlers } from "./notification-handlers.js";
32
32
  import { createImageHandlers } from "./image-handlers.js";
33
+ import { createProviderHandlers } from "./provider-handlers.js";
33
34
  // ---------------------------------------------------------------------------
34
35
  // Error classification
35
36
  // ---------------------------------------------------------------------------
@@ -88,6 +89,19 @@ export function createRpcDispatch(deps) {
88
89
  ...createAgentHandlers({
89
90
  ...deps,
90
91
  secretManager: deps.container?.secretManager,
92
+ providerEntries: deps.container.config.providers.entries,
93
+ persistDeps: {
94
+ container: deps.container,
95
+ configPaths: deps.configPaths,
96
+ defaultConfigPaths: deps.defaultConfigPaths,
97
+ configGitManager: deps.configGitManager,
98
+ logger: deps.logger,
99
+ },
100
+ }),
101
+ ...createProviderHandlers({
102
+ agents: deps.agents,
103
+ providerEntries: deps.container.config.providers.entries,
104
+ secretManager: deps.container?.secretManager,
91
105
  persistDeps: {
92
106
  container: deps.container,
93
107
  configPaths: deps.configPaths,
@@ -97,7 +111,10 @@ export function createRpcDispatch(deps) {
97
111
  },
98
112
  }),
99
113
  ...createObsHandlers(deps),
100
- ...createModelHandlers(deps),
114
+ ...createModelHandlers({
115
+ ...deps,
116
+ providerEntries: deps.container.config.providers.entries,
117
+ }),
101
118
  ...createChannelHandlers({
102
119
  ...deps,
103
120
  persistDeps: {
@@ -0,0 +1,4 @@
1
+ import type { ComisLogger } from "@comis/infra";
2
+ export declare function emitDockerRestartPolicyWarn(logger: ComisLogger, opts?: {
3
+ isDocker?: () => boolean;
4
+ }): void;
@@ -0,0 +1,30 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Boot-time WARN that fires inside Docker containers, telling the operator
4
+ * that wizard "Restart" actions and any `gateway.*` config-reload action
5
+ * (`gateway.restart`, `gateway.env_set`, `gateway.patch` on restart-triggering
6
+ * paths) all rely on the container's restart policy to bring the daemon back.
7
+ *
8
+ * Without `--restart unless-stopped` (or compose `restart: unless-stopped`)
9
+ * the container exits and stays exited the first time the user clicks
10
+ * "Restart" in the wizard, producing a silent "comis status: offline" with
11
+ * no breadcrumb in `docker logs` pointing at the missing flag. This WARN
12
+ * is that breadcrumb.
13
+ *
14
+ * Pure function over an injected logger and an optional `isDocker` probe
15
+ * (defaulting to the real one from `@comis/infra`) so it is unit-testable
16
+ * without spinning up the daemon harness.
17
+ *
18
+ * @module
19
+ */
20
+ import { isDocker as defaultIsDocker } from "@comis/infra";
21
+ export function emitDockerRestartPolicyWarn(logger, opts = {}) {
22
+ const probe = opts.isDocker ?? defaultIsDocker;
23
+ if (!probe())
24
+ return;
25
+ logger.warn({
26
+ hint: "Wizard 'Restart' actions, gateway.restart, gateway.env_set, and gateway.patch on restart-triggering paths all require the container to have --restart unless-stopped (or compose restart: unless-stopped). Verify from your host with: docker inspect <name> --format '{{.HostConfig.RestartPolicy.Name}}'",
27
+ errorKind: "config",
28
+ module: "daemon",
29
+ }, "Running in Docker — restart policy required for config-reload operations");
30
+ }
@@ -8,7 +8,7 @@
8
8
  import { type AppContainer, type InjectionRateLimiter, type PerAgentConfig } from "@comis/core";
9
9
  import type { ComisLogger } from "@comis/infra";
10
10
  import type { SqliteMemoryAdapter, createSessionStore } from "@comis/memory";
11
- import { createBudgetGuard, createCostTracker, createStepCounter, createSessionLifecycle, createComisSessionManager, type AgentExecutor, type ActiveRunRegistry, type ProviderHealthMonitor } from "@comis/agent";
11
+ import { createBudgetGuard, createCostTracker, createStepCounter, createSessionLifecycle, createComisSessionManager, type AgentExecutor, type ActiveRunRegistry, type ProviderHealthMonitor, type LastKnownModelTracker } from "@comis/agent";
12
12
  import { type SkillRegistry, type SkillWatcherHandle } from "@comis/skills";
13
13
  type PiSessionAdapter = ReturnType<typeof createComisSessionManager>;
14
14
  /** Shared dependencies computed once before the agent loop and passed to each
@@ -39,6 +39,8 @@ export interface SingleAgentDeps {
39
39
  db?: unknown;
40
40
  /** Global provider health monitor shared across all agents */
41
41
  providerHealth?: ProviderHealthMonitor;
42
+ /** Global last-known-working model tracker shared across all agents */
43
+ lastKnownModel?: LastKnownModelTracker;
42
44
  /** Optional embedding port for discover_tools semantic search. */
43
45
  embeddingPort?: import("@comis/core").EmbeddingPort;
44
46
  /** Delivery mirror port for session mirroring injection */
@@ -12,7 +12,7 @@ import { createHmac } from "node:crypto";
12
12
  import { homedir } from "node:os";
13
13
  import { existsSync, mkdirSync } from "node:fs";
14
14
  import { isAbsolute, resolve } from "node:path";
15
- import { createCircuitBreaker, createBudgetGuard, createCostTracker, createStepCounter, createSessionLifecycle, ensureWorkspace, resolveWorkspaceDir, createPiExecutor, createComisSessionManager, cleanupStaleLocks, createAuthStorageAdapter, createModelRegistryAdapter, registerCustomProviders, createProviderHealthMonitor, setSanitizeLogger, setToolNormalizationLogger, LEAN_TOOL_DESCRIPTIONS, resolveDescription, } from "@comis/agent";
15
+ import { createCircuitBreaker, createBudgetGuard, createCostTracker, createStepCounter, createSessionLifecycle, ensureWorkspace, resolveWorkspaceDir, createPiExecutor, createComisSessionManager, cleanupStaleLocks, createAuthStorageAdapter, createModelRegistryAdapter, registerCustomProviders, createProviderHealthMonitor, createLastKnownModelTracker, createAuthProfileManager, createAuthRotationAdapter, setSanitizeLogger, setToolNormalizationLogger, LEAN_TOOL_DESCRIPTIONS, resolveDescription, } from "@comis/agent";
16
16
  import { agentToolsToToolDefinitions, createSkillRegistry, createRuntimeEligibilityContext, TOOL_PROFILES, } from "@comis/skills";
17
17
  // ---------------------------------------------------------------------------
18
18
  // Single-agent setup (extracted for hot-add reuse)
@@ -71,10 +71,13 @@ export async function setupSingleAgent(agentId, rawAgentConfig, deps) {
71
71
  customProviderEntries,
72
72
  });
73
73
  const piModelRegistry = createModelRegistryAdapter(piAuthStorage);
74
- const customProviderCount = registerCustomProviders(piModelRegistry, customProviderEntries, scopedManager, agentLogger);
74
+ const { registered: customProviderCount, providerAliases } = registerCustomProviders(piModelRegistry, customProviderEntries, scopedManager, agentLogger);
75
75
  if (customProviderCount > 0) {
76
76
  agentLogger.debug({ agentId, customProviderCount }, "Custom YAML providers registered with pi ModelRegistry");
77
77
  }
78
+ if (providerAliases.size > 0) {
79
+ agentLogger.debug({ agentId, aliases: Object.fromEntries(providerAliases) }, "Provider name aliases for built-in resolution");
80
+ }
78
81
  // Create JSONL session adapter for this agent
79
82
  const lockDir = safePath(dir, ".locks");
80
83
  const sessionAdapter = createComisSessionManager({
@@ -172,9 +175,26 @@ export async function setupSingleAgent(agentId, rawAgentConfig, deps) {
172
175
  // No wrapWithAudit: PiEventBridge already emits tool:executed for ALL tools.
173
176
  // tools: [] -- all tools come exclusively through customTools where the full
174
177
  // Comis security pipeline (safePath + tool policy + audit) is enforced.
178
+ // Model failover: convert config FallbackModel[] to "provider:modelId" strings
179
+ // and create auth rotation adapter for multi-key providers.
180
+ const failoverConfig = effectiveConfig.modelFailover;
181
+ const fallbackModelStrings = failoverConfig.fallbackModels.map((m) => `${m.provider}:${m.modelId}`);
182
+ const authProfileManager = failoverConfig.authProfiles.length > 0
183
+ ? createAuthProfileManager({
184
+ profiles: failoverConfig.authProfiles,
185
+ secretManager: scopedManager,
186
+ initialMs: failoverConfig.cooldownInitialMs,
187
+ multiplier: failoverConfig.cooldownMultiplier,
188
+ capMs: failoverConfig.cooldownCapMs,
189
+ })
190
+ : undefined;
191
+ const authRotation = authProfileManager
192
+ ? createAuthRotationAdapter({ authStorage: piAuthStorage, profileManager: authProfileManager })
193
+ : undefined;
175
194
  const executor = createPiExecutor(effectiveConfig, {
176
195
  circuitBreaker,
177
196
  providerHealth: deps.providerHealth,
197
+ lastKnownModel: deps.lastKnownModel,
178
198
  budgetGuard,
179
199
  costTracker,
180
200
  stepCounter,
@@ -182,6 +202,9 @@ export async function setupSingleAgent(agentId, rawAgentConfig, deps) {
182
202
  logger: perAgentLogger,
183
203
  authStorage: piAuthStorage,
184
204
  modelRegistry: piModelRegistry,
205
+ providerAliases,
206
+ fallbackModels: fallbackModelStrings.length > 0 ? fallbackModelStrings : undefined,
207
+ authRotation,
185
208
  sessionAdapter,
186
209
  workspaceDir: dir,
187
210
  agentDir: resolvedAgentDir,
@@ -309,6 +332,8 @@ export async function setupAgents(deps) {
309
332
  recoveryThreshold: 1,
310
333
  eventBus: container.eventBus,
311
334
  });
335
+ // Global last-known-working model tracker (shared across all agents)
336
+ const lastKnownModel = createLastKnownModelTracker();
312
337
  // Construct shared deps struct once before the loop (for hot-add reuse)
313
338
  const singleAgentDeps = {
314
339
  container,
@@ -328,6 +353,7 @@ export async function setupAgents(deps) {
328
353
  contextStore: deps.contextStore,
329
354
  db: deps.db,
330
355
  providerHealth,
356
+ lastKnownModel,
331
357
  embeddingPort: deps.embeddingPort,
332
358
  deliveryMirror: deps.deliveryMirror,
333
359
  deliveryMirrorConfig: deps.deliveryMirrorConfig,
@@ -53,6 +53,7 @@ export const SUB_AGENT_TOOL_DENYLIST = new Set([
53
53
  "channels_manage", // channels.restart, config.patch -> SIGUSR2
54
54
  "agents_manage", // agent create/delete -> config persistence -> SIGUSR2
55
55
  "models_manage", // model config changes -> config persistence -> SIGUSR2
56
+ "providers_manage", // provider CRUD -> config persistence -> SIGUSR2
56
57
  "tokens_manage", // token CRUD -> config persistence -> SIGUSR2
57
58
  "skills_manage", // skill config changes -> config persistence -> potential SIGUSR2
58
59
  "sessions_manage", // session purge is destructive
@@ -11,7 +11,7 @@ import { enterConfigMutationFence, leaveConfigMutationFence } from "../rpc/persi
11
11
  import { SkillsConfigSchema, sanitizeLogString, tryGetContext, parseFormattedSessionKey, safePath, formatSessionKey } from "@comis/core";
12
12
  import { sessionKeyToPath, WORKSPACE_FILE_NAMES, DEFAULT_TEMPLATES, registerWorkspaceFilesInTracker, } from "@comis/agent";
13
13
  import { stat as fsStat } from "node:fs/promises";
14
- import { assembleToolPipeline, createFileStateTracker, createCronTool, createUnifiedMemoryTool, createUnifiedSessionTool, createUnifiedContextTool, createAgentsListTool, createMessageTool, createDiscordActionTool, createTelegramActionTool, createSlackActionTool, createWhatsAppActionTool, createSessionsSendTool, createSessionsSpawnTool, createSubagentsTool, createPipelineTool, createImageTool, createTTSTool, createTranscribeAudioTool, createDescribeVideoTool, createExtractDocumentTool, createGatewayTool, createBrowserTool, createAgentsManageTool, createObsQueryTool, createSessionsManageTool, createModelsManageTool, createTokensManageTool, createChannelsManageTool, createSkillsManageTool, createMcpManageTool, createHeartbeatManageTool, createNotifyTool, createImageGenerateTool, createBackgroundTasksTool, createExecTool, createProcessTool, createProcessRegistry, createApplyPatchTool, sanitizeImageForApi, createMediaPersistenceService, createCredentialInjector, mcpToolsToAgentTools, TOOL_PROFILES, TOOL_GROUPS, } from "@comis/skills";
14
+ import { assembleToolPipeline, createFileStateTracker, createCronTool, createUnifiedMemoryTool, createUnifiedSessionTool, createUnifiedContextTool, createMessageTool, createDiscordActionTool, createTelegramActionTool, createSlackActionTool, createWhatsAppActionTool, createSessionsSendTool, createSessionsSpawnTool, createSubagentsTool, createPipelineTool, createImageTool, createTTSTool, createTranscribeAudioTool, createDescribeVideoTool, createExtractDocumentTool, createGatewayTool, createBrowserTool, createAgentsManageTool, createObsQueryTool, createSessionsManageTool, createModelsManageTool, createTokensManageTool, createChannelsManageTool, createSkillsManageTool, createMcpManageTool, createHeartbeatManageTool, createProvidersManageTool, createNotifyTool, createImageGenerateTool, createBackgroundTasksTool, createExecTool, createProcessTool, createProcessRegistry, createApplyPatchTool, sanitizeImageForApi, createMediaPersistenceService, createCredentialInjector, mcpToolsToAgentTools, TOOL_PROFILES, TOOL_GROUPS, } from "@comis/skills";
15
15
  // ---------------------------------------------------------------------------
16
16
  // Setup function
17
17
  // ---------------------------------------------------------------------------
@@ -154,7 +154,6 @@ export function setupTools(deps) {
154
154
  createCronTool(agentRpc),
155
155
  createUnifiedMemoryTool(agentRpc, approvalGate),
156
156
  createUnifiedSessionTool(agentRpc),
157
- createAgentsListTool(agentRpc),
158
157
  createMessageTool(agentRpc),
159
158
  createDiscordActionTool(agentRpc, skillsLogger),
160
159
  createTelegramActionTool(agentRpc),
@@ -169,8 +168,8 @@ export function setupTools(deps) {
169
168
  createTranscribeAudioTool(agentRpc),
170
169
  createDescribeVideoTool(agentRpc),
171
170
  createExtractDocumentTool(agentRpc),
172
- createGatewayTool(agentRpc),
173
- createAgentsManageTool(agentRpc, approvalGate, {
171
+ createGatewayTool(agentRpc, skillsLogger),
172
+ createAgentsManageTool(agentRpc, skillsLogger, approvalGate, {
174
173
  onMutationStart: enterConfigMutationFence,
175
174
  onMutationEnd: leaveConfigMutationFence,
176
175
  // After agents.create seeds the new workspace's template files
@@ -204,6 +203,10 @@ export function setupTools(deps) {
204
203
  createObsQueryTool(agentRpc),
205
204
  createSessionsManageTool(agentRpc, approvalGate),
206
205
  createModelsManageTool(agentRpc),
206
+ createProvidersManageTool(agentRpc, approvalGate, {
207
+ onMutationStart: enterConfigMutationFence,
208
+ onMutationEnd: leaveConfigMutationFence,
209
+ }),
207
210
  createTokensManageTool(agentRpc, approvalGate),
208
211
  createChannelsManageTool(agentRpc, approvalGate),
209
212
  createSkillsManageTool(agentRpc, approvalGate),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/daemon",
3
3
  "private": true,
4
- "version": "1.0.25",
4
+ "version": "1.0.27",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Background daemon and orchestrator for the Comis platform",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/gateway",
3
3
  "private": true,
4
- "version": "1.0.25",
4
+ "version": "1.0.27",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "HTTP, JSON-RPC, and WebSocket gateway for Comis",
@@ -2,3 +2,4 @@ export { createLogger } from "./logging/index.js";
2
2
  export type { LoggerOptions, ComisLogger } from "./logging/index.js";
3
3
  export type { LogFields, ErrorKind } from "./logging/index.js";
4
4
  export { isValidLogLevel, VALID_LOG_LEVELS } from "./logging/index.js";
5
+ export { isDocker } from "./runtime/is-docker.js";
@@ -3,3 +3,5 @@
3
3
  // Logging (Pino logger factory with credential redaction, audit level)
4
4
  export { createLogger } from "./logging/index.js";
5
5
  export { isValidLogLevel, VALID_LOG_LEVELS } from "./logging/index.js";
6
+ // Runtime detection helpers (single source of truth for Docker/PID-1 probes)
7
+ export { isDocker } from "./runtime/is-docker.js";
@@ -0,0 +1 @@
1
+ export declare function isDocker(): boolean;
@@ -0,0 +1,25 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Detect whether we are running inside a Docker container.
4
+ *
5
+ * Probes `/.dockerenv`, the standard marker file Docker creates at PID 1's
6
+ * filesystem root. Used by callers that need to surface restart-policy
7
+ * guidance: inside a container the daemon is owned by PID 1 (dumb-init in
8
+ * the official image), so signalling it exits the container — Docker's
9
+ * restart policy is what brings it back. Without `--restart unless-stopped`
10
+ * (or compose `restart: unless-stopped`) the container stays exited.
11
+ *
12
+ * Defensive: any probe error returns false. We never throw out of a runtime
13
+ * detection helper.
14
+ *
15
+ * @module
16
+ */
17
+ import { existsSync } from "node:fs";
18
+ export function isDocker() {
19
+ try {
20
+ return existsSync("/.dockerenv");
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/infra",
3
3
  "private": true,
4
- "version": "1.0.25",
4
+ "version": "1.0.27",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Structured logging infrastructure for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/memory",
3
3
  "private": true,
4
- "version": "1.0.25",
4
+ "version": "1.0.27",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "SQLite memory, embeddings, and RAG storage for Comis agents",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/scheduler",
3
3
  "private": true,
4
- "version": "1.0.25",
4
+ "version": "1.0.27",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Task scheduling and cron management for Comis",