amalgm 0.1.44 → 0.1.47
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/README.md +0 -1
- package/lib/cli.js +0 -2
- package/lib/runtime-manifest.js +1 -129
- package/lib/service.js +0 -1
- package/lib/supervisor.js +0 -3
- package/lib/tunnel-chat.js +12 -12
- package/lib/tunnel-events.js +12 -12
- package/package.json +2 -2
- package/runtime/lib/runtime-manifest.js +159 -0
- package/runtime/scripts/amalgm-mcp/agents/hooks.js +182 -0
- package/runtime/scripts/amalgm-mcp/agents/rest.js +6 -1
- package/runtime/scripts/amalgm-mcp/agents/store.js +61 -31
- package/runtime/scripts/amalgm-mcp/agents/talk.js +12 -22
- package/runtime/scripts/amalgm-mcp/agents/tools.js +8 -13
- package/runtime/scripts/amalgm-mcp/artifacts/supervisor.js +3 -2
- package/runtime/scripts/amalgm-mcp/config.js +3 -2
- package/runtime/scripts/amalgm-mcp/index.js +2 -2
- package/runtime/scripts/amalgm-mcp/lib/chat-runner.js +1 -1
- package/runtime/scripts/amalgm-mcp/state/snapshot.js +12 -48
- package/runtime/scripts/chat-core/adapters/claude.js +3 -1
- package/runtime/scripts/chat-core/adapters/codex.js +173 -29
- package/runtime/scripts/chat-core/auth.js +1 -1
- package/runtime/scripts/chat-core/contract.js +2 -1
- package/runtime/scripts/chat-core/tooling/mcp-bundle.js +3 -3
- package/runtime/scripts/chat-core/tooling/native-config.js +133 -0
- package/runtime/scripts/chat-server/config.js +2 -1
- package/runtime/scripts/local-gateway.js +17 -17
- package/runtime/scripts/port-monitor.js +7 -8
- package/runtime/scripts/fs-watcher.js +0 -923
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Agents storage — SQLite-backed local agent registry + conversation logs.
|
|
3
3
|
*
|
|
4
4
|
* The registry is the Local Live Store source of truth for agent capabilities.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* shape.
|
|
5
|
+
* Default harness agents are seeded as normal rows. User-created and default
|
|
6
|
+
* agents use the same editable/deletable shape.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
const crypto = require('crypto');
|
|
10
|
+
const fs = require('fs');
|
|
11
11
|
const os = require('os');
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const {
|
|
@@ -25,10 +25,13 @@ const {
|
|
|
25
25
|
} = require('../lib/storage');
|
|
26
26
|
const { openLocalDb } = require('../state/db');
|
|
27
27
|
const { insertStateEvent, publishStateEvent } = require('../state/events');
|
|
28
|
+
const { getPreferredAuthMethod } = require('../lib/prefs');
|
|
29
|
+
const credentialAdapter = require('../../credential-adapter');
|
|
28
30
|
|
|
29
31
|
const DEFAULT_AGENT_STATUS = 'unknown';
|
|
30
32
|
const CUSTOM_AGENT_STATUS = 'ready';
|
|
31
33
|
const BUILTIN_AGENT_IDS = ['claude_code', 'codex', 'opencode', 'pi'];
|
|
34
|
+
const DEFAULT_AGENTS_SEEDED_FILE = path.join(STORAGE_DIR, '.default-agents-seeded');
|
|
32
35
|
const AMALGM_COMPUTER_ID = process.env.AMALGM_COMPUTER_ID || '';
|
|
33
36
|
|
|
34
37
|
const BUILTIN_AGENT_BLUEPRINTS = [
|
|
@@ -76,9 +79,9 @@ const BUILTIN_AGENTS = BUILTIN_AGENT_BLUEPRINTS.map((agent) => ({
|
|
|
76
79
|
nativeMcps: [],
|
|
77
80
|
tools: { mode: 'all', selectedToolIds: [] },
|
|
78
81
|
mcp: { inheritAll: true, customServers: [], appIds: [], nativeMcps: [] },
|
|
79
|
-
builtin:
|
|
80
|
-
deletable:
|
|
81
|
-
editable:
|
|
82
|
+
builtin: false,
|
|
83
|
+
deletable: true,
|
|
84
|
+
editable: true,
|
|
82
85
|
status: DEFAULT_AGENT_STATUS,
|
|
83
86
|
}));
|
|
84
87
|
|
|
@@ -133,6 +136,26 @@ function computerName() {
|
|
|
133
136
|
|| 'This computer';
|
|
134
137
|
}
|
|
135
138
|
|
|
139
|
+
function persistedAuthMethod(baseHarnessId) {
|
|
140
|
+
const localFallback = typeof credentialAdapter.getPersistedAuthMode === 'function'
|
|
141
|
+
? credentialAdapter.getPersistedAuthMode(baseHarnessId)
|
|
142
|
+
: 'amalgm';
|
|
143
|
+
if (typeof getPreferredAuthMethod === 'function') {
|
|
144
|
+
return getPreferredAuthMethod(baseHarnessId, localFallback);
|
|
145
|
+
}
|
|
146
|
+
return localFallback;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function defaultAgentAuthMethod(baseHarnessId, existing) {
|
|
150
|
+
const persisted = persistedAuthMethod(baseHarnessId);
|
|
151
|
+
const existingAuth = nonEmptyString(existing?.authMethod);
|
|
152
|
+
if (!existingAuth) return persisted;
|
|
153
|
+
if (existingAuth === 'amalgm' && persisted && persisted !== 'amalgm') {
|
|
154
|
+
return persisted;
|
|
155
|
+
}
|
|
156
|
+
return existingAuth;
|
|
157
|
+
}
|
|
158
|
+
|
|
136
159
|
function normalizeLocation(inputLocation, fallback = {}) {
|
|
137
160
|
const id = nonEmptyString(fallback.ownerComputerId) || computerId();
|
|
138
161
|
const name = nonEmptyString(fallback.locationName) || computerName();
|
|
@@ -195,7 +218,7 @@ function normalizeToolConfig(tools, legacyMcp) {
|
|
|
195
218
|
function normalizeAgent(input, existing) {
|
|
196
219
|
if (!isObject(input)) throw new Error('agent must be an object');
|
|
197
220
|
const id = nonEmptyString(input.id) || `custom-${crypto.randomUUID()}`;
|
|
198
|
-
const builtin = input.builtin === true
|
|
221
|
+
const builtin = input.builtin === true;
|
|
199
222
|
const baseHarnessId = nonEmptyString(input.baseHarnessId || input.base_harness_id) || id;
|
|
200
223
|
const adapter = nonEmptyString(input.adapter) || baseHarnessId;
|
|
201
224
|
const mcpConfig = normalizeMcpConfig(input.mcp, input.mcpAppIds, input.nativeMcps);
|
|
@@ -227,7 +250,7 @@ function normalizeAgent(input, existing) {
|
|
|
227
250
|
...mcpConfig,
|
|
228
251
|
inheritAll: toolConfig.mode !== 'selected',
|
|
229
252
|
},
|
|
230
|
-
authMethod: input.authMethod || existing?.authMethod ||
|
|
253
|
+
authMethod: input.authMethod || existing?.authMethod || persistedAuthMethod(baseHarnessId),
|
|
231
254
|
location,
|
|
232
255
|
locationName: locationLabel(location),
|
|
233
256
|
ownerComputerId,
|
|
@@ -238,8 +261,8 @@ function normalizeAgent(input, existing) {
|
|
|
238
261
|
? { ...defaultCapabilities({ tools: toolConfig }), ...input.capabilities }
|
|
239
262
|
: defaultCapabilities({ tools: toolConfig }),
|
|
240
263
|
builtin,
|
|
241
|
-
deletable: input.deletable === false
|
|
242
|
-
editable: input.editable === false
|
|
264
|
+
deletable: input.deletable === false ? false : true,
|
|
265
|
+
editable: input.editable === false ? false : true,
|
|
243
266
|
createdAt,
|
|
244
267
|
updatedAt,
|
|
245
268
|
...(input.configDir ? { configDir: input.configDir } : existing?.configDir ? { configDir: existing.configDir } : {}),
|
|
@@ -351,7 +374,6 @@ function writeAgentsJson(customAgents) {
|
|
|
351
374
|
function readCustomAgentsFromDb(db = openLocalDb()) {
|
|
352
375
|
return db.prepare(`
|
|
353
376
|
SELECT * FROM agents
|
|
354
|
-
WHERE builtin = 0
|
|
355
377
|
ORDER BY updated_at DESC, id ASC
|
|
356
378
|
`).all()
|
|
357
379
|
.map(rowToAgent)
|
|
@@ -372,29 +394,36 @@ function customAgentRowCount(db = openLocalDb()) {
|
|
|
372
394
|
|
|
373
395
|
function seedBuiltinAgents(options = {}) {
|
|
374
396
|
const db = openLocalDb();
|
|
397
|
+
const alreadySeeded = fs.existsSync(DEFAULT_AGENTS_SEEDED_FILE);
|
|
375
398
|
const events = db.transaction(() => {
|
|
376
399
|
const inserted = [];
|
|
377
400
|
for (const blueprint of BUILTIN_AGENT_BLUEPRINTS) {
|
|
378
401
|
const existing = readAgentRow(db, blueprint.id);
|
|
402
|
+
if (!existing && alreadySeeded) continue;
|
|
379
403
|
const next = normalizeAgent({
|
|
380
404
|
...blueprint,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
405
|
+
name: existing?.name || blueprint.name,
|
|
406
|
+
description: existing?.description ?? blueprint.description,
|
|
407
|
+
adapter: existing?.adapter || blueprint.adapter,
|
|
408
|
+
baseHarnessId: existing?.baseHarnessId || blueprint.baseHarnessId,
|
|
409
|
+
baseModelId: existing?.baseModelId || blueprint.baseModelId,
|
|
410
|
+
systemPrompt: existing?.systemPrompt || '',
|
|
411
|
+
files: existing?.files || [],
|
|
412
|
+
skills: existing?.skills || [],
|
|
413
|
+
mcpAppIds: existing?.mcpAppIds || [],
|
|
414
|
+
nativeMcps: existing?.nativeMcps || [],
|
|
415
|
+
tools: existing?.tools || { mode: 'all', selectedToolIds: [] },
|
|
416
|
+
mcp: existing?.mcp || { inheritAll: true, customServers: [], appIds: [], nativeMcps: [] },
|
|
417
|
+
builtin: false,
|
|
418
|
+
deletable: true,
|
|
419
|
+
editable: true,
|
|
391
420
|
status: existing?.status || DEFAULT_AGENT_STATUS,
|
|
392
421
|
installStatus: existing?.installStatus || 'unknown',
|
|
393
422
|
authStatus: existing?.authStatus || 'unknown',
|
|
394
423
|
authDetails: existing?.authDetails,
|
|
395
424
|
configDir: existing?.configDir,
|
|
396
425
|
createdAt: existing?.createdAt,
|
|
397
|
-
authMethod: existing?.
|
|
426
|
+
authMethod: defaultAgentAuthMethod(existing?.baseHarnessId || blueprint.baseHarnessId, existing),
|
|
398
427
|
}, existing);
|
|
399
428
|
if (existing && agentsEqualForWrite(existing, next)) continue;
|
|
400
429
|
upsertAgentRow(db, next);
|
|
@@ -406,13 +435,17 @@ function seedBuiltinAgents(options = {}) {
|
|
|
406
435
|
}
|
|
407
436
|
return inserted;
|
|
408
437
|
})();
|
|
438
|
+
try {
|
|
439
|
+
ensureDir(STORAGE_DIR);
|
|
440
|
+
fs.writeFileSync(DEFAULT_AGENTS_SEEDED_FILE, nowIso());
|
|
441
|
+
} catch {
|
|
442
|
+
// Best-effort marker; default seeding still works without it.
|
|
443
|
+
}
|
|
409
444
|
publishEvents(events);
|
|
410
445
|
}
|
|
411
446
|
|
|
412
447
|
function migrateLegacyAgentsJsonIfNeeded() {
|
|
413
448
|
const db = openLocalDb();
|
|
414
|
-
if (customAgentRowCount(db) > 0) return;
|
|
415
|
-
|
|
416
449
|
const legacy = readJson(AGENTS_FILE, { version: 1, agents: [] });
|
|
417
450
|
const legacyAgents = Array.isArray(legacy?.agents) ? legacy.agents : [];
|
|
418
451
|
if (legacyAgents.length === 0) return;
|
|
@@ -421,6 +454,7 @@ function migrateLegacyAgentsJsonIfNeeded() {
|
|
|
421
454
|
for (const agent of legacyAgents) {
|
|
422
455
|
const normalized = normalizeAgent(agent, null);
|
|
423
456
|
if (normalized.builtin) continue;
|
|
457
|
+
if (readAgentRow(db, normalized.id)) continue;
|
|
424
458
|
upsertAgentRow(db, normalized);
|
|
425
459
|
}
|
|
426
460
|
})();
|
|
@@ -523,10 +557,6 @@ function updateAgent(agentId, updates, options = {}) {
|
|
|
523
557
|
const db = openLocalDb();
|
|
524
558
|
const existing = readAgentRow(db, agentId);
|
|
525
559
|
if (!existing) throw new Error(`Agent not found: ${agentId}`);
|
|
526
|
-
if (existing.builtin && options.allowBuiltinUpdate !== true) {
|
|
527
|
-
throw new Error(`Built-in agent "${existing.name}" cannot be edited`);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
560
|
const requestedName = nonEmptyString(updates?.name);
|
|
531
561
|
if (requestedName) {
|
|
532
562
|
const duplicate = getAllAgentsWithBuiltins()
|
|
@@ -569,12 +599,12 @@ function deleteAgent(agentId, options = {}) {
|
|
|
569
599
|
const db = openLocalDb();
|
|
570
600
|
const existing = readAgentRow(db, agentId);
|
|
571
601
|
if (!existing) throw new Error(`Agent not found: ${agentId}`);
|
|
572
|
-
if (existing.
|
|
573
|
-
throw new Error(`
|
|
602
|
+
if (existing.deletable === false) {
|
|
603
|
+
throw new Error(`Agent "${existing.name}" cannot be deleted`);
|
|
574
604
|
}
|
|
575
605
|
|
|
576
606
|
const event = db.transaction(() => {
|
|
577
|
-
db.prepare('DELETE FROM agents WHERE id = ?
|
|
607
|
+
db.prepare('DELETE FROM agents WHERE id = ?').run(agentId);
|
|
578
608
|
return insertAgentEvent(db, 'delete', existing, {
|
|
579
609
|
source: options.source || 'agents:delete',
|
|
580
610
|
});
|
|
@@ -14,7 +14,7 @@ const crypto = require('crypto');
|
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const os = require('os');
|
|
16
16
|
|
|
17
|
-
const {
|
|
17
|
+
const { AMALGM_USER_ID, DEFAULT_CWD, STORAGE_DIR } = require('../config');
|
|
18
18
|
const { runThroughChatServer } = require('../lib/chat-runner');
|
|
19
19
|
const {
|
|
20
20
|
hasSupabase,
|
|
@@ -31,11 +31,7 @@ const {
|
|
|
31
31
|
} = require('../lib/prefs');
|
|
32
32
|
const { textResult, errorResult } = require('../lib/tool-result');
|
|
33
33
|
const { ensureDir } = require('../lib/storage');
|
|
34
|
-
const {
|
|
35
|
-
appendAgentConvoLog,
|
|
36
|
-
normalizeConversationId,
|
|
37
|
-
resolveAgentByNameOrId,
|
|
38
|
-
} = require('./store');
|
|
34
|
+
const { appendAgentConvoLog, normalizeConversationId, resolveAgentByNameOrId } = require('./store');
|
|
39
35
|
const {
|
|
40
36
|
chatInputToLegacyFields,
|
|
41
37
|
getChatInputText,
|
|
@@ -465,8 +461,6 @@ async function deliverResponseToCallerSession({
|
|
|
465
461
|
callerResponseDelivered: true,
|
|
466
462
|
callerResponseDeliveredAt: deliveredAt,
|
|
467
463
|
callerResponseTarget: targetSessionId,
|
|
468
|
-
callerResponseText: messageText,
|
|
469
|
-
callerResponseDescription: description || null,
|
|
470
464
|
});
|
|
471
465
|
appendStatusLog(sourceSessionId, 'caller_response_delivered', {
|
|
472
466
|
targetConversationId: targetSessionId,
|
|
@@ -537,6 +531,7 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
537
531
|
`Agent not found: ${agentLookup}. Use agents_list to see available agents.`,
|
|
538
532
|
);
|
|
539
533
|
}
|
|
534
|
+
|
|
540
535
|
const isNewConversation = !normalizedConversationId;
|
|
541
536
|
const sessionId = normalizedConversationId || crypto.randomUUID();
|
|
542
537
|
const userMessageId = crypto.randomUUID();
|
|
@@ -552,10 +547,13 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
552
547
|
const persistedAuthMethod = credentialAdapter.VALID_HARNESS_IDS.includes(agent.baseHarnessId)
|
|
553
548
|
? credentialAdapter.getPersistedAuthMode(agent.baseHarnessId)
|
|
554
549
|
: 'amalgm';
|
|
550
|
+
const preferredAuthMethod = getPreferredAuthMethod(agent.baseHarnessId, persistedAuthMethod);
|
|
551
|
+
const isDefaultAgentClass = agent.id === agent.baseHarnessId;
|
|
555
552
|
const defaultAuthMethod = coerceAuthMethodForHarness(
|
|
556
553
|
agent.baseHarnessId,
|
|
557
|
-
agent.authMethod
|
|
558
|
-
|
|
554
|
+
isDefaultAgentClass && agent.authMethod === 'amalgm' && preferredAuthMethod !== 'amalgm'
|
|
555
|
+
? preferredAuthMethod
|
|
556
|
+
: agent.authMethod || preferredAuthMethod,
|
|
559
557
|
);
|
|
560
558
|
const agentFiles = normalizeStringList(agent.files);
|
|
561
559
|
const agentSkills = normalizeStringList(agent.skills);
|
|
@@ -707,7 +705,6 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
707
705
|
await supabaseInsert('sessions', {
|
|
708
706
|
id: sessionId,
|
|
709
707
|
user_id: AMALGM_USER_ID,
|
|
710
|
-
computer_id: AMALGM_COMPUTER_ID,
|
|
711
708
|
container_id: os.hostname() || 'agent-conversation',
|
|
712
709
|
harness: agent.id,
|
|
713
710
|
title: taskDescription || 'New Chat',
|
|
@@ -779,7 +776,6 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
779
776
|
chatInput: normalizedChatInput,
|
|
780
777
|
prompt: legacyChatFields.prompt,
|
|
781
778
|
userId: AMALGM_USER_ID,
|
|
782
|
-
computerId: AMALGM_COMPUTER_ID,
|
|
783
779
|
codeSessionId: sessionId,
|
|
784
780
|
assistantMessageId,
|
|
785
781
|
userMessageId,
|
|
@@ -912,11 +908,8 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
912
908
|
},
|
|
913
909
|
},
|
|
914
910
|
);
|
|
915
|
-
const activeAfterTurn = summarizeActiveConversation(sessionId);
|
|
916
|
-
const deliveredResponseText = String(activeAfterTurn?.callerResponseText || '').trim();
|
|
917
|
-
const finalOutputText = String(outputText || '').trim() ? outputText : deliveredResponseText;
|
|
918
911
|
const warnings = [];
|
|
919
|
-
if (!String(
|
|
912
|
+
if (!String(outputText || '').trim()) {
|
|
920
913
|
warnings.push(
|
|
921
914
|
metrics?.toolEvents > 0
|
|
922
915
|
? 'Agent completed without visible text after tool activity; check the session log or workspace diff before retrying.'
|
|
@@ -933,7 +926,7 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
933
926
|
agentName: agent.name,
|
|
934
927
|
runId,
|
|
935
928
|
description: taskDescription,
|
|
936
|
-
message:
|
|
929
|
+
message: outputText,
|
|
937
930
|
timestamp: new Date().toISOString(),
|
|
938
931
|
stopReason,
|
|
939
932
|
usage,
|
|
@@ -954,7 +947,7 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
954
947
|
});
|
|
955
948
|
|
|
956
949
|
console.log(
|
|
957
|
-
`[AmalgmMCP:Agent] ${agent.name} responded (${
|
|
950
|
+
`[AmalgmMCP:Agent] ${agent.name} responded (${outputText.length} chars, session: ${sessionId})`,
|
|
958
951
|
);
|
|
959
952
|
|
|
960
953
|
if (
|
|
@@ -982,7 +975,7 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
982
975
|
status: 'completed',
|
|
983
976
|
isNewConversation,
|
|
984
977
|
longMessageContext,
|
|
985
|
-
outputText
|
|
978
|
+
outputText,
|
|
986
979
|
stopReason,
|
|
987
980
|
usage,
|
|
988
981
|
metrics,
|
|
@@ -990,9 +983,6 @@ async function handleTalkToAgent(args, context = {}) {
|
|
|
990
983
|
recovery:
|
|
991
984
|
'Use agents_get_conversation with this conversation_id if the caller times out or needs the local transcript.',
|
|
992
985
|
includeMetrics,
|
|
993
|
-
extra: deliveredResponseText && !String(outputText || '').trim()
|
|
994
|
-
? { response_source: 'return_channel' }
|
|
995
|
-
: {},
|
|
996
986
|
}),
|
|
997
987
|
null,
|
|
998
988
|
2,
|
|
@@ -26,20 +26,17 @@ module.exports = [
|
|
|
26
26
|
{
|
|
27
27
|
name: 'agents_list',
|
|
28
28
|
description:
|
|
29
|
-
'List all available
|
|
29
|
+
'List all available agent classes. Use this to discover which agents you can talk to via talk_to_agent.',
|
|
30
30
|
inputSchema: { type: 'object', properties: {} },
|
|
31
31
|
async handler() {
|
|
32
32
|
const all = getAllAgentsWithBuiltins();
|
|
33
33
|
if (all.length === 0) return textResult('No agents available.');
|
|
34
34
|
const summary = all
|
|
35
35
|
.map((a) => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
getSelectedModel(a.baseHarnessId) ||
|
|
41
|
-
DEFAULT_SELECTED_MODELS[a.baseHarnessId];
|
|
42
|
-
return `- ${a.name} (${a.id}) ${tag}\n ${a.description || 'No description'}\n adapter: ${a.adapter || a.baseHarnessId} | harness: ${a.baseHarnessId} | model: ${model}\n location: ${a.locationName || a.location?.name || 'this computer'} | status: ${a.status || 'unknown'}`;
|
|
36
|
+
const model = a.baseModelId ||
|
|
37
|
+
getSelectedModel(a.baseHarnessId) ||
|
|
38
|
+
DEFAULT_SELECTED_MODELS[a.baseHarnessId];
|
|
39
|
+
return `- ${a.name} (${a.id})\n ${a.description || 'No description'}\n adapter: ${a.adapter || a.baseHarnessId} | harness: ${a.baseHarnessId} | model: ${model}\n location: ${a.locationName || a.location?.name || 'this computer'} | status: ${a.status || 'unknown'}`;
|
|
43
40
|
})
|
|
44
41
|
.join('\n\n');
|
|
45
42
|
return textResult(`Available agents:\n\n${summary}`);
|
|
@@ -63,11 +60,9 @@ module.exports = [
|
|
|
63
60
|
description: agent.description,
|
|
64
61
|
adapter: agent.adapter || agent.baseHarnessId,
|
|
65
62
|
baseHarnessId: agent.baseHarnessId,
|
|
66
|
-
baseModelId: agent.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
getSelectedModel(agent.baseHarnessId) ||
|
|
70
|
-
DEFAULT_SELECTED_MODELS[agent.baseHarnessId],
|
|
63
|
+
baseModelId: agent.baseModelId ||
|
|
64
|
+
getSelectedModel(agent.baseHarnessId) ||
|
|
65
|
+
DEFAULT_SELECTED_MODELS[agent.baseHarnessId],
|
|
71
66
|
systemPrompt: agent.systemPrompt ? '(configured)' : '(none)',
|
|
72
67
|
mcp: {
|
|
73
68
|
inheritAll: agent.mcp?.inheritAll ?? true,
|
|
@@ -10,6 +10,7 @@ const path = require('path');
|
|
|
10
10
|
const { spawn } = require('child_process');
|
|
11
11
|
const { DEFAULT_CWD } = require('../config');
|
|
12
12
|
const activeMemory = require('../../chat-core/tooling/active-memory');
|
|
13
|
+
const { runtimePort } = require('../../../lib/runtime-manifest');
|
|
13
14
|
const { syncArtifactRoutesToGateway } = require('./advertise');
|
|
14
15
|
const {
|
|
15
16
|
allocatePort,
|
|
@@ -88,8 +89,8 @@ function buildEnv(artifact) {
|
|
|
88
89
|
AMALGM_ARTIFACT_ID: artifact.id,
|
|
89
90
|
AMALGM_ARTIFACT_REF: artifact.artifactRef,
|
|
90
91
|
AMALGM_ARTIFACT_URL: artifact.publicUrl,
|
|
91
|
-
AMALGM_CHAT_SERVER_URL: `http://127.0.0.1:${
|
|
92
|
-
AMALGM_MCP_URL: `http://127.0.0.1:${
|
|
92
|
+
AMALGM_CHAT_SERVER_URL: `http://127.0.0.1:${runtimePort('chat-server')}`,
|
|
93
|
+
AMALGM_MCP_URL: `http://127.0.0.1:${runtimePort('amalgm-mcp')}`,
|
|
93
94
|
};
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -14,8 +14,9 @@ const {
|
|
|
14
14
|
proxyBaseUrl,
|
|
15
15
|
readProxyToken,
|
|
16
16
|
} = require('../proxy-token-store');
|
|
17
|
+
const { runtimePort } = require('../../lib/runtime-manifest');
|
|
17
18
|
|
|
18
|
-
const PORT =
|
|
19
|
+
const PORT = runtimePort('amalgm-mcp');
|
|
19
20
|
const MCP_PROTOCOL_VERSION = '2024-11-05';
|
|
20
21
|
|
|
21
22
|
const AMALGM_DIR = process.env.AMALGM_DIR || path.join(os.homedir(), '.amalgm');
|
|
@@ -46,7 +47,7 @@ function cleanString(value) {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
// Chat server (local Next.js/Electron) — same process tree; no cloud hop.
|
|
49
|
-
const CHAT_SERVER_URL = `http://localhost:${
|
|
50
|
+
const CHAT_SERVER_URL = `http://localhost:${runtimePort('chat-server')}`;
|
|
50
51
|
|
|
51
52
|
const SCHEDULER_INTERVAL_MS = 30_000;
|
|
52
53
|
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* (default: ~/.amalgm/) — same pattern as scripts/credential-adapter.js.
|
|
7
7
|
*
|
|
8
8
|
* Ports:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* this server uses the amalgm-mcp runtime port
|
|
10
|
+
* chat-server uses the chat-server runtime port for task/event/agent runs
|
|
11
11
|
*
|
|
12
12
|
* Modules:
|
|
13
13
|
* config.js env + paths
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - agents/talk.js (talk_to_agent tool)
|
|
8
8
|
* - email/inbound.js (email replies/new email → agent runs)
|
|
9
9
|
*
|
|
10
|
-
* POSTs to chat-server
|
|
10
|
+
* POSTs to chat-server and consumes the SSE stream, accumulating
|
|
11
11
|
* text from agent_message_chunk events and returning the final output.
|
|
12
12
|
*/
|
|
13
13
|
|
|
@@ -2,27 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const { currentSeq } = require('./events');
|
|
4
4
|
|
|
5
|
-
const DEFAULT_RESOURCES = [
|
|
6
|
-
'tasks',
|
|
7
|
-
'event_triggers',
|
|
8
|
-
'agents',
|
|
9
|
-
'artifacts',
|
|
10
|
-
'toolbox',
|
|
11
|
-
'tools',
|
|
12
|
-
'tool_actions',
|
|
13
|
-
'projects',
|
|
14
|
-
'workspaces',
|
|
15
|
-
'memories',
|
|
16
|
-
];
|
|
5
|
+
const DEFAULT_RESOURCES = ['tasks', 'event_triggers', 'agents', 'artifacts', 'toolbox', 'tools', 'tool_actions', 'hooks', 'projects', 'workspaces', 'memories'];
|
|
17
6
|
|
|
18
7
|
function normalizeResources(resources) {
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
? resources
|
|
22
|
-
: String(resources).split(',');
|
|
23
|
-
const clean = values
|
|
24
|
-
.map((value) => String(value || '').trim())
|
|
25
|
-
.filter(Boolean);
|
|
8
|
+
const values = resources ? String(resources).split(',') : DEFAULT_RESOURCES;
|
|
9
|
+
const clean = values.map((value) => String(value || '').trim()).filter(Boolean);
|
|
26
10
|
return clean.length > 0 ? Array.from(new Set(clean)) : DEFAULT_RESOURCES;
|
|
27
11
|
}
|
|
28
12
|
|
|
@@ -36,18 +20,17 @@ function readResource(resource, cache) {
|
|
|
36
20
|
return require('../agents/store').getAllAgentsWithBuiltins();
|
|
37
21
|
case 'artifacts':
|
|
38
22
|
return require('../artifacts/store').loadArtifacts().artifacts;
|
|
39
|
-
case 'toolbox':
|
|
23
|
+
case 'toolbox':
|
|
40
24
|
cache.toolbox ||= require('../toolbox/store').readToolbox();
|
|
41
25
|
return cache.toolbox;
|
|
42
|
-
|
|
43
|
-
case 'tools': {
|
|
26
|
+
case 'tools':
|
|
44
27
|
cache.toolbox ||= require('../toolbox/store').readToolbox();
|
|
45
28
|
return cache.toolbox.tools;
|
|
46
|
-
|
|
47
|
-
case 'tool_actions': {
|
|
29
|
+
case 'tool_actions':
|
|
48
30
|
cache.toolbox ||= require('../toolbox/store').readToolbox();
|
|
49
31
|
return cache.toolbox.toolActions;
|
|
50
|
-
|
|
32
|
+
case 'hooks':
|
|
33
|
+
return require('../agents/hooks').collectNativeHooks();
|
|
51
34
|
case 'projects':
|
|
52
35
|
case 'workspaces': {
|
|
53
36
|
const workspaceStore = require('../workspace/store');
|
|
@@ -68,37 +51,18 @@ function buildSnapshot(resourcesInput) {
|
|
|
68
51
|
const beforeSeq = currentSeq();
|
|
69
52
|
const cache = {};
|
|
70
53
|
const data = {};
|
|
71
|
-
|
|
72
54
|
for (const resource of resources) {
|
|
73
55
|
const value = readResource(resource, cache);
|
|
74
56
|
if (value !== undefined) data[resource] = value;
|
|
75
57
|
}
|
|
76
|
-
|
|
77
58
|
const afterSeq = currentSeq();
|
|
78
59
|
if (beforeSeq === afterSeq) {
|
|
79
|
-
return {
|
|
80
|
-
seq: afterSeq,
|
|
81
|
-
stable: true,
|
|
82
|
-
resources: data,
|
|
83
|
-
};
|
|
60
|
+
return { seq: afterSeq, stable: true, resources: data };
|
|
84
61
|
}
|
|
85
|
-
|
|
86
|
-
lastUnstable = {
|
|
87
|
-
seq: beforeSeq,
|
|
88
|
-
stable: false,
|
|
89
|
-
resources: data,
|
|
90
|
-
};
|
|
62
|
+
lastUnstable = { seq: beforeSeq, stable: false, resources: data };
|
|
91
63
|
}
|
|
92
64
|
|
|
93
|
-
return lastUnstable || {
|
|
94
|
-
seq: currentSeq(),
|
|
95
|
-
stable: true,
|
|
96
|
-
resources: {},
|
|
97
|
-
};
|
|
65
|
+
return lastUnstable || { seq: currentSeq(), stable: true, resources: {} };
|
|
98
66
|
}
|
|
99
67
|
|
|
100
|
-
module.exports = {
|
|
101
|
-
DEFAULT_RESOURCES,
|
|
102
|
-
buildSnapshot,
|
|
103
|
-
normalizeResources,
|
|
104
|
-
};
|
|
68
|
+
module.exports = { DEFAULT_RESOURCES, buildSnapshot, normalizeResources };
|
|
@@ -8,6 +8,7 @@ const { normalizeClaudeMessage, usageRecordsFromClaudeResult, usageFromClaude }
|
|
|
8
8
|
const { recordNativeEvent } = require('../recorder');
|
|
9
9
|
const { toClaudeMcpServers } = require('../tooling/mcp-bundle');
|
|
10
10
|
const { bundledClaudeBinary } = require('../tooling/native-binaries');
|
|
11
|
+
const { syncNativeHarnessConfig } = require('../tooling/native-config');
|
|
11
12
|
const { importPackage } = require('../tooling/package-import');
|
|
12
13
|
const { composeSystemPrompt } = require('../tooling/system-prompt');
|
|
13
14
|
|
|
@@ -31,6 +32,7 @@ class ClaudeAdapter {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
options(contract, extra = {}) {
|
|
35
|
+
syncNativeHarnessConfig(contract);
|
|
34
36
|
const systemPrompt = composeSystemPrompt(contract);
|
|
35
37
|
const pathToClaudeCodeExecutable = process.env.CLAUDE_CODE_BINARY || bundledClaudeBinary();
|
|
36
38
|
return {
|
|
@@ -47,7 +49,7 @@ class ClaudeAdapter {
|
|
|
47
49
|
...(process.env.CHAT_CORE_DEBUG_CLAUDE === '1'
|
|
48
50
|
? { debug: true, debugFile: path.join(contract.auth.runtimeHome || process.cwd(), 'claude-debug.log') }
|
|
49
51
|
: {}),
|
|
50
|
-
settingSources: [],
|
|
52
|
+
settingSources: ['user', 'project', 'local'],
|
|
51
53
|
strictMcpConfig: false,
|
|
52
54
|
...extra,
|
|
53
55
|
};
|