gestalt-mobile 0.35.2 → 0.35.3
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.
|
@@ -2242,6 +2242,65 @@ describe('production composition', () => {
|
|
|
2242
2242
|
});
|
|
2243
2243
|
});
|
|
2244
2244
|
describeCompositionConcern('lifecycle', () => {
|
|
2245
|
+
it('rejects a wait lease when automatic continuation is unavailable', async () => {
|
|
2246
|
+
const root = await mkdtemp(join(tmpdir(), 'gestalt-mobile-root-'));
|
|
2247
|
+
const dataDir = await mkdtemp(join(tmpdir(), 'gestalt-mobile-state-'));
|
|
2248
|
+
ownTemporaryPaths(root, dataDir);
|
|
2249
|
+
await mkdir(join(root, 'workspace'));
|
|
2250
|
+
const handles = [];
|
|
2251
|
+
const app = await composeAuthorizedApp({
|
|
2252
|
+
root,
|
|
2253
|
+
dataDir,
|
|
2254
|
+
relyingParty,
|
|
2255
|
+
installedCodexVersion: 'codex-cli 0.144.3',
|
|
2256
|
+
startAppServers: true,
|
|
2257
|
+
launchAppServer: liveAppServer(handles),
|
|
2258
|
+
profiles: {
|
|
2259
|
+
list: async () => [],
|
|
2260
|
+
require: async () => ({
|
|
2261
|
+
name: 'default',
|
|
2262
|
+
state: 'ok',
|
|
2263
|
+
status: 'ready',
|
|
2264
|
+
}),
|
|
2265
|
+
},
|
|
2266
|
+
});
|
|
2267
|
+
const sessionId = await createComposedSession(app);
|
|
2268
|
+
const handle = handles.find((candidate) => candidate.calls.includes('thread/start'));
|
|
2269
|
+
const started = await app.inject({
|
|
2270
|
+
method: 'POST',
|
|
2271
|
+
url: `/api/sessions/${sessionId}/turns`,
|
|
2272
|
+
payload: { text: 'continue supervised work' },
|
|
2273
|
+
});
|
|
2274
|
+
const turnId = started.json().activeTurnId;
|
|
2275
|
+
const threadId = (await app.inject(`/api/sessions/${sessionId}`)).json().threadId;
|
|
2276
|
+
handle.notify?.({ method: 'turn/started', params: { threadId, turn: { id: turnId } } });
|
|
2277
|
+
await expect(handle.request({
|
|
2278
|
+
id: 89,
|
|
2279
|
+
method: 'item/tool/call',
|
|
2280
|
+
params: {
|
|
2281
|
+
threadId,
|
|
2282
|
+
turnId,
|
|
2283
|
+
tool: 'gestalt_autopilot_wait_lease',
|
|
2284
|
+
arguments: {
|
|
2285
|
+
version: 2,
|
|
2286
|
+
reportId: 'unavailable-report',
|
|
2287
|
+
leaseId: 'unavailable-lease',
|
|
2288
|
+
wakeConditions: ['executorChanged'],
|
|
2289
|
+
maxWaitMs: 60_000,
|
|
2290
|
+
},
|
|
2291
|
+
},
|
|
2292
|
+
})).resolves.toEqual({
|
|
2293
|
+
success: true,
|
|
2294
|
+
contentItems: [
|
|
2295
|
+
{
|
|
2296
|
+
type: 'inputText',
|
|
2297
|
+
text: '{"accepted":false,"reason":"automaticContinuationUnavailable","next":"continueSameTurn"}',
|
|
2298
|
+
},
|
|
2299
|
+
],
|
|
2300
|
+
});
|
|
2301
|
+
expect((await app.inject(`/api/sessions/${sessionId}`)).json().activeTurnId).toBe(turnId);
|
|
2302
|
+
await app.close();
|
|
2303
|
+
});
|
|
2245
2304
|
it('acknowledges root-owned capacity recovery before recycling only its app-server', async () => {
|
|
2246
2305
|
const root = await mkdtemp(join(tmpdir(), 'gestalt-mobile-root-'));
|
|
2247
2306
|
const dataDir = await mkdtemp(join(tmpdir(), 'gestalt-mobile-state-'));
|
|
@@ -581,7 +581,7 @@ export async function composeRelayApp(options) {
|
|
|
581
581
|
const rootOwned = origin.kind === 'root' && origin.physicalTurnId === session.activeTurnId;
|
|
582
582
|
if (rootOwned)
|
|
583
583
|
autopilot.rejectProbe(sessionId);
|
|
584
|
-
return (runtime?.resolveServerRequest(sessionId, String(request.id), autopilotWaitLeaseToolResponse()) === true);
|
|
584
|
+
return (runtime?.resolveServerRequest(sessionId, String(request.id), autopilotWaitLeaseToolResponse(false)) === true);
|
|
585
585
|
}
|
|
586
586
|
if (!rawInteraction)
|
|
587
587
|
return false;
|
|
@@ -605,7 +605,7 @@ export async function composeRelayApp(options) {
|
|
|
605
605
|
if (!accepted) {
|
|
606
606
|
if (rootOwned)
|
|
607
607
|
autopilot.rejectProbe(sessionId);
|
|
608
|
-
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, autopilotWaitLeaseToolResponse()) === true);
|
|
608
|
+
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, autopilotWaitLeaseToolResponse(false)) === true);
|
|
609
609
|
}
|
|
610
610
|
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, autopilotWaitLeaseToolResponse()) === true);
|
|
611
611
|
}
|
|
@@ -20,7 +20,7 @@ export const AUTOPILOT_WAIT_MAX_MS = 86_400_000;
|
|
|
20
20
|
export const gestaltAutopilotWaitLeaseDynamicTool = {
|
|
21
21
|
type: 'function',
|
|
22
22
|
name: GESTALT_AUTOPILOT_WAIT_LEASE_TOOL_NAME,
|
|
23
|
-
description: 'Register one non-persistent Autopilot wait episode for the current supervised session. Version 2 may be called proactively for known long work and resumes on the first requested event or bounded maxWaitMs deadline; call it again in a later turn only if another long wait is justified. This cannot request human authority and never accepts transcript prose.',
|
|
23
|
+
description: 'Register one non-persistent Autopilot wait episode for the current supervised session. Version 2 may be called proactively for known long work and resumes on the first requested event or bounded maxWaitMs deadline; call it again in a later turn only if another long wait is justified. Yield only when the response has accepted:true; accepted:false requires same-turn supervision. This cannot request human authority and never accepts transcript prose.',
|
|
24
24
|
inputSchema: {
|
|
25
25
|
type: 'object',
|
|
26
26
|
additionalProperties: false,
|
|
@@ -74,8 +74,18 @@ export function parseAutopilotWaitLease(value) {
|
|
|
74
74
|
maxWaitMs: value.maxWaitMs,
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
-
export function autopilotWaitLeaseToolResponse() {
|
|
78
|
-
return {
|
|
77
|
+
export function autopilotWaitLeaseToolResponse(accepted = true) {
|
|
78
|
+
return {
|
|
79
|
+
success: true,
|
|
80
|
+
contentItems: [
|
|
81
|
+
{
|
|
82
|
+
type: 'inputText',
|
|
83
|
+
text: accepted
|
|
84
|
+
? '{"accepted":true}'
|
|
85
|
+
: '{"accepted":false,"reason":"automaticContinuationUnavailable","next":"continueSameTurn"}',
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
79
89
|
}
|
|
80
90
|
function record(value) {
|
|
81
91
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|