@dmsdc-ai/aigentry-deliberation 0.0.1
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/LICENSE +21 -0
- package/README.md +94 -0
- package/browser-control-port.js +563 -0
- package/degradation-state-machine.js +206 -0
- package/index.js +3156 -0
- package/install.js +202 -0
- package/observer.js +483 -0
- package/package.json +65 -0
- package/public/index.html +1478 -0
- package/selectors/chatgpt-extension.json +21 -0
- package/selectors/chatgpt.json +20 -0
- package/selectors/claude-extension.json +21 -0
- package/selectors/claude.json +19 -0
- package/selectors/extension-providers.json +24 -0
- package/selectors/gemini-extension.json +21 -0
- package/selectors/gemini.json +19 -0
- package/selectors/role-presets.json +28 -0
- package/selectors/roles/critic.md +12 -0
- package/selectors/roles/free.md +1 -0
- package/selectors/roles/implementer.md +12 -0
- package/selectors/roles/mediator.md +12 -0
- package/selectors/roles/researcher.md +12 -0
- package/session-monitor-win.js +94 -0
- package/session-monitor.sh +316 -0
- package/skills/deliberation/SKILL.md +164 -0
- package/skills/deliberation-executor/SKILL.md +86 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DegradationStateMachine — 4-stage graceful degradation for BrowserControlPort
|
|
3
|
+
*
|
|
4
|
+
* States: HEALTHY → RETRYING → REBINDING → RELOADING → FALLBACK → FAILED
|
|
5
|
+
* Time budget (60s SLO): S1(12s) + S2(8s) + S3(18s) + S4(22s spare)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const STATES = {
|
|
9
|
+
HEALTHY: "HEALTHY",
|
|
10
|
+
RETRYING: "RETRYING",
|
|
11
|
+
REBINDING: "REBINDING",
|
|
12
|
+
RELOADING: "RELOADING",
|
|
13
|
+
FALLBACK: "FALLBACK",
|
|
14
|
+
FAILED: "FAILED",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const STAGE_BUDGETS = {
|
|
18
|
+
RETRYING: { maxAttempts: 2, backoffMs: [2000, 4000], budgetMs: 12000 },
|
|
19
|
+
REBINDING: { maxAttempts: 1, budgetMs: 8000 },
|
|
20
|
+
RELOADING: { maxAttempts: 1, budgetMs: 18000 },
|
|
21
|
+
FALLBACK: { budgetMs: 22000 },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const ERROR_CODES = {
|
|
25
|
+
BIND_FAILED: { category: "transient", domain: "browser", retryable: true },
|
|
26
|
+
SEND_FAILED: { category: "transient", domain: "transport", retryable: true },
|
|
27
|
+
TIMEOUT: { category: "transient", domain: "transport", retryable: true },
|
|
28
|
+
DOM_CHANGED: { category: "transient", domain: "dom", retryable: true },
|
|
29
|
+
SESSION_EXPIRED: { category: "permanent", domain: "session", retryable: false },
|
|
30
|
+
TAB_CLOSED: { category: "transient", domain: "browser", retryable: true },
|
|
31
|
+
NETWORK_DISCONNECTED: { category: "transient", domain: "transport", retryable: true },
|
|
32
|
+
MCP_CHANNEL_CLOSED: { category: "transient", domain: "transport", retryable: true },
|
|
33
|
+
BROWSER_CRASHED: { category: "transient", domain: "browser", retryable: true },
|
|
34
|
+
INVALID_SELECTOR_CONFIG: { category: "permanent", domain: "dom", retryable: false },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function makeResult(ok, data, error) {
|
|
38
|
+
if (ok) return { ok: true, data: data ?? null };
|
|
39
|
+
const meta = ERROR_CODES[error?.code] || ERROR_CODES.TIMEOUT;
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
error: {
|
|
43
|
+
code: error?.code || "UNKNOWN",
|
|
44
|
+
category: meta.category,
|
|
45
|
+
domain: meta.domain,
|
|
46
|
+
message: error?.message || "Unknown error",
|
|
47
|
+
retryable: meta.retryable,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class DegradationStateMachine {
|
|
53
|
+
constructor({ onRetry, onRebind, onReload, onFallback, skipEnabled = false } = {}) {
|
|
54
|
+
this.state = STATES.HEALTHY;
|
|
55
|
+
this.stageAttempts = { RETRYING: 0, REBINDING: 0, RELOADING: 0 };
|
|
56
|
+
this.startTime = null;
|
|
57
|
+
this.lastError = null;
|
|
58
|
+
this.skipEnabled = skipEnabled;
|
|
59
|
+
|
|
60
|
+
// Callbacks for each stage action
|
|
61
|
+
this._onRetry = onRetry || (() => makeResult(false, null, { code: "SEND_FAILED", message: "retry not implemented" }));
|
|
62
|
+
this._onRebind = onRebind || (() => makeResult(false, null, { code: "DOM_CHANGED", message: "rebind not implemented" }));
|
|
63
|
+
this._onReload = onReload || (() => makeResult(false, null, { code: "TAB_CLOSED", message: "reload not implemented" }));
|
|
64
|
+
this._onFallback = onFallback || (() => makeResult(false, null, { code: "TIMEOUT", message: "fallback not implemented" }));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
reset() {
|
|
68
|
+
this.state = STATES.HEALTHY;
|
|
69
|
+
this.stageAttempts = { RETRYING: 0, REBINDING: 0, RELOADING: 0 };
|
|
70
|
+
this.startTime = null;
|
|
71
|
+
this.lastError = null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get elapsedMs() {
|
|
75
|
+
return this.startTime ? Date.now() - this.startTime : 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get totalBudgetMs() {
|
|
79
|
+
return 60000;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get isTerminal() {
|
|
83
|
+
return this.state === STATES.FAILED || this.state === STATES.FALLBACK;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Execute a turn with full degradation pipeline.
|
|
88
|
+
* @param {Function} primaryAction - async () => Result. The main action to attempt.
|
|
89
|
+
* @returns {Result} Final result after all degradation attempts.
|
|
90
|
+
*/
|
|
91
|
+
async execute(primaryAction) {
|
|
92
|
+
this.startTime = Date.now();
|
|
93
|
+
this.state = STATES.HEALTHY;
|
|
94
|
+
this.stageAttempts = { RETRYING: 0, REBINDING: 0, RELOADING: 0 };
|
|
95
|
+
|
|
96
|
+
// Stage 0: Primary attempt
|
|
97
|
+
const primaryResult = await this._timed(primaryAction);
|
|
98
|
+
if (primaryResult.ok) return primaryResult;
|
|
99
|
+
this.lastError = primaryResult.error;
|
|
100
|
+
|
|
101
|
+
// Check if permanent error — skip to FAILED
|
|
102
|
+
if (primaryResult.error && !primaryResult.error.retryable) {
|
|
103
|
+
this.state = STATES.FAILED;
|
|
104
|
+
return primaryResult;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Stage 1: Retry with backoff
|
|
108
|
+
this.state = STATES.RETRYING;
|
|
109
|
+
const retryResult = await this._stageRetry(primaryAction);
|
|
110
|
+
if (retryResult.ok) { this.state = STATES.HEALTHY; return retryResult; }
|
|
111
|
+
if (this._budgetExceeded()) return this._toFallback(retryResult);
|
|
112
|
+
|
|
113
|
+
// Stage 2: Rebind (DOM re-scan)
|
|
114
|
+
this.state = STATES.REBINDING;
|
|
115
|
+
const rebindResult = await this._stageRebind();
|
|
116
|
+
if (rebindResult.ok) {
|
|
117
|
+
// Rebind succeeded, retry primary once more
|
|
118
|
+
const afterRebind = await this._timed(primaryAction);
|
|
119
|
+
if (afterRebind.ok) { this.state = STATES.HEALTHY; return afterRebind; }
|
|
120
|
+
}
|
|
121
|
+
if (this._budgetExceeded()) return this._toFallback(rebindResult);
|
|
122
|
+
|
|
123
|
+
// Stage 3: Reload/Reopen
|
|
124
|
+
this.state = STATES.RELOADING;
|
|
125
|
+
const reloadResult = await this._stageReload();
|
|
126
|
+
if (reloadResult.ok) {
|
|
127
|
+
// After reload, retry primary once (auto-resend with turn_id idempotency)
|
|
128
|
+
const afterReload = await this._timed(primaryAction);
|
|
129
|
+
if (afterReload.ok) { this.state = STATES.HEALTHY; return afterReload; }
|
|
130
|
+
}
|
|
131
|
+
if (this._budgetExceeded()) return this._toFallback(reloadResult);
|
|
132
|
+
|
|
133
|
+
// Stage 4: Fallback
|
|
134
|
+
return this._toFallback(reloadResult);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async _stageRetry(action) {
|
|
138
|
+
const budget = STAGE_BUDGETS.RETRYING;
|
|
139
|
+
let lastResult = null;
|
|
140
|
+
for (let i = 0; i < budget.maxAttempts; i++) {
|
|
141
|
+
if (this._budgetExceeded()) break;
|
|
142
|
+
const delay = budget.backoffMs[i] || budget.backoffMs[budget.backoffMs.length - 1];
|
|
143
|
+
await this._sleep(delay);
|
|
144
|
+
this.stageAttempts.RETRYING++;
|
|
145
|
+
lastResult = await this._timed(action);
|
|
146
|
+
if (lastResult.ok) return lastResult;
|
|
147
|
+
this.lastError = lastResult.error;
|
|
148
|
+
}
|
|
149
|
+
return lastResult || makeResult(false, null, { code: "TIMEOUT", message: "retry exhausted" });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async _stageRebind() {
|
|
153
|
+
if (this._budgetExceeded()) return makeResult(false, null, { code: "TIMEOUT", message: "budget exceeded before rebind" });
|
|
154
|
+
this.stageAttempts.REBINDING++;
|
|
155
|
+
return this._timed(this._onRebind);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async _stageReload() {
|
|
159
|
+
if (this._budgetExceeded()) return makeResult(false, null, { code: "TIMEOUT", message: "budget exceeded before reload" });
|
|
160
|
+
this.stageAttempts.RELOADING++;
|
|
161
|
+
return this._timed(this._onReload);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async _toFallback(lastResult) {
|
|
165
|
+
this.state = STATES.FALLBACK;
|
|
166
|
+
const fallbackResult = await this._onFallback(lastResult);
|
|
167
|
+
if (!fallbackResult?.ok && !this.skipEnabled) {
|
|
168
|
+
this.state = STATES.FAILED;
|
|
169
|
+
}
|
|
170
|
+
return fallbackResult || makeResult(false, null, {
|
|
171
|
+
code: "TIMEOUT",
|
|
172
|
+
message: `All degradation stages exhausted (elapsed: ${this.elapsedMs}ms)`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_budgetExceeded() {
|
|
177
|
+
return this.elapsedMs >= this.totalBudgetMs;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async _timed(fn) {
|
|
181
|
+
try {
|
|
182
|
+
return await fn();
|
|
183
|
+
} catch (err) {
|
|
184
|
+
return makeResult(false, null, {
|
|
185
|
+
code: err.code || "UNKNOWN",
|
|
186
|
+
message: err.message || String(err),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
_sleep(ms) {
|
|
192
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
toJSON() {
|
|
196
|
+
return {
|
|
197
|
+
state: this.state,
|
|
198
|
+
elapsedMs: this.elapsedMs,
|
|
199
|
+
stageAttempts: { ...this.stageAttempts },
|
|
200
|
+
lastError: this.lastError,
|
|
201
|
+
skipEnabled: this.skipEnabled,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export { DegradationStateMachine, STATES, STAGE_BUDGETS, ERROR_CODES, makeResult };
|