@agent-relay/wrapper 0.1.0 → 2.0.2
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/base-wrapper.d.ts +25 -1
- package/dist/base-wrapper.d.ts.map +1 -1
- package/dist/base-wrapper.js +44 -2
- package/dist/base-wrapper.js.map +1 -1
- package/dist/relay-pty-orchestrator.d.ts +2 -0
- package/dist/relay-pty-orchestrator.d.ts.map +1 -1
- package/dist/relay-pty-orchestrator.js +55 -10
- package/dist/relay-pty-orchestrator.js.map +1 -1
- package/dist/shared.d.ts +25 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +40 -0
- package/dist/shared.js.map +1 -1
- package/dist/tmux-wrapper.d.ts +7 -0
- package/dist/tmux-wrapper.d.ts.map +1 -1
- package/dist/tmux-wrapper.js +62 -9
- package/dist/tmux-wrapper.js.map +1 -1
- package/package.json +8 -8
- package/src/base-wrapper.ts +55 -1
- package/src/relay-pty-orchestrator.test.ts +3 -0
- package/src/relay-pty-orchestrator.ts +58 -10
- package/src/shared.test.ts +101 -0
- package/src/shared.ts +41 -0
- package/src/tmux-wrapper.ts +77 -9
package/src/shared.ts
CHANGED
|
@@ -7,6 +7,47 @@
|
|
|
7
7
|
|
|
8
8
|
import type { SyncMeta } from '@agent-relay/protocol/types';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Message priority levels for queue ordering.
|
|
12
|
+
* Lower numbers = higher priority (processed first).
|
|
13
|
+
*/
|
|
14
|
+
export const MESSAGE_PRIORITY = {
|
|
15
|
+
/** System-critical messages (sync ACKs, errors) - skip idle wait */
|
|
16
|
+
URGENT: 0,
|
|
17
|
+
/** Time-sensitive messages (user requests) - reduced idle wait */
|
|
18
|
+
HIGH: 1,
|
|
19
|
+
/** Normal agent-to-agent messages */
|
|
20
|
+
NORMAL: 2,
|
|
21
|
+
/** Batch/background messages - can wait longer */
|
|
22
|
+
LOW: 3,
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
export type MessagePriority = typeof MESSAGE_PRIORITY[keyof typeof MESSAGE_PRIORITY];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get priority from importance value or default to NORMAL.
|
|
29
|
+
* Maps importance number to priority level.
|
|
30
|
+
*/
|
|
31
|
+
export function getPriorityFromImportance(importance?: number): MessagePriority {
|
|
32
|
+
if (importance === undefined) return MESSAGE_PRIORITY.NORMAL;
|
|
33
|
+
if (importance >= 90) return MESSAGE_PRIORITY.URGENT;
|
|
34
|
+
if (importance >= 70) return MESSAGE_PRIORITY.HIGH;
|
|
35
|
+
if (importance >= 30) return MESSAGE_PRIORITY.NORMAL;
|
|
36
|
+
return MESSAGE_PRIORITY.LOW;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Sort messages by priority (lower number = higher priority).
|
|
41
|
+
* Stable sort - maintains order within same priority.
|
|
42
|
+
*/
|
|
43
|
+
export function sortByPriority(messages: QueuedMessage[]): QueuedMessage[] {
|
|
44
|
+
return [...messages].sort((a, b) => {
|
|
45
|
+
const priorityA = getPriorityFromImportance(a.importance);
|
|
46
|
+
const priorityB = getPriorityFromImportance(b.importance);
|
|
47
|
+
return priorityA - priorityB;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
10
51
|
/**
|
|
11
52
|
* Message queued for injection into an agent's terminal
|
|
12
53
|
*/
|
package/src/tmux-wrapper.ts
CHANGED
|
@@ -50,6 +50,8 @@ import {
|
|
|
50
50
|
INJECTION_CONSTANTS,
|
|
51
51
|
CLI_QUIRKS,
|
|
52
52
|
AdaptiveThrottle,
|
|
53
|
+
sortByPriority,
|
|
54
|
+
getPriorityFromImportance,
|
|
53
55
|
} from './shared.js';
|
|
54
56
|
import { getTmuxPanePid } from './idle-detector.js';
|
|
55
57
|
import { DEFAULT_TMUX_WRAPPER_CONFIG } from '@agent-relay/config/relay-config';
|
|
@@ -1575,18 +1577,32 @@ export class TmuxWrapper extends BaseWrapper {
|
|
|
1575
1577
|
/**
|
|
1576
1578
|
* Check if we should inject a message.
|
|
1577
1579
|
* Uses UniversalIdleDetector (from BaseWrapper) for robust cross-CLI idle detection.
|
|
1580
|
+
* Processes messages by priority (urgent first).
|
|
1578
1581
|
*/
|
|
1579
1582
|
private checkForInjectionOpportunity(): void {
|
|
1580
1583
|
if (this.messageQueue.length === 0) return;
|
|
1581
1584
|
if (this.isInjecting) return;
|
|
1582
1585
|
if (!this.running) return;
|
|
1583
1586
|
|
|
1587
|
+
// Sort queue by priority before processing (urgent messages first)
|
|
1588
|
+
if (this.messageQueue.length > 1) {
|
|
1589
|
+
this.messageQueue = sortByPriority(this.messageQueue);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// Check the priority of the next message
|
|
1593
|
+
const nextMsg = this.messageQueue[0];
|
|
1594
|
+
const priority = getPriorityFromImportance(nextMsg?.importance);
|
|
1595
|
+
|
|
1584
1596
|
// Use universal idle detector for more reliable detection (inherited from BaseWrapper)
|
|
1585
1597
|
const idleResult = this.checkIdleForInjection();
|
|
1586
1598
|
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1599
|
+
// Urgent messages (priority 0) can proceed with lower idle confidence
|
|
1600
|
+
const idleThreshold = priority === 0 ? 0.5 : 0.7;
|
|
1601
|
+
|
|
1602
|
+
if (!idleResult.isIdle && idleResult.confidence < idleThreshold) {
|
|
1603
|
+
// Not idle yet, retry later (urgent messages retry faster)
|
|
1604
|
+
const baseRetryMs = this.config.injectRetryMs ?? 300;
|
|
1605
|
+
const retryMs = priority <= 1 ? Math.floor(baseRetryMs / 2) : baseRetryMs;
|
|
1590
1606
|
setTimeout(() => this.checkForInjectionOpportunity(), retryMs);
|
|
1591
1607
|
return;
|
|
1592
1608
|
}
|
|
@@ -1622,15 +1638,19 @@ export class TmuxWrapper extends BaseWrapper {
|
|
|
1622
1638
|
}
|
|
1623
1639
|
|
|
1624
1640
|
// Ensure pane output is stable to avoid interleaving with active generation
|
|
1641
|
+
// Pass message priority for adaptive timeout (urgent messages wait less)
|
|
1642
|
+
const msgPriority = getPriorityFromImportance(msg.importance);
|
|
1625
1643
|
const stablePane = await this.waitForStablePane(
|
|
1626
|
-
this.config.outputStabilityTimeoutMs ??
|
|
1627
|
-
this.config.outputStabilityPollMs ??
|
|
1644
|
+
this.config.outputStabilityTimeoutMs ?? 800,
|
|
1645
|
+
this.config.outputStabilityPollMs ?? 150,
|
|
1646
|
+
2,
|
|
1647
|
+
msgPriority
|
|
1628
1648
|
);
|
|
1629
1649
|
if (!stablePane) {
|
|
1630
1650
|
this.logStderr('Output still active, re-queuing injection');
|
|
1631
1651
|
this.messageQueue.unshift(msg);
|
|
1632
1652
|
this.isInjecting = false;
|
|
1633
|
-
setTimeout(() => this.checkForInjectionOpportunity(), this.config.injectRetryMs ??
|
|
1653
|
+
setTimeout(() => this.checkForInjectionOpportunity(), this.config.injectRetryMs ?? 300);
|
|
1634
1654
|
return;
|
|
1635
1655
|
}
|
|
1636
1656
|
|
|
@@ -1943,15 +1963,56 @@ export class TmuxWrapper extends BaseWrapper {
|
|
|
1943
1963
|
|
|
1944
1964
|
/**
|
|
1945
1965
|
* Wait for pane output to stabilize before injecting to avoid interleaving with ongoing output.
|
|
1966
|
+
* Uses adaptive timeout based on idle detector confidence for faster injection when safe.
|
|
1967
|
+
*
|
|
1968
|
+
* @param maxWaitMs - Maximum time to wait (default from config)
|
|
1969
|
+
* @param pollIntervalMs - Polling interval (default from config)
|
|
1970
|
+
* @param requiredStablePolls - Consecutive stable polls needed (default 2)
|
|
1971
|
+
* @param priority - Message priority (lower = more urgent, can use shorter timeout)
|
|
1946
1972
|
*/
|
|
1947
|
-
private async waitForStablePane(
|
|
1973
|
+
private async waitForStablePane(
|
|
1974
|
+
maxWaitMs = 800,
|
|
1975
|
+
pollIntervalMs = 150,
|
|
1976
|
+
requiredStablePolls = 2,
|
|
1977
|
+
priority?: number
|
|
1978
|
+
): Promise<boolean> {
|
|
1948
1979
|
const start = Date.now();
|
|
1980
|
+
|
|
1981
|
+
// Adaptive timeout based on idle confidence and priority
|
|
1982
|
+
// If idle detector shows high confidence (process state), we can be more aggressive
|
|
1983
|
+
const idleResult = this.checkIdleForInjection();
|
|
1984
|
+
const highConfidence = idleResult.confidence >= 0.9;
|
|
1985
|
+
|
|
1986
|
+
// Priority-based timeout adjustment (urgent messages get shorter timeout)
|
|
1987
|
+
let effectiveMaxWait = maxWaitMs;
|
|
1988
|
+
if (priority !== undefined && priority <= 1) {
|
|
1989
|
+
// Urgent/high priority: reduce timeout by 50%
|
|
1990
|
+
effectiveMaxWait = Math.min(maxWaitMs, highConfidence ? 200 : 400);
|
|
1991
|
+
} else if (highConfidence) {
|
|
1992
|
+
// High confidence from process state: reduce timeout by 60%
|
|
1993
|
+
effectiveMaxWait = Math.floor(maxWaitMs * 0.4);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1949
1996
|
let lastSig = await this.capturePaneSignature();
|
|
1950
1997
|
if (!lastSig) return false;
|
|
1951
1998
|
|
|
1952
1999
|
let stableCount = 0;
|
|
1953
2000
|
|
|
1954
|
-
|
|
2001
|
+
// Fast initial check - if already stable, exit quickly
|
|
2002
|
+
await sleep(Math.min(pollIntervalMs, 50));
|
|
2003
|
+
const initialSig = await this.capturePaneSignature();
|
|
2004
|
+
if (initialSig && initialSig === lastSig) {
|
|
2005
|
+
stableCount = 1;
|
|
2006
|
+
// If high confidence and initial check stable, we're good
|
|
2007
|
+
if (highConfidence && stableCount >= 1) {
|
|
2008
|
+
this.logStderr(`waitForStablePane: fast exit (high confidence, ${Date.now() - start}ms)`);
|
|
2009
|
+
return true;
|
|
2010
|
+
}
|
|
2011
|
+
} else if (initialSig) {
|
|
2012
|
+
lastSig = initialSig;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
while (Date.now() - start < effectiveMaxWait) {
|
|
1955
2016
|
await sleep(pollIntervalMs);
|
|
1956
2017
|
const sig = await this.capturePaneSignature();
|
|
1957
2018
|
if (!sig) continue;
|
|
@@ -1959,6 +2020,7 @@ export class TmuxWrapper extends BaseWrapper {
|
|
|
1959
2020
|
if (sig === lastSig) {
|
|
1960
2021
|
stableCount++;
|
|
1961
2022
|
if (stableCount >= requiredStablePolls) {
|
|
2023
|
+
this.logStderr(`waitForStablePane: stable after ${Date.now() - start}ms`);
|
|
1962
2024
|
return true;
|
|
1963
2025
|
}
|
|
1964
2026
|
} else {
|
|
@@ -1967,7 +2029,13 @@ export class TmuxWrapper extends BaseWrapper {
|
|
|
1967
2029
|
}
|
|
1968
2030
|
}
|
|
1969
2031
|
|
|
1970
|
-
|
|
2032
|
+
// Even on timeout, if we had at least 1 stable poll and high confidence, proceed
|
|
2033
|
+
if (stableCount >= 1 && highConfidence) {
|
|
2034
|
+
this.logStderr(`waitForStablePane: proceeding with partial stability (high confidence)`);
|
|
2035
|
+
return true;
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
this.logStderr(`waitForStablePane: timed out after ${Date.now() - start}ms`);
|
|
1971
2039
|
return false;
|
|
1972
2040
|
}
|
|
1973
2041
|
|