comisai 1.0.25 → 1.0.26
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.
- package/node_modules/@comis/agent/dist/bootstrap/sections/tool-descriptions.js +130 -10
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.d.ts +1 -1
- package/node_modules/@comis/agent/dist/bootstrap/sections/tooling-sections.js +9 -2
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.d.ts +8 -0
- package/node_modules/@comis/agent/dist/bridge/bridge-metrics.js +2 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.d.ts +29 -0
- package/node_modules/@comis/agent/dist/bridge/pi-event-bridge.js +242 -2
- package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.d.ts +210 -0
- package/node_modules/@comis/agent/dist/bridge/thinking-block-hash-invariant.js +566 -0
- package/node_modules/@comis/agent/dist/context-engine/context-engine.js +8 -6
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.d.ts +51 -30
- package/node_modules/@comis/agent/dist/context-engine/signature-replay-scrubber.js +109 -36
- package/node_modules/@comis/agent/dist/executor/executor-context-engine-setup.js +5 -1
- package/node_modules/@comis/agent/dist/executor/executor-post-execution.js +22 -20
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.d.ts +2 -0
- package/node_modules/@comis/agent/dist/executor/executor-prompt-runner.js +111 -15
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.d.ts +20 -17
- package/node_modules/@comis/agent/dist/executor/executor-response-filter.js +132 -52
- package/node_modules/@comis/agent/dist/executor/executor-tool-assembly.js +16 -3
- package/node_modules/@comis/agent/dist/executor/model-retry.d.ts +14 -0
- package/node_modules/@comis/agent/dist/executor/model-retry.js +72 -1
- package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +3 -0
- package/node_modules/@comis/agent/dist/executor/pi-executor.js +68 -9
- package/node_modules/@comis/agent/dist/executor/post-batch-continuation.d.ts +82 -0
- package/node_modules/@comis/agent/dist/executor/post-batch-continuation.js +200 -0
- package/node_modules/@comis/agent/dist/executor/stream-wrappers/request-body-injector.js +1 -9
- package/node_modules/@comis/agent/dist/executor/tool-deferral.d.ts +37 -2
- package/node_modules/@comis/agent/dist/executor/tool-deferral.js +45 -3
- package/node_modules/@comis/agent/dist/executor/tool-parallelism.js +0 -1
- package/node_modules/@comis/agent/dist/executor/types.d.ts +11 -2
- package/node_modules/@comis/agent/dist/index.d.ts +3 -1
- package/node_modules/@comis/agent/dist/index.js +2 -0
- package/node_modules/@comis/agent/dist/model/last-known-model.d.ts +36 -0
- package/node_modules/@comis/agent/dist/model/last-known-model.js +49 -0
- package/node_modules/@comis/agent/dist/model/model-registry-adapter.d.ts +16 -4
- package/node_modules/@comis/agent/dist/model/model-registry-adapter.js +65 -21
- package/node_modules/@comis/agent/dist/planner/types.d.ts +0 -2
- package/node_modules/@comis/agent/dist/session/comis-session-manager.d.ts +10 -0
- package/node_modules/@comis/agent/dist/session/comis-session-manager.js +5 -0
- package/node_modules/@comis/agent/dist/spawn/pi-mono-adapters.js +7 -0
- package/node_modules/@comis/agent/package.json +1 -1
- package/node_modules/@comis/channels/package.json +1 -1
- package/node_modules/@comis/cli/dist/client/rpc-client.js +6 -1
- package/node_modules/@comis/cli/dist/commands/doctor.js +5 -3
- package/node_modules/@comis/cli/dist/commands/health.js +5 -2
- package/node_modules/@comis/cli/dist/wizard/json-output.js +7 -3
- package/node_modules/@comis/cli/dist/wizard/steps/11-daemon-start.js +130 -0
- package/node_modules/@comis/cli/package.json +1 -1
- package/node_modules/@comis/core/dist/config/immutable-keys.d.ts +2 -2
- package/node_modules/@comis/core/dist/config/immutable-keys.js +8 -3
- package/node_modules/@comis/core/dist/config/managed-sections.d.ts +43 -4
- package/node_modules/@comis/core/dist/config/managed-sections.js +100 -6
- package/node_modules/@comis/core/dist/config/schema-agent.d.ts +39 -0
- package/node_modules/@comis/core/dist/config/schema-agent.js +14 -0
- package/node_modules/@comis/core/dist/config/schema.d.ts +4 -0
- package/node_modules/@comis/core/dist/config/schema.js +14 -0
- package/node_modules/@comis/core/dist/domain/execution-graph.d.ts +1 -1
- package/node_modules/@comis/core/dist/event-bus/events-agent.d.ts +17 -2
- package/node_modules/@comis/core/dist/exports/config.d.ts +2 -2
- package/node_modules/@comis/core/dist/exports/config.js +1 -1
- package/node_modules/@comis/core/package.json +1 -1
- package/node_modules/@comis/daemon/dist/daemon.d.ts +22 -0
- package/node_modules/@comis/daemon/dist/daemon.js +42 -0
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.d.ts +5 -2
- package/node_modules/@comis/daemon/dist/rpc/agent-handlers.js +80 -1
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.d.ts +67 -0
- package/node_modules/@comis/daemon/dist/rpc/agent-inline-workspace.js +139 -0
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.d.ts +3 -0
- package/node_modules/@comis/daemon/dist/rpc/model-handlers.js +29 -5
- package/node_modules/@comis/daemon/dist/rpc/probe-provider-auth.d.ts +30 -0
- package/node_modules/@comis/daemon/dist/rpc/probe-provider-auth.js +59 -0
- package/node_modules/@comis/daemon/dist/rpc/provider-handlers.d.ts +37 -0
- package/node_modules/@comis/daemon/dist/rpc/provider-handlers.js +330 -0
- package/node_modules/@comis/daemon/dist/rpc/rpc-dispatch.js +18 -1
- package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.d.ts +4 -0
- package/node_modules/@comis/daemon/dist/setup-docker-restart-warn.js +30 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.d.ts +3 -1
- package/node_modules/@comis/daemon/dist/wiring/setup-agents.js +28 -2
- package/node_modules/@comis/daemon/dist/wiring/setup-cross-session.js +1 -0
- package/node_modules/@comis/daemon/dist/wiring/setup-tools.js +7 -4
- package/node_modules/@comis/daemon/package.json +1 -1
- package/node_modules/@comis/gateway/package.json +1 -1
- package/node_modules/@comis/infra/dist/index.d.ts +1 -0
- package/node_modules/@comis/infra/dist/index.js +2 -0
- package/node_modules/@comis/infra/dist/runtime/is-docker.d.ts +1 -0
- package/node_modules/@comis/infra/dist/runtime/is-docker.js +25 -0
- package/node_modules/@comis/infra/package.json +1 -1
- package/node_modules/@comis/memory/package.json +1 -1
- package/node_modules/@comis/scheduler/package.json +1 -1
- package/node_modules/@comis/shared/package.json +1 -1
- package/node_modules/@comis/skills/dist/bridge/tool-metadata-registry.js +1 -3
- package/node_modules/@comis/skills/dist/builtin/platform/admin-manage-factory.js +24 -1
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.d.ts +53 -7
- package/node_modules/@comis/skills/dist/builtin/platform/agents-manage-tool.js +218 -24
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +4 -1
- package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.js +16 -1
- package/node_modules/@comis/skills/dist/builtin/platform/index.d.ts +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/index.js +1 -1
- package/node_modules/@comis/skills/dist/builtin/platform/providers-manage-tool.d.ts +56 -0
- package/node_modules/@comis/skills/dist/builtin/platform/providers-manage-tool.js +203 -0
- package/node_modules/@comis/skills/dist/index.d.ts +1 -1
- package/node_modules/@comis/skills/dist/index.js +2 -2
- package/node_modules/@comis/skills/dist/policy/tool-policy.js +0 -1
- package/node_modules/@comis/skills/package.json +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-detail-ru-AhppM.js → agent-detail-DqL6Artv.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-editor-hjwRuFVp.js → agent-editor-CNM_h94Y.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{agent-list-6Uotjatr.js → agent-list-Dbh-xD_F.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{billing-view-CxysXH0p.js → billing-view-C1DmtyzK.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-detail-BBCKtmne.js → channel-detail-CtCH22N1.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{channel-list-FkfeOLBQ.js → channel-list-C7xXn-60.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{chat-console-BumBaIgO.js → chat-console-C51pjFwk.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{config-editor-C9BSwHGy.js → config-editor-BLArYRB7.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-dag-browser-BHm00mJD.js → context-dag-browser-fuyMinNI.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{context-engine-BENY3pWE.js → context-engine-Bngf2bH0.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{delivery-view-BCnkPsAp.js → delivery-view-C80hucxX.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{diagnostics-view-C_jQFG2H.js → diagnostics-view-Cl4VbHZ6.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-chat-message-FdQcZsSQ.js → ic-chat-message-ByFUoMm6.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-connection-dot-BgYiK2N4.js → ic-connection-dot-C4nDHgY2.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{ic-tool-call-DMPHsLyx.js → ic-tool-call-Bh5kq-yY.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{index-FLPhHz8p.js → index-BBkuC-EU.js} +2 -2
- package/node_modules/@comis/web/dist/assets/{mcp-management-5jyScQis.js → mcp-management-DB-phOo7.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{media-config-J9oT9PPs.js → media-config-CRqZ1ZUH.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{media-test-DGTCtM8-.js → media-test-C9vE20Oy.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{memory-inspector-D5Re9ptG.js → memory-inspector-CeqfnxMZ.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{message-center-cRLK6ZmG.js → message-center-Daup7Mof.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{models-D5vu07MR.js → models-DLYnEU8E.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{observe-view-CalNNEmd.js → observe-view-BTSt_PO5.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-builder-DUYDGwZf.js → pipeline-builder-DknfzyLt.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-BAO8brOe.js → pipeline-history-JnHZdeU_.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-history-detail-DectIoQt.js → pipeline-history-detail-Dg4knsEb.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-list-BHlaBKww.js → pipeline-list-AEnibjsp.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{pipeline-monitor-BhtpNEHf.js → pipeline-monitor-DG7RbIOO.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{scheduler-VafN_8xi.js → scheduler-uL1fYKAT.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{security-QQXMRTlo.js → security-C3DywRLH.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-detail-BpZ_8Yih.js → session-detail-BtqCNWXV.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{session-list-DfCm8Cec.js → session-list-CJXWa2XT.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{setup-wizard-C-z477CG.js → setup-wizard-ywn7oJvu.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{skills-BCOGPf6s.js → skills-DX0KYnWD.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{subagents-l-auUraL.js → subagents-B8p5YJEB.js} +1 -1
- package/node_modules/@comis/web/dist/assets/{workspace-manager-DlvBixiq.js → workspace-manager-CgzNIrw1.js} +1 -1
- package/node_modules/@comis/web/dist/index.html +1 -1
- package/node_modules/@comis/web/package.json +1 -1
- package/package.json +13 -13
- package/node_modules/@comis/skills/dist/builtin/platform/agents-list-tool.d.ts +0 -19
- 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(
|
|
114
|
+
...createModelHandlers({
|
|
115
|
+
...deps,
|
|
116
|
+
providerEntries: deps.container.config.providers.entries,
|
|
117
|
+
}),
|
|
101
118
|
...createChannelHandlers({
|
|
102
119
|
...deps,
|
|
103
120
|
persistDeps: {
|
|
@@ -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,
|
|
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),
|
|
@@ -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
|
+
}
|