@holon-run/agentinbox 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/adapters.js +6 -6
- package/dist/src/cli.js +18 -5
- package/dist/src/daemon.js +36 -2
- package/dist/src/http.js +1 -0
- package/dist/src/logging.js +112 -0
- package/dist/src/paths.js +1 -0
- package/dist/src/runtime_gate.js +360 -37
- package/dist/src/service.js +60 -3
- package/dist/src/source_resolution.js +20 -20
- package/dist/src/source_schema.js +2 -2
- package/dist/src/sources/remote.js +23 -23
- package/dist/src/sources/remote_modules.js +418 -0
- package/dist/src/sources/remote_profiles.js +9 -414
- package/package.json +1 -1
- package/scripts/iterm2_cursor_probe.py +8 -3
package/dist/src/service.js
CHANGED
|
@@ -9,6 +9,7 @@ const source_resolution_1 = require("./source_resolution");
|
|
|
9
9
|
const filter_1 = require("./filter");
|
|
10
10
|
const terminal_1 = require("./terminal");
|
|
11
11
|
const runtime_gate_1 = require("./runtime_gate");
|
|
12
|
+
const logging_1 = require("./logging");
|
|
12
13
|
const DEFAULT_SUBSCRIPTION_POLL_LIMIT = 100;
|
|
13
14
|
const DEFAULT_ACTIVATION_WINDOW_MS = 3_000;
|
|
14
15
|
const DEFAULT_ACTIVATION_MAX_ITEMS = 20;
|
|
@@ -43,7 +44,7 @@ class AgentInboxService {
|
|
|
43
44
|
lastAckedInboxGcAt = 0;
|
|
44
45
|
lastLifecycleCleanupAt = 0;
|
|
45
46
|
lastOfflineAgentGcAt = 0;
|
|
46
|
-
constructor(store, adapters, activationDispatcher = new ActivationDispatcher(), backend, activationPolicy, terminalDispatcher = new terminal_1.TerminalDispatcher(), activationGate = new
|
|
47
|
+
constructor(store, adapters, activationDispatcher = new ActivationDispatcher(), backend, activationPolicy, terminalDispatcher = new terminal_1.TerminalDispatcher(), activationGate, logger = new logging_1.NoopLogger()) {
|
|
47
48
|
this.store = store;
|
|
48
49
|
this.adapters = adapters;
|
|
49
50
|
this.activationDispatcher = activationDispatcher;
|
|
@@ -52,11 +53,13 @@ class AgentInboxService {
|
|
|
52
53
|
this.activationMaxItems = activationPolicy?.maxItems ?? DEFAULT_ACTIVATION_MAX_ITEMS;
|
|
53
54
|
this.ackedRetentionMs = DEFAULT_ACKED_RETENTION_MS;
|
|
54
55
|
this.terminalDispatcher = terminalDispatcher;
|
|
55
|
-
this.
|
|
56
|
+
this.logger = logger;
|
|
57
|
+
this.activationGate = activationGate ?? new runtime_gate_1.DefaultActivationGate(undefined, undefined, this.logger.child("gate"));
|
|
56
58
|
}
|
|
57
59
|
activationDispatcher;
|
|
58
60
|
terminalDispatcher;
|
|
59
61
|
activationGate;
|
|
62
|
+
logger;
|
|
60
63
|
async start() {
|
|
61
64
|
if (this.syncInterval) {
|
|
62
65
|
return;
|
|
@@ -1550,12 +1553,32 @@ class AgentInboxService {
|
|
|
1550
1553
|
try {
|
|
1551
1554
|
if (target.kind === "terminal") {
|
|
1552
1555
|
const gate = await this.activationGate.evaluate(target);
|
|
1556
|
+
this.logger.debug("activation.gate_decision", {
|
|
1557
|
+
agentId: input.agentId,
|
|
1558
|
+
targetId: target.targetId,
|
|
1559
|
+
runtimeKind: target.runtimeKind,
|
|
1560
|
+
backend: target.backend,
|
|
1561
|
+
outcome: gate.outcome,
|
|
1562
|
+
reason: gate.reason,
|
|
1563
|
+
});
|
|
1553
1564
|
if (gate.outcome === "offline") {
|
|
1565
|
+
this.logger.info("activation.target_offline", {
|
|
1566
|
+
agentId: input.agentId,
|
|
1567
|
+
targetId: target.targetId,
|
|
1568
|
+
reason: gate.reason,
|
|
1569
|
+
transition: "runtime_gate",
|
|
1570
|
+
});
|
|
1554
1571
|
this.markActivationTargetOffline(target.targetId, `runtime gate: ${gate.reason}`);
|
|
1555
1572
|
this.reconcileAgentStatus(target.agentId);
|
|
1556
1573
|
return "offline";
|
|
1557
1574
|
}
|
|
1558
1575
|
if (gate.outcome === "defer") {
|
|
1576
|
+
this.logger.debug("activation.dispatch_deferred", {
|
|
1577
|
+
agentId: input.agentId,
|
|
1578
|
+
targetId: target.targetId,
|
|
1579
|
+
reason: gate.reason,
|
|
1580
|
+
retryMs: DEFAULT_NOTIFY_RETRY_MS,
|
|
1581
|
+
});
|
|
1559
1582
|
this.store.upsertActivationDispatchState({
|
|
1560
1583
|
agentId: input.agentId,
|
|
1561
1584
|
targetId: input.targetId,
|
|
@@ -1594,6 +1617,11 @@ class AgentInboxService {
|
|
|
1594
1617
|
terminalPrompt = prompt;
|
|
1595
1618
|
const promptFingerprint = terminalReminderFingerprint(prompt, input.items);
|
|
1596
1619
|
if (state?.status === "dirty" && state.lastNotifiedFingerprint === promptFingerprint) {
|
|
1620
|
+
this.logger.debug("activation.dispatch_suppressed", {
|
|
1621
|
+
agentId: input.agentId,
|
|
1622
|
+
targetId: target.targetId,
|
|
1623
|
+
reason: "unchanged_terminal_prompt",
|
|
1624
|
+
});
|
|
1597
1625
|
this.store.upsertActivationDispatchState({
|
|
1598
1626
|
agentId: input.agentId,
|
|
1599
1627
|
targetId: input.targetId,
|
|
@@ -1608,7 +1636,19 @@ class AgentInboxService {
|
|
|
1608
1636
|
});
|
|
1609
1637
|
return "suppressed";
|
|
1610
1638
|
}
|
|
1639
|
+
this.logger.debug("activation.terminal_dispatch_start", {
|
|
1640
|
+
agentId: input.agentId,
|
|
1641
|
+
targetId: target.targetId,
|
|
1642
|
+
totalUnackedCount,
|
|
1643
|
+
newItemCount: input.newItemCount,
|
|
1644
|
+
sourceIds: input.sourceIds,
|
|
1645
|
+
subscriptionIds: input.subscriptionIds,
|
|
1646
|
+
});
|
|
1611
1647
|
await this.terminalDispatcher.dispatch(target, prompt);
|
|
1648
|
+
this.logger.debug("activation.terminal_dispatch_succeeded", {
|
|
1649
|
+
agentId: input.agentId,
|
|
1650
|
+
targetId: target.targetId,
|
|
1651
|
+
});
|
|
1612
1652
|
}
|
|
1613
1653
|
else {
|
|
1614
1654
|
const activation = {
|
|
@@ -1648,11 +1688,28 @@ class AgentInboxService {
|
|
|
1648
1688
|
return "dispatched";
|
|
1649
1689
|
}
|
|
1650
1690
|
catch (error) {
|
|
1651
|
-
console.warn(`activation target dispatch failed for ${target.targetId}:`, error);
|
|
1652
1691
|
const message = error instanceof Error ? error.message : String(error);
|
|
1692
|
+
this.logger.warn("activation.dispatch_failed", {
|
|
1693
|
+
agentId: input.agentId,
|
|
1694
|
+
targetId: target.targetId,
|
|
1695
|
+
targetKind: target.kind,
|
|
1696
|
+
error,
|
|
1697
|
+
message,
|
|
1698
|
+
});
|
|
1653
1699
|
if (target.kind === "terminal") {
|
|
1654
1700
|
const exists = await this.terminalDispatcher.probe(target);
|
|
1701
|
+
this.logger.debug("activation.terminal_probe_after_failure", {
|
|
1702
|
+
agentId: input.agentId,
|
|
1703
|
+
targetId: target.targetId,
|
|
1704
|
+
exists,
|
|
1705
|
+
});
|
|
1655
1706
|
if (!exists) {
|
|
1707
|
+
this.logger.info("activation.target_offline", {
|
|
1708
|
+
agentId: input.agentId,
|
|
1709
|
+
targetId: target.targetId,
|
|
1710
|
+
reason: message,
|
|
1711
|
+
transition: "dispatch_probe",
|
|
1712
|
+
});
|
|
1656
1713
|
this.markActivationTargetOffline(target.targetId, message);
|
|
1657
1714
|
this.reconcileAgentStatus(target.agentId);
|
|
1658
1715
|
return "offline";
|
|
@@ -4,7 +4,7 @@ exports.resolveSourceIdentity = resolveSourceIdentity;
|
|
|
4
4
|
exports.resolveSourceSchema = resolveSourceSchema;
|
|
5
5
|
exports.withResolvedIdentity = withResolvedIdentity;
|
|
6
6
|
const paths_1 = require("./paths");
|
|
7
|
-
const
|
|
7
|
+
const remote_modules_1 = require("./sources/remote_modules");
|
|
8
8
|
const source_schema_1 = require("./source_schema");
|
|
9
9
|
async function resolveSourceIdentity(source, context = {}) {
|
|
10
10
|
if (source.sourceType === "local_event") {
|
|
@@ -14,7 +14,7 @@ async function resolveSourceIdentity(source, context = {}) {
|
|
|
14
14
|
implementationId: "builtin.local_event",
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
const builtinImplementationId = (0,
|
|
17
|
+
const builtinImplementationId = (0, remote_modules_1.builtInModuleIdForSourceType)(source.sourceType);
|
|
18
18
|
if (builtinImplementationId) {
|
|
19
19
|
return {
|
|
20
20
|
hostType: "remote_source",
|
|
@@ -25,30 +25,30 @@ async function resolveSourceIdentity(source, context = {}) {
|
|
|
25
25
|
if (source.sourceType !== "remote_source") {
|
|
26
26
|
throw new Error(`unsupported source type for source resolution: ${source.sourceType}`);
|
|
27
27
|
}
|
|
28
|
-
const
|
|
28
|
+
const moduleRegistry = context.moduleRegistry ?? context.profileRegistry ?? new remote_modules_1.RemoteSourceModuleRegistry();
|
|
29
29
|
const homeDir = context.homeDir ?? (0, paths_1.resolveAgentInboxHome)(process.env);
|
|
30
|
-
const
|
|
31
|
-
const capabilityDescription = typeof
|
|
32
|
-
?
|
|
30
|
+
const module = await moduleRegistry.resolve(source, homeDir);
|
|
31
|
+
const capabilityDescription = typeof module.describeCapabilities === "function"
|
|
32
|
+
? module.describeCapabilities(moduleInputSource(source))
|
|
33
33
|
: undefined;
|
|
34
34
|
return {
|
|
35
35
|
hostType: "remote_source",
|
|
36
|
-
sourceKind: capabilityDescription?.sourceKind?.trim() || `remote:${
|
|
37
|
-
implementationId:
|
|
36
|
+
sourceKind: capabilityDescription?.sourceKind?.trim() || `remote:${module.id}`,
|
|
37
|
+
implementationId: module.id,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
async function resolveSourceSchema(source, context = {}) {
|
|
41
|
-
const
|
|
41
|
+
const moduleRegistry = context.moduleRegistry ?? context.profileRegistry ?? new remote_modules_1.RemoteSourceModuleRegistry();
|
|
42
42
|
const homeDir = context.homeDir ?? (0, paths_1.resolveAgentInboxHome)(process.env);
|
|
43
|
-
const resolvedContext = { ...context,
|
|
43
|
+
const resolvedContext = { ...context, moduleRegistry, homeDir };
|
|
44
44
|
const identity = await resolveSourceIdentity(source, resolvedContext);
|
|
45
45
|
const staticSchema = (0, source_schema_1.getSourceSchema)(source.sourceType);
|
|
46
46
|
let capabilityDescription;
|
|
47
|
-
let
|
|
47
|
+
let module = null;
|
|
48
48
|
if (identity.hostType === "remote_source") {
|
|
49
|
-
|
|
50
|
-
capabilityDescription = typeof
|
|
51
|
-
?
|
|
49
|
+
module = await moduleRegistry.resolve(source, homeDir);
|
|
50
|
+
capabilityDescription = typeof module.describeCapabilities === "function"
|
|
51
|
+
? module.describeCapabilities(moduleInputSource(source))
|
|
52
52
|
: undefined;
|
|
53
53
|
}
|
|
54
54
|
return withResolvedIdentity(source.sourceId, {
|
|
@@ -60,10 +60,10 @@ async function resolveSourceSchema(source, context = {}) {
|
|
|
60
60
|
}, identity, identity.hostType === "remote_source"
|
|
61
61
|
? {
|
|
62
62
|
aliases: capabilityDescription?.aliases,
|
|
63
|
-
supportsTrackedResourceRef: typeof
|
|
64
|
-
supportsLifecycleSignals: typeof
|
|
65
|
-
shortcuts: typeof
|
|
66
|
-
?
|
|
63
|
+
supportsTrackedResourceRef: typeof module?.deriveTrackedResource === "function",
|
|
64
|
+
supportsLifecycleSignals: typeof module?.projectLifecycleSignal === "function",
|
|
65
|
+
shortcuts: typeof module?.listSubscriptionShortcuts === "function"
|
|
66
|
+
? module.listSubscriptionShortcuts(moduleInputSource(source))
|
|
67
67
|
: [],
|
|
68
68
|
}
|
|
69
69
|
: undefined);
|
|
@@ -89,12 +89,12 @@ function withResolvedIdentity(sourceId, schema, identity, capabilityMetadata) {
|
|
|
89
89
|
} : {}),
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
-
function
|
|
92
|
+
function moduleInputSource(source) {
|
|
93
93
|
if (source.sourceType !== "remote_source") {
|
|
94
94
|
return source;
|
|
95
95
|
}
|
|
96
96
|
return {
|
|
97
97
|
...source,
|
|
98
|
-
config: (0,
|
|
98
|
+
config: (0, remote_modules_1.moduleConfigForSource)(source),
|
|
99
99
|
};
|
|
100
100
|
}
|
|
@@ -21,8 +21,8 @@ const SOURCE_SCHEMAS = {
|
|
|
21
21
|
payloadExamples: [],
|
|
22
22
|
eventVariantExamples: [],
|
|
23
23
|
configFields: [
|
|
24
|
-
{ name: "profilePath", type: "string", required: true, description: "Local
|
|
25
|
-
{ name: "profileConfig", type: "object", required: false, description: "
|
|
24
|
+
{ name: "profilePath", type: "string", required: true, description: "Local module path under $AGENTINBOX_HOME/source-profiles." },
|
|
25
|
+
{ name: "profileConfig", type: "object", required: false, description: "Module-specific configuration passed to validate/spec/map hooks." },
|
|
26
26
|
],
|
|
27
27
|
},
|
|
28
28
|
github_repo: {
|
|
@@ -4,7 +4,7 @@ exports.RemoteSourceRuntime = exports.RpcUxcRemoteSourceClient = void 0;
|
|
|
4
4
|
const uxc_daemon_client_1 = require("@holon-run/uxc-daemon-client");
|
|
5
5
|
const paths_1 = require("../paths");
|
|
6
6
|
const util_1 = require("../util");
|
|
7
|
-
const
|
|
7
|
+
const remote_modules_1 = require("./remote_modules");
|
|
8
8
|
const REMOTE_SOURCE_TYPES = new Set([
|
|
9
9
|
"remote_source",
|
|
10
10
|
"github_repo",
|
|
@@ -55,7 +55,7 @@ exports.RpcUxcRemoteSourceClient = RpcUxcRemoteSourceClient;
|
|
|
55
55
|
class RemoteSourceRuntime {
|
|
56
56
|
store;
|
|
57
57
|
appendSourceEvent;
|
|
58
|
-
|
|
58
|
+
moduleRegistry;
|
|
59
59
|
client;
|
|
60
60
|
interval = null;
|
|
61
61
|
inFlight = new Set();
|
|
@@ -65,7 +65,7 @@ class RemoteSourceRuntime {
|
|
|
65
65
|
constructor(store, appendSourceEvent, options) {
|
|
66
66
|
this.store = store;
|
|
67
67
|
this.appendSourceEvent = appendSourceEvent;
|
|
68
|
-
this.
|
|
68
|
+
this.moduleRegistry = options?.moduleRegistry ?? options?.profileRegistry ?? new remote_modules_1.RemoteSourceModuleRegistry();
|
|
69
69
|
this.client = options?.client ?? new RpcUxcRemoteSourceClient();
|
|
70
70
|
this.homeDir = options?.homeDir ?? (0, paths_1.resolveAgentInboxHome)(process.env);
|
|
71
71
|
}
|
|
@@ -79,10 +79,10 @@ class RemoteSourceRuntime {
|
|
|
79
79
|
if (!REMOTE_SOURCE_TYPES.has(source.sourceType)) {
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
const module = await this.moduleRegistry.resolve(source, this.homeDir);
|
|
83
|
+
const moduleSource = moduleInputSource(source);
|
|
84
|
+
module.validateConfig(moduleSource);
|
|
85
|
+
module.buildManagedSourceSpec(moduleSource);
|
|
86
86
|
}
|
|
87
87
|
async start() {
|
|
88
88
|
if (this.interval) {
|
|
@@ -171,35 +171,35 @@ class RemoteSourceRuntime {
|
|
|
171
171
|
if (!REMOTE_SOURCE_TYPES.has(source.sourceType)) {
|
|
172
172
|
return null;
|
|
173
173
|
}
|
|
174
|
-
const
|
|
175
|
-
if (typeof
|
|
174
|
+
const module = await this.moduleRegistry.resolve(source, this.homeDir);
|
|
175
|
+
if (typeof module.projectLifecycleSignal !== "function") {
|
|
176
176
|
return null;
|
|
177
177
|
}
|
|
178
|
-
return
|
|
178
|
+
return module.projectLifecycleSignal(rawPayload, moduleInputSource(source));
|
|
179
179
|
}
|
|
180
180
|
async expandSubscriptionShortcut(source, input) {
|
|
181
181
|
if (!REMOTE_SOURCE_TYPES.has(source.sourceType)) {
|
|
182
182
|
return null;
|
|
183
183
|
}
|
|
184
|
-
const
|
|
185
|
-
if (typeof
|
|
184
|
+
const module = await this.moduleRegistry.resolve(source, this.homeDir);
|
|
185
|
+
if (typeof module.expandSubscriptionShortcut !== "function") {
|
|
186
186
|
return null;
|
|
187
187
|
}
|
|
188
|
-
return
|
|
188
|
+
return module.expandSubscriptionShortcut({
|
|
189
189
|
name: input.name,
|
|
190
190
|
args: input.args,
|
|
191
|
-
source:
|
|
191
|
+
source: moduleInputSource(source),
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
194
|
async deriveInlinePreview(source, item) {
|
|
195
195
|
if (!REMOTE_SOURCE_TYPES.has(source.sourceType)) {
|
|
196
196
|
return null;
|
|
197
197
|
}
|
|
198
|
-
const
|
|
199
|
-
if (typeof
|
|
198
|
+
const module = await this.moduleRegistry.resolve(source, this.homeDir);
|
|
199
|
+
if (typeof module.deriveInlinePreview !== "function") {
|
|
200
200
|
return null;
|
|
201
201
|
}
|
|
202
|
-
return
|
|
202
|
+
return module.deriveInlinePreview(item, moduleInputSource(source));
|
|
203
203
|
}
|
|
204
204
|
async syncAll() {
|
|
205
205
|
const sources = this.store
|
|
@@ -255,10 +255,10 @@ class RemoteSourceRuntime {
|
|
|
255
255
|
};
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
const spec =
|
|
258
|
+
const module = await this.moduleRegistry.resolve(source, this.homeDir);
|
|
259
|
+
const moduleSource = moduleInputSource(source);
|
|
260
|
+
module.validateConfig(moduleSource);
|
|
261
|
+
const spec = module.buildManagedSourceSpec(moduleSource);
|
|
262
262
|
const binding = managedBindingForSource(source);
|
|
263
263
|
const ensured = await this.client.sourceEnsure({
|
|
264
264
|
namespace: binding.namespace,
|
|
@@ -279,7 +279,7 @@ class RemoteSourceRuntime {
|
|
|
279
279
|
if (Object.keys(rawPayload).length === 0) {
|
|
280
280
|
continue;
|
|
281
281
|
}
|
|
282
|
-
const mapped =
|
|
282
|
+
const mapped = module.mapRawEvent(rawPayload, moduleSource);
|
|
283
283
|
if (!mapped) {
|
|
284
284
|
continue;
|
|
285
285
|
}
|
|
@@ -348,7 +348,7 @@ class RemoteSourceRuntime {
|
|
|
348
348
|
}
|
|
349
349
|
}
|
|
350
350
|
exports.RemoteSourceRuntime = RemoteSourceRuntime;
|
|
351
|
-
function
|
|
351
|
+
function moduleInputSource(source) {
|
|
352
352
|
if (source.sourceType !== "remote_source") {
|
|
353
353
|
return source;
|
|
354
354
|
}
|