@akagilnc/pi-workflow-roles 0.1.5797 → 0.1.5805
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/acp-host/production-host.js +74 -49
- package/dist/engine-detour-tool.js +51 -37
- package/dist/engine-detour.js +22 -11
- package/dist/headless-host/production-host.js +74 -49
- package/package.json +1 -1
- package/resources/engine-dispatch.md +6 -6
- package/resources/engines/agy.md +1 -1
- package/src/engine-detour-tool.ts +88 -57
- package/src/engine-detour.ts +31 -14
- package/src/host-contracts.ts +7 -0
- package/src/role-envelope.ts +3 -1
- package/src/role-runtime.ts +1 -1
|
@@ -1425,18 +1425,29 @@ async function runEngineDetourOnce(input) {
|
|
|
1425
1425
|
function isEngineDetourFailure(result) {
|
|
1426
1426
|
return result.code !== 0 || result.stdout.trim() === "";
|
|
1427
1427
|
}
|
|
1428
|
-
function
|
|
1429
|
-
|
|
1430
|
-
if (result.stdout.
|
|
1431
|
-
|
|
1432
|
-
let
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1428
|
+
function engineDetourFailureSeatText(result) {
|
|
1429
|
+
const parts = [];
|
|
1430
|
+
if (result.stdout.length > 0) parts.push(result.stdout);
|
|
1431
|
+
if (result.stderr.length > 0) parts.push(result.stderr);
|
|
1432
|
+
let text = "";
|
|
1433
|
+
if (parts.length > 0) {
|
|
1434
|
+
text = parts[0];
|
|
1435
|
+
for (let index = 1; index < parts.length; index += 1) {
|
|
1436
|
+
if (!text.endsWith("\n")) text += "\n";
|
|
1437
|
+
text += parts[index];
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
const append = (line2) => {
|
|
1441
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
1442
|
+
text += line2;
|
|
1443
|
+
};
|
|
1444
|
+
if (result.code !== 0) {
|
|
1445
|
+
append(`\u52B3\u52A1\u5F15\u64CE\u4EE5 code ${result.code} \u9000\u51FA`);
|
|
1446
|
+
}
|
|
1447
|
+
if (result.stdout.trim() === "") {
|
|
1448
|
+
append(ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC);
|
|
1438
1449
|
}
|
|
1439
|
-
return
|
|
1450
|
+
return text.length > 0 ? text : ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC;
|
|
1440
1451
|
}
|
|
1441
1452
|
function engineNameFromEnv() {
|
|
1442
1453
|
return normalizeEngineName(
|
|
@@ -21065,6 +21076,7 @@ init_engine_material();
|
|
|
21065
21076
|
init_engine_detour();
|
|
21066
21077
|
init_engine_detour_usage();
|
|
21067
21078
|
init_run_terminal_artifacts();
|
|
21079
|
+
init_serialize_thrown_value();
|
|
21068
21080
|
import { Type as Type18 } from "typebox";
|
|
21069
21081
|
var engineDetourArgsSchema = Type18.Object(
|
|
21070
21082
|
{
|
|
@@ -21085,6 +21097,27 @@ function isCallerCancellation(error, signal) {
|
|
|
21085
21097
|
function asError(error, fallback) {
|
|
21086
21098
|
return error instanceof Error ? error : new Error(String(error).trim() || fallback);
|
|
21087
21099
|
}
|
|
21100
|
+
function engineFailureResult(input) {
|
|
21101
|
+
const details = {
|
|
21102
|
+
tool: ENGINE_DETOUR_TOOL_NAME,
|
|
21103
|
+
...input.code === void 0 ? {} : { code: input.code },
|
|
21104
|
+
...input.stdout === void 0 ? {} : { stdout: input.stdout },
|
|
21105
|
+
...input.stderr === void 0 ? {} : { stderr: input.stderr },
|
|
21106
|
+
...input.errorCode === void 0 ? {} : { errorCode: input.errorCode },
|
|
21107
|
+
...input.ledgerError === void 0 ? {} : { ledgerError: input.ledgerError }
|
|
21108
|
+
};
|
|
21109
|
+
let text = input.text;
|
|
21110
|
+
if (input.ledgerError !== void 0 && input.ledgerError.length > 0) {
|
|
21111
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
21112
|
+
text += input.ledgerError;
|
|
21113
|
+
}
|
|
21114
|
+
return {
|
|
21115
|
+
content: [{ type: "text", text }],
|
|
21116
|
+
details,
|
|
21117
|
+
// Identified detour failure is a tool error, not a seat-run death (#1213).
|
|
21118
|
+
isError: true
|
|
21119
|
+
};
|
|
21120
|
+
}
|
|
21088
21121
|
function createEngineDetourToolDefinition(input) {
|
|
21089
21122
|
const engineName = input.engineName;
|
|
21090
21123
|
const engineModel = input.engineModel;
|
|
@@ -21098,13 +21131,6 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21098
21131
|
async execute(toolCallId, params, signal, _onUpdate, ctx) {
|
|
21099
21132
|
const args = params;
|
|
21100
21133
|
const argv = Array.isArray(args.argv) ? args.argv : [];
|
|
21101
|
-
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
21102
|
-
input.fail(
|
|
21103
|
-
new Error("\u52B3\u52A1\u5F15\u64CE argv \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4"),
|
|
21104
|
-
toolCallId,
|
|
21105
|
-
ctx
|
|
21106
|
-
);
|
|
21107
|
-
}
|
|
21108
21134
|
const sessionParent = ctx.sessionManager?.getSessionFile?.();
|
|
21109
21135
|
const startedAt = Date.now();
|
|
21110
21136
|
const runDirectory = typeof ctx.runDirectory === "string" && ctx.runDirectory.length > 0 ? ctx.runDirectory : void 0;
|
|
@@ -21125,25 +21151,21 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21125
21151
|
...observed2.stdoutByteLength === void 0 ? {} : { stdoutByteLength: observed2.stdoutByteLength }
|
|
21126
21152
|
});
|
|
21127
21153
|
};
|
|
21128
|
-
const
|
|
21154
|
+
const recordCallOrLedgerError = (observed2) => {
|
|
21129
21155
|
try {
|
|
21130
21156
|
recordCall(observed2);
|
|
21157
|
+
return void 0;
|
|
21131
21158
|
} catch (recordError) {
|
|
21132
|
-
|
|
21133
|
-
new AggregateError(
|
|
21134
|
-
[
|
|
21135
|
-
engineCause,
|
|
21136
|
-
asError(recordError, "engine detour usage ledger write failed")
|
|
21137
|
-
],
|
|
21138
|
-
aggregateMessage,
|
|
21139
|
-
{ cause: engineCause }
|
|
21140
|
-
),
|
|
21141
|
-
toolCallId,
|
|
21142
|
-
ctx
|
|
21143
|
-
);
|
|
21159
|
+
return serializeThrownValue(recordError);
|
|
21144
21160
|
}
|
|
21145
|
-
input.fail(engineCause, toolCallId, ctx);
|
|
21146
21161
|
};
|
|
21162
|
+
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
21163
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
21164
|
+
return engineFailureResult({
|
|
21165
|
+
text: "\u52B3\u52A1\u5F15\u64CE argv \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4",
|
|
21166
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
21167
|
+
});
|
|
21168
|
+
}
|
|
21147
21169
|
let result;
|
|
21148
21170
|
try {
|
|
21149
21171
|
result = await runEngineDetourOnce({
|
|
@@ -21153,20 +21175,26 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21153
21175
|
});
|
|
21154
21176
|
} catch (error) {
|
|
21155
21177
|
if (isCallerCancellation(error, signal)) throw error;
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21178
|
+
const engineError = asError(error, "\u52B3\u52A1\u5F15\u64CE spawn \u5931\u8D25");
|
|
21179
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
21180
|
+
const errno = typeof engineError.code === "string" ? engineError.code : void 0;
|
|
21181
|
+
return engineFailureResult({
|
|
21182
|
+
text: engineError.message,
|
|
21183
|
+
...errno === void 0 ? {} : { errorCode: errno },
|
|
21184
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
21185
|
+
});
|
|
21161
21186
|
}
|
|
21162
21187
|
const stdoutByteLength = engineDetourStdoutByteLength(result.stdout);
|
|
21163
21188
|
const observed = { code: result.code, stdoutByteLength };
|
|
21164
21189
|
if (isEngineDetourFailure(result)) {
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21190
|
+
const ledgerError = recordCallOrLedgerError(observed);
|
|
21191
|
+
return engineFailureResult({
|
|
21192
|
+
text: engineDetourFailureSeatText(result),
|
|
21193
|
+
code: result.code,
|
|
21194
|
+
stdout: result.stdout,
|
|
21195
|
+
stderr: result.stderr,
|
|
21196
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
21197
|
+
});
|
|
21170
21198
|
}
|
|
21171
21199
|
recordCall(observed);
|
|
21172
21200
|
return {
|
|
@@ -21180,7 +21208,7 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21180
21208
|
}
|
|
21181
21209
|
};
|
|
21182
21210
|
}
|
|
21183
|
-
function registerEngineDetourTool(roleHost
|
|
21211
|
+
function registerEngineDetourTool(roleHost) {
|
|
21184
21212
|
const getFlag = (name) => roleHost.getFlag(name);
|
|
21185
21213
|
const engineName = resolveEngineName(getFlag);
|
|
21186
21214
|
if (engineName === void 0) {
|
|
@@ -21189,10 +21217,7 @@ function registerEngineDetourTool(roleHost, hostActions) {
|
|
|
21189
21217
|
const engineModel = resolveEngineModel(getFlag);
|
|
21190
21218
|
const definition = createEngineDetourToolDefinition({
|
|
21191
21219
|
engineName,
|
|
21192
|
-
...engineModel === void 0 ? {} : { engineModel }
|
|
21193
|
-
fail(error, toolCallId, ctx) {
|
|
21194
|
-
hostActions.failInfrastructure(error, ctx, toolCallId);
|
|
21195
|
-
}
|
|
21220
|
+
...engineModel === void 0 ? {} : { engineModel }
|
|
21196
21221
|
});
|
|
21197
21222
|
roleHost.registerTool(definition);
|
|
21198
21223
|
return true;
|
|
@@ -24128,7 +24153,7 @@ function createRoleRuntimeExtension(dependencies, deliveryRequestLimit) {
|
|
|
24128
24153
|
]);
|
|
24129
24154
|
roleReferenceMaterials = await dependencies.loadRoleReferenceMaterials?.(entry.role) ?? "";
|
|
24130
24155
|
if (!engineDetourRegistered) {
|
|
24131
|
-
engineDetourRegistered = registerEngineDetourTool(roleHost
|
|
24156
|
+
engineDetourRegistered = registerEngineDetourTool(roleHost);
|
|
24132
24157
|
}
|
|
24133
24158
|
if (secretariat.claimsEngineDetour === true && engineDetourRegistered) {
|
|
24134
24159
|
roleHost.setActiveTools([
|
|
@@ -24501,7 +24526,7 @@ async function prepareRoleEnvelope(options) {
|
|
|
24501
24526
|
const projected = await projectToolResult(toolCallId, name, {
|
|
24502
24527
|
content: result.content,
|
|
24503
24528
|
details: result.details,
|
|
24504
|
-
isError:
|
|
24529
|
+
isError: result.isError === true
|
|
24505
24530
|
});
|
|
24506
24531
|
if (result.terminate === false) {
|
|
24507
24532
|
rejection = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import {
|
|
3
3
|
ENGINE_DETOUR_TOOL_NAME,
|
|
4
|
-
|
|
4
|
+
engineDetourFailureSeatText,
|
|
5
5
|
isEngineDetourFailure,
|
|
6
6
|
resolveEngineModel,
|
|
7
7
|
resolveEngineName,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
reportEngineDetourCall
|
|
13
13
|
} from "./engine-detour-usage.js";
|
|
14
14
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.js";
|
|
15
|
+
import { serializeThrownValue } from "./serialize-thrown-value.js";
|
|
15
16
|
const engineDetourArgsSchema = Type.Object(
|
|
16
17
|
{
|
|
17
18
|
argv: Type.Array(Type.String({ minLength: 1 }), {
|
|
@@ -31,6 +32,27 @@ function isCallerCancellation(error, signal) {
|
|
|
31
32
|
function asError(error, fallback) {
|
|
32
33
|
return error instanceof Error ? error : new Error(String(error).trim() || fallback);
|
|
33
34
|
}
|
|
35
|
+
function engineFailureResult(input) {
|
|
36
|
+
const details = {
|
|
37
|
+
tool: ENGINE_DETOUR_TOOL_NAME,
|
|
38
|
+
...input.code === void 0 ? {} : { code: input.code },
|
|
39
|
+
...input.stdout === void 0 ? {} : { stdout: input.stdout },
|
|
40
|
+
...input.stderr === void 0 ? {} : { stderr: input.stderr },
|
|
41
|
+
...input.errorCode === void 0 ? {} : { errorCode: input.errorCode },
|
|
42
|
+
...input.ledgerError === void 0 ? {} : { ledgerError: input.ledgerError }
|
|
43
|
+
};
|
|
44
|
+
let text = input.text;
|
|
45
|
+
if (input.ledgerError !== void 0 && input.ledgerError.length > 0) {
|
|
46
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
47
|
+
text += input.ledgerError;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text }],
|
|
51
|
+
details,
|
|
52
|
+
// Identified detour failure is a tool error, not a seat-run death (#1213).
|
|
53
|
+
isError: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
34
56
|
function createEngineDetourToolDefinition(input) {
|
|
35
57
|
const engineName = input.engineName;
|
|
36
58
|
const engineModel = input.engineModel;
|
|
@@ -44,13 +66,6 @@ function createEngineDetourToolDefinition(input) {
|
|
|
44
66
|
async execute(toolCallId, params, signal, _onUpdate, ctx) {
|
|
45
67
|
const args = params;
|
|
46
68
|
const argv = Array.isArray(args.argv) ? args.argv : [];
|
|
47
|
-
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
48
|
-
input.fail(
|
|
49
|
-
new Error("\u52B3\u52A1\u5F15\u64CE argv \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4"),
|
|
50
|
-
toolCallId,
|
|
51
|
-
ctx
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
69
|
const sessionParent = ctx.sessionManager?.getSessionFile?.();
|
|
55
70
|
const startedAt = Date.now();
|
|
56
71
|
const runDirectory = typeof ctx.runDirectory === "string" && ctx.runDirectory.length > 0 ? ctx.runDirectory : void 0;
|
|
@@ -71,25 +86,21 @@ function createEngineDetourToolDefinition(input) {
|
|
|
71
86
|
...observed2.stdoutByteLength === void 0 ? {} : { stdoutByteLength: observed2.stdoutByteLength }
|
|
72
87
|
});
|
|
73
88
|
};
|
|
74
|
-
const
|
|
89
|
+
const recordCallOrLedgerError = (observed2) => {
|
|
75
90
|
try {
|
|
76
91
|
recordCall(observed2);
|
|
92
|
+
return void 0;
|
|
77
93
|
} catch (recordError) {
|
|
78
|
-
|
|
79
|
-
new AggregateError(
|
|
80
|
-
[
|
|
81
|
-
engineCause,
|
|
82
|
-
asError(recordError, "engine detour usage ledger write failed")
|
|
83
|
-
],
|
|
84
|
-
aggregateMessage,
|
|
85
|
-
{ cause: engineCause }
|
|
86
|
-
),
|
|
87
|
-
toolCallId,
|
|
88
|
-
ctx
|
|
89
|
-
);
|
|
94
|
+
return serializeThrownValue(recordError);
|
|
90
95
|
}
|
|
91
|
-
input.fail(engineCause, toolCallId, ctx);
|
|
92
96
|
};
|
|
97
|
+
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
98
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
99
|
+
return engineFailureResult({
|
|
100
|
+
text: "\u52B3\u52A1\u5F15\u64CE argv \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4",
|
|
101
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
102
|
+
});
|
|
103
|
+
}
|
|
93
104
|
let result;
|
|
94
105
|
try {
|
|
95
106
|
result = await runEngineDetourOnce({
|
|
@@ -99,20 +110,26 @@ function createEngineDetourToolDefinition(input) {
|
|
|
99
110
|
});
|
|
100
111
|
} catch (error) {
|
|
101
112
|
if (isCallerCancellation(error, signal)) throw error;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
const engineError = asError(error, "\u52B3\u52A1\u5F15\u64CE spawn \u5931\u8D25");
|
|
114
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
115
|
+
const errno = typeof engineError.code === "string" ? engineError.code : void 0;
|
|
116
|
+
return engineFailureResult({
|
|
117
|
+
text: engineError.message,
|
|
118
|
+
...errno === void 0 ? {} : { errorCode: errno },
|
|
119
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
120
|
+
});
|
|
107
121
|
}
|
|
108
122
|
const stdoutByteLength = engineDetourStdoutByteLength(result.stdout);
|
|
109
123
|
const observed = { code: result.code, stdoutByteLength };
|
|
110
124
|
if (isEngineDetourFailure(result)) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
125
|
+
const ledgerError = recordCallOrLedgerError(observed);
|
|
126
|
+
return engineFailureResult({
|
|
127
|
+
text: engineDetourFailureSeatText(result),
|
|
128
|
+
code: result.code,
|
|
129
|
+
stdout: result.stdout,
|
|
130
|
+
stderr: result.stderr,
|
|
131
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
132
|
+
});
|
|
116
133
|
}
|
|
117
134
|
recordCall(observed);
|
|
118
135
|
return {
|
|
@@ -126,7 +143,7 @@ function createEngineDetourToolDefinition(input) {
|
|
|
126
143
|
}
|
|
127
144
|
};
|
|
128
145
|
}
|
|
129
|
-
function registerEngineDetourTool(roleHost
|
|
146
|
+
function registerEngineDetourTool(roleHost) {
|
|
130
147
|
const getFlag = (name) => roleHost.getFlag(name);
|
|
131
148
|
const engineName = resolveEngineName(getFlag);
|
|
132
149
|
if (engineName === void 0) {
|
|
@@ -135,10 +152,7 @@ function registerEngineDetourTool(roleHost, hostActions) {
|
|
|
135
152
|
const engineModel = resolveEngineModel(getFlag);
|
|
136
153
|
const definition = createEngineDetourToolDefinition({
|
|
137
154
|
engineName,
|
|
138
|
-
...engineModel === void 0 ? {} : { engineModel }
|
|
139
|
-
fail(error, toolCallId, ctx) {
|
|
140
|
-
hostActions.failInfrastructure(error, ctx, toolCallId);
|
|
141
|
-
}
|
|
155
|
+
...engineModel === void 0 ? {} : { engineModel }
|
|
142
156
|
});
|
|
143
157
|
roleHost.registerTool(definition);
|
|
144
158
|
return true;
|
package/dist/engine-detour.js
CHANGED
|
@@ -89,18 +89,29 @@ async function runEngineDetourOnce(input) {
|
|
|
89
89
|
function isEngineDetourFailure(result) {
|
|
90
90
|
return result.code !== 0 || result.stdout.trim() === "";
|
|
91
91
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
if (result.stdout.
|
|
95
|
-
|
|
96
|
-
let
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
function engineDetourFailureSeatText(result) {
|
|
93
|
+
const parts = [];
|
|
94
|
+
if (result.stdout.length > 0) parts.push(result.stdout);
|
|
95
|
+
if (result.stderr.length > 0) parts.push(result.stderr);
|
|
96
|
+
let text = "";
|
|
97
|
+
if (parts.length > 0) {
|
|
98
|
+
text = parts[0];
|
|
99
|
+
for (let index = 1; index < parts.length; index += 1) {
|
|
100
|
+
if (!text.endsWith("\n")) text += "\n";
|
|
101
|
+
text += parts[index];
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
+
const append = (line) => {
|
|
105
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
106
|
+
text += line;
|
|
107
|
+
};
|
|
108
|
+
if (result.code !== 0) {
|
|
109
|
+
append(`\u52B3\u52A1\u5F15\u64CE\u4EE5 code ${result.code} \u9000\u51FA`);
|
|
110
|
+
}
|
|
111
|
+
if (result.stdout.trim() === "") {
|
|
112
|
+
append(ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC);
|
|
113
|
+
}
|
|
114
|
+
return text.length > 0 ? text : ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC;
|
|
104
115
|
}
|
|
105
116
|
function engineNameFromEnv() {
|
|
106
117
|
return normalizeEngineName(
|
|
@@ -127,7 +138,7 @@ export {
|
|
|
127
138
|
ENGINE_FLAG_NAME,
|
|
128
139
|
ENGINE_MODEL_FLAG_NAME,
|
|
129
140
|
applyEngineChildEnv,
|
|
130
|
-
|
|
141
|
+
engineDetourFailureSeatText,
|
|
131
142
|
engineNameFromEnv,
|
|
132
143
|
isEngineDetourFailure,
|
|
133
144
|
normalizeEngineName,
|
|
@@ -5808,18 +5808,29 @@ async function runEngineDetourOnce(input) {
|
|
|
5808
5808
|
function isEngineDetourFailure(result) {
|
|
5809
5809
|
return result.code !== 0 || result.stdout.trim() === "";
|
|
5810
5810
|
}
|
|
5811
|
-
function
|
|
5812
|
-
|
|
5813
|
-
if (result.stdout.
|
|
5814
|
-
|
|
5815
|
-
let
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5811
|
+
function engineDetourFailureSeatText(result) {
|
|
5812
|
+
const parts = [];
|
|
5813
|
+
if (result.stdout.length > 0) parts.push(result.stdout);
|
|
5814
|
+
if (result.stderr.length > 0) parts.push(result.stderr);
|
|
5815
|
+
let text = "";
|
|
5816
|
+
if (parts.length > 0) {
|
|
5817
|
+
text = parts[0];
|
|
5818
|
+
for (let index = 1; index < parts.length; index += 1) {
|
|
5819
|
+
if (!text.endsWith("\n")) text += "\n";
|
|
5820
|
+
text += parts[index];
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
const append = (line2) => {
|
|
5824
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
5825
|
+
text += line2;
|
|
5826
|
+
};
|
|
5827
|
+
if (result.code !== 0) {
|
|
5828
|
+
append(`\u52B3\u52A1\u5F15\u64CE\u4EE5 code ${result.code} \u9000\u51FA`);
|
|
5829
|
+
}
|
|
5830
|
+
if (result.stdout.trim() === "") {
|
|
5831
|
+
append(ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC);
|
|
5821
5832
|
}
|
|
5822
|
-
return
|
|
5833
|
+
return text.length > 0 ? text : ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC;
|
|
5823
5834
|
}
|
|
5824
5835
|
function engineNameFromEnv() {
|
|
5825
5836
|
return normalizeEngineName(
|
|
@@ -21875,6 +21886,7 @@ init_engine_material();
|
|
|
21875
21886
|
init_engine_detour();
|
|
21876
21887
|
init_engine_detour_usage();
|
|
21877
21888
|
init_run_terminal_artifacts();
|
|
21889
|
+
init_serialize_thrown_value();
|
|
21878
21890
|
import { Type as Type19 } from "typebox";
|
|
21879
21891
|
var engineDetourArgsSchema = Type19.Object(
|
|
21880
21892
|
{
|
|
@@ -21895,6 +21907,27 @@ function isCallerCancellation(error, signal) {
|
|
|
21895
21907
|
function asError(error, fallback) {
|
|
21896
21908
|
return error instanceof Error ? error : new Error(String(error).trim() || fallback);
|
|
21897
21909
|
}
|
|
21910
|
+
function engineFailureResult(input) {
|
|
21911
|
+
const details = {
|
|
21912
|
+
tool: ENGINE_DETOUR_TOOL_NAME,
|
|
21913
|
+
...input.code === void 0 ? {} : { code: input.code },
|
|
21914
|
+
...input.stdout === void 0 ? {} : { stdout: input.stdout },
|
|
21915
|
+
...input.stderr === void 0 ? {} : { stderr: input.stderr },
|
|
21916
|
+
...input.errorCode === void 0 ? {} : { errorCode: input.errorCode },
|
|
21917
|
+
...input.ledgerError === void 0 ? {} : { ledgerError: input.ledgerError }
|
|
21918
|
+
};
|
|
21919
|
+
let text = input.text;
|
|
21920
|
+
if (input.ledgerError !== void 0 && input.ledgerError.length > 0) {
|
|
21921
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
21922
|
+
text += input.ledgerError;
|
|
21923
|
+
}
|
|
21924
|
+
return {
|
|
21925
|
+
content: [{ type: "text", text }],
|
|
21926
|
+
details,
|
|
21927
|
+
// Identified detour failure is a tool error, not a seat-run death (#1213).
|
|
21928
|
+
isError: true
|
|
21929
|
+
};
|
|
21930
|
+
}
|
|
21898
21931
|
function createEngineDetourToolDefinition(input) {
|
|
21899
21932
|
const engineName = input.engineName;
|
|
21900
21933
|
const engineModel = input.engineModel;
|
|
@@ -21908,13 +21941,6 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21908
21941
|
async execute(toolCallId, params, signal, _onUpdate, ctx) {
|
|
21909
21942
|
const args = params;
|
|
21910
21943
|
const argv = Array.isArray(args.argv) ? args.argv : [];
|
|
21911
|
-
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
21912
|
-
input.fail(
|
|
21913
|
-
new Error("\u52B3\u52A1\u5F15\u64CE argv \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4"),
|
|
21914
|
-
toolCallId,
|
|
21915
|
-
ctx
|
|
21916
|
-
);
|
|
21917
|
-
}
|
|
21918
21944
|
const sessionParent = ctx.sessionManager?.getSessionFile?.();
|
|
21919
21945
|
const startedAt = Date.now();
|
|
21920
21946
|
const runDirectory = typeof ctx.runDirectory === "string" && ctx.runDirectory.length > 0 ? ctx.runDirectory : void 0;
|
|
@@ -21935,25 +21961,21 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21935
21961
|
...observed2.stdoutByteLength === void 0 ? {} : { stdoutByteLength: observed2.stdoutByteLength }
|
|
21936
21962
|
});
|
|
21937
21963
|
};
|
|
21938
|
-
const
|
|
21964
|
+
const recordCallOrLedgerError = (observed2) => {
|
|
21939
21965
|
try {
|
|
21940
21966
|
recordCall(observed2);
|
|
21967
|
+
return void 0;
|
|
21941
21968
|
} catch (recordError) {
|
|
21942
|
-
|
|
21943
|
-
new AggregateError(
|
|
21944
|
-
[
|
|
21945
|
-
engineCause,
|
|
21946
|
-
asError(recordError, "engine detour usage ledger write failed")
|
|
21947
|
-
],
|
|
21948
|
-
aggregateMessage,
|
|
21949
|
-
{ cause: engineCause }
|
|
21950
|
-
),
|
|
21951
|
-
toolCallId,
|
|
21952
|
-
ctx
|
|
21953
|
-
);
|
|
21969
|
+
return serializeThrownValue(recordError);
|
|
21954
21970
|
}
|
|
21955
|
-
input.fail(engineCause, toolCallId, ctx);
|
|
21956
21971
|
};
|
|
21972
|
+
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
21973
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
21974
|
+
return engineFailureResult({
|
|
21975
|
+
text: "\u52B3\u52A1\u5F15\u64CE argv \u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4",
|
|
21976
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
21977
|
+
});
|
|
21978
|
+
}
|
|
21957
21979
|
let result;
|
|
21958
21980
|
try {
|
|
21959
21981
|
result = await runEngineDetourOnce({
|
|
@@ -21963,20 +21985,26 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21963
21985
|
});
|
|
21964
21986
|
} catch (error) {
|
|
21965
21987
|
if (isCallerCancellation(error, signal)) throw error;
|
|
21966
|
-
|
|
21967
|
-
|
|
21968
|
-
|
|
21969
|
-
|
|
21970
|
-
|
|
21988
|
+
const engineError = asError(error, "\u52B3\u52A1\u5F15\u64CE spawn \u5931\u8D25");
|
|
21989
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
21990
|
+
const errno = typeof engineError.code === "string" ? engineError.code : void 0;
|
|
21991
|
+
return engineFailureResult({
|
|
21992
|
+
text: engineError.message,
|
|
21993
|
+
...errno === void 0 ? {} : { errorCode: errno },
|
|
21994
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
21995
|
+
});
|
|
21971
21996
|
}
|
|
21972
21997
|
const stdoutByteLength = engineDetourStdoutByteLength(result.stdout);
|
|
21973
21998
|
const observed = { code: result.code, stdoutByteLength };
|
|
21974
21999
|
if (isEngineDetourFailure(result)) {
|
|
21975
|
-
|
|
21976
|
-
|
|
21977
|
-
|
|
21978
|
-
|
|
21979
|
-
|
|
22000
|
+
const ledgerError = recordCallOrLedgerError(observed);
|
|
22001
|
+
return engineFailureResult({
|
|
22002
|
+
text: engineDetourFailureSeatText(result),
|
|
22003
|
+
code: result.code,
|
|
22004
|
+
stdout: result.stdout,
|
|
22005
|
+
stderr: result.stderr,
|
|
22006
|
+
...ledgerError === void 0 ? {} : { ledgerError }
|
|
22007
|
+
});
|
|
21980
22008
|
}
|
|
21981
22009
|
recordCall(observed);
|
|
21982
22010
|
return {
|
|
@@ -21990,7 +22018,7 @@ function createEngineDetourToolDefinition(input) {
|
|
|
21990
22018
|
}
|
|
21991
22019
|
};
|
|
21992
22020
|
}
|
|
21993
|
-
function registerEngineDetourTool(roleHost
|
|
22021
|
+
function registerEngineDetourTool(roleHost) {
|
|
21994
22022
|
const getFlag = (name) => roleHost.getFlag(name);
|
|
21995
22023
|
const engineName = resolveEngineName(getFlag);
|
|
21996
22024
|
if (engineName === void 0) {
|
|
@@ -21999,10 +22027,7 @@ function registerEngineDetourTool(roleHost, hostActions) {
|
|
|
21999
22027
|
const engineModel = resolveEngineModel(getFlag);
|
|
22000
22028
|
const definition = createEngineDetourToolDefinition({
|
|
22001
22029
|
engineName,
|
|
22002
|
-
...engineModel === void 0 ? {} : { engineModel }
|
|
22003
|
-
fail(error, toolCallId, ctx) {
|
|
22004
|
-
hostActions.failInfrastructure(error, ctx, toolCallId);
|
|
22005
|
-
}
|
|
22030
|
+
...engineModel === void 0 ? {} : { engineModel }
|
|
22006
22031
|
});
|
|
22007
22032
|
roleHost.registerTool(definition);
|
|
22008
22033
|
return true;
|
|
@@ -24148,7 +24173,7 @@ function createRoleRuntimeExtension(dependencies, deliveryRequestLimit) {
|
|
|
24148
24173
|
]);
|
|
24149
24174
|
roleReferenceMaterials = await dependencies.loadRoleReferenceMaterials?.(entry.role) ?? "";
|
|
24150
24175
|
if (!engineDetourRegistered) {
|
|
24151
|
-
engineDetourRegistered = registerEngineDetourTool(roleHost
|
|
24176
|
+
engineDetourRegistered = registerEngineDetourTool(roleHost);
|
|
24152
24177
|
}
|
|
24153
24178
|
if (secretariat.claimsEngineDetour === true && engineDetourRegistered) {
|
|
24154
24179
|
roleHost.setActiveTools([
|
|
@@ -24572,7 +24597,7 @@ async function prepareRoleEnvelope(options) {
|
|
|
24572
24597
|
const projected = await projectToolResult(toolCallId, name, {
|
|
24573
24598
|
content: result.content,
|
|
24574
24599
|
details: result.details,
|
|
24575
|
-
isError:
|
|
24600
|
+
isError: result.isError === true
|
|
24576
24601
|
});
|
|
24577
24602
|
if (result.terminate === false) {
|
|
24578
24603
|
rejection = {
|
package/package.json
CHANGED
|
@@ -45,9 +45,9 @@ themselves. Stuffing large bodies into argv/prompt is the verified cause of
|
|
|
45
45
|
|
|
46
46
|
## Failure handling
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
connection-drop, or other engine-process failure,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
Prefer outsourcing labor to the selected engine rather than doing the work
|
|
49
|
+
in-seat (尽量外包,别自己干). On spawn, auth, quota, model-id, stream-stall,
|
|
50
|
+
connection-drop, or other engine-process failure, the real failure and any
|
|
51
|
+
process result come back to this same session; decide next steps here (retry,
|
|
52
|
+
report, or submit through the existing path). Do not silently swap to another
|
|
53
|
+
engine id.
|
package/resources/engines/agy.md
CHANGED
|
@@ -35,6 +35,6 @@ agy --sandbox --dangerously-skip-permissions --print 'YOUR_LABOR_PROMPT' --log-f
|
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
When the dispatch order names a model, pass it verbatim via `--model`; an
|
|
38
|
-
unknown model id is an engine-process failure (
|
|
38
|
+
unknown model id is an engine-process failure (returned to this seat — per
|
|
39
39
|
`../engine-dispatch.md`). Never copy a model id from this note or from a
|
|
40
40
|
previous run — ids here would go stale.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Package-owned engine detour tool (#357 T2 / #378 / #380).
|
|
2
|
+
* Package-owned engine detour tool (#357 T2 / #378 / #380 / #1213).
|
|
3
3
|
* Registered by shared role-runtime when any role + engine activation signal is present.
|
|
4
4
|
* Evidence-child legs install the same definition via customTools (no spawn in role modules).
|
|
5
|
-
* Engine process failures
|
|
5
|
+
* Engine process failures return as tool results to the same seat session — the package
|
|
6
|
+
* does not abort the seat run on their behalf (#1213).
|
|
6
7
|
* Caller AbortSignal cancellation propagates unchanged.
|
|
7
8
|
*/
|
|
8
9
|
import { Type, type Static } from "typebox";
|
|
@@ -10,7 +11,7 @@ import type { HostContext, HostToolDefinition, HostToolResult, RoleHost } from "
|
|
|
10
11
|
|
|
11
12
|
import {
|
|
12
13
|
ENGINE_DETOUR_TOOL_NAME,
|
|
13
|
-
|
|
14
|
+
engineDetourFailureSeatText,
|
|
14
15
|
isEngineDetourFailure,
|
|
15
16
|
resolveEngineModel,
|
|
16
17
|
resolveEngineName,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
reportEngineDetourCall,
|
|
22
23
|
} from "./engine-detour-usage.ts";
|
|
23
24
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.ts";
|
|
25
|
+
import { serializeThrownValue } from "./serialize-thrown-value.ts";
|
|
24
26
|
|
|
25
27
|
// #836 r16 class 3: argv required/minItems/element-minLength stay — execute()
|
|
26
28
|
// must obtain the first item as the executable and spawn it (below; #82-98).
|
|
@@ -46,14 +48,6 @@ type EngineDetourContext = Pick<HostContext, "cwd" | "mode" | "abort"> & {
|
|
|
46
48
|
host?: string;
|
|
47
49
|
};
|
|
48
50
|
|
|
49
|
-
export type EngineDetourHostActions = {
|
|
50
|
-
failInfrastructure(
|
|
51
|
-
error: unknown,
|
|
52
|
-
ctx: EngineDetourContext,
|
|
53
|
-
toolCallId?: string,
|
|
54
|
-
): never;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
51
|
/** Caller/upper-layer cancellation must propagate unchanged. */
|
|
58
52
|
function isCallerCancellation(
|
|
59
53
|
error: unknown,
|
|
@@ -76,17 +70,60 @@ function asError(error: unknown, fallback: string): Error {
|
|
|
76
70
|
: new Error(String(error).trim() || fallback);
|
|
77
71
|
}
|
|
78
72
|
|
|
73
|
+
/** Structured details shared by success and engine-process failure results. */
|
|
74
|
+
type EngineDetourResultDetails = {
|
|
75
|
+
tool: typeof ENGINE_DETOUR_TOOL_NAME;
|
|
76
|
+
code?: number;
|
|
77
|
+
/** Full child stdout when the process closed (failure keeps labor output). */
|
|
78
|
+
stdout?: string;
|
|
79
|
+
stderr?: string;
|
|
80
|
+
/** Node errno on spawn failure (e.g. ENOENT). */
|
|
81
|
+
errorCode?: string;
|
|
82
|
+
/** Full ledger-write failure when dual-fail (serializeThrownValue; seat still lives). */
|
|
83
|
+
ledgerError?: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
function engineFailureResult(input: {
|
|
87
|
+
text: string;
|
|
88
|
+
code?: number;
|
|
89
|
+
stdout?: string;
|
|
90
|
+
stderr?: string;
|
|
91
|
+
errorCode?: string;
|
|
92
|
+
ledgerError?: string;
|
|
93
|
+
}): HostToolResult<EngineDetourResultDetails> {
|
|
94
|
+
const details: EngineDetourResultDetails = {
|
|
95
|
+
tool: ENGINE_DETOUR_TOOL_NAME,
|
|
96
|
+
...(input.code === undefined ? {} : { code: input.code }),
|
|
97
|
+
...(input.stdout === undefined ? {} : { stdout: input.stdout }),
|
|
98
|
+
...(input.stderr === undefined ? {} : { stderr: input.stderr }),
|
|
99
|
+
...(input.errorCode === undefined ? {} : { errorCode: input.errorCode }),
|
|
100
|
+
...(input.ledgerError === undefined ? {} : { ledgerError: input.ledgerError }),
|
|
101
|
+
};
|
|
102
|
+
// MCP / invokeAkTool deliver content only — dual-fail ledger cause must ride
|
|
103
|
+
// the seat-visible content channel, not details alone (#1213).
|
|
104
|
+
let text = input.text;
|
|
105
|
+
if (input.ledgerError !== undefined && input.ledgerError.length > 0) {
|
|
106
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
107
|
+
text += input.ledgerError;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
content: [{ type: "text" as const, text }],
|
|
111
|
+
details,
|
|
112
|
+
// Identified detour failure is a tool error, not a seat-run death (#1213).
|
|
113
|
+
isError: true as const,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
79
117
|
/**
|
|
80
118
|
* Build one detour tool definition for a configured engine name.
|
|
81
|
-
*
|
|
82
|
-
*
|
|
119
|
+
* Engine process failures (nonzero/empty/spawn) and empty/invalid argv return as
|
|
120
|
+
* ordinary tool results to the same seat — no seat-run abort (#1213 A3).
|
|
83
121
|
* Caller AbortSignal cancellation propagates unchanged.
|
|
84
122
|
*/
|
|
85
123
|
export function createEngineDetourToolDefinition(input: {
|
|
86
124
|
engineName: string;
|
|
87
125
|
/** Optional pool-directive model id (#883); description only — argv stays caller-assembled. */
|
|
88
126
|
engineModel?: string;
|
|
89
|
-
fail: (error: Error, toolCallId: string, ctx: EngineDetourContext) => never;
|
|
90
127
|
}): HostToolDefinition<typeof engineDetourArgsSchema, unknown, EngineDetourContext> {
|
|
91
128
|
const engineName = input.engineName;
|
|
92
129
|
const engineModel = input.engineModel;
|
|
@@ -110,13 +147,6 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
110
147
|
): Promise<HostToolResult> {
|
|
111
148
|
const args = params as EngineDetourArgs;
|
|
112
149
|
const argv = Array.isArray(args.argv) ? args.argv : [];
|
|
113
|
-
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
114
|
-
input.fail(
|
|
115
|
-
new Error("劳务引擎 argv 须为非空字符串数组"),
|
|
116
|
-
toolCallId,
|
|
117
|
-
ctx,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
150
|
|
|
121
151
|
const sessionParent = ctx.sessionManager?.getSessionFile?.();
|
|
122
152
|
const startedAt = Date.now();
|
|
@@ -155,31 +185,28 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
155
185
|
});
|
|
156
186
|
};
|
|
157
187
|
|
|
158
|
-
/**
|
|
159
|
-
const
|
|
160
|
-
engineCause: Error,
|
|
188
|
+
/** Record usage; on ledger failure keep the full thrown value (失败诚实, no abort). */
|
|
189
|
+
const recordCallOrLedgerError = (
|
|
161
190
|
observed: { code?: number; stdoutByteLength?: number },
|
|
162
|
-
|
|
163
|
-
): never => {
|
|
191
|
+
): string | undefined => {
|
|
164
192
|
try {
|
|
165
193
|
recordCall(observed);
|
|
194
|
+
return undefined;
|
|
166
195
|
} catch (recordError) {
|
|
167
|
-
|
|
168
|
-
new AggregateError(
|
|
169
|
-
[
|
|
170
|
-
engineCause,
|
|
171
|
-
asError(recordError, "engine detour usage ledger write failed"),
|
|
172
|
-
],
|
|
173
|
-
aggregateMessage,
|
|
174
|
-
{ cause: engineCause },
|
|
175
|
-
),
|
|
176
|
-
toolCallId,
|
|
177
|
-
ctx,
|
|
178
|
-
);
|
|
196
|
+
return serializeThrownValue(recordError);
|
|
179
197
|
}
|
|
180
|
-
input.fail(engineCause, toolCallId, ctx);
|
|
181
198
|
};
|
|
182
199
|
|
|
200
|
+
if (argv.length === 0 || argv.some((part) => typeof part !== "string" || part.length === 0)) {
|
|
201
|
+
// A3: parameter error returns to the seat — do not abort the run.
|
|
202
|
+
// Call actually entered execute: book it with no forged process metrics (#1213 / #537).
|
|
203
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
204
|
+
return engineFailureResult({
|
|
205
|
+
text: "劳务引擎 argv 须为非空字符串数组",
|
|
206
|
+
...(ledgerError === undefined ? {} : { ledgerError }),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
183
210
|
let result: Awaited<ReturnType<typeof runEngineDetourOnce>>;
|
|
184
211
|
try {
|
|
185
212
|
result = await runEngineDetourOnce({
|
|
@@ -190,24 +217,34 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
190
217
|
} catch (error) {
|
|
191
218
|
if (isCallerCancellation(error, signal)) throw error;
|
|
192
219
|
// Spawn path: duration only — code/stdout bytes absent (not forged 0).
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
220
|
+
// Return the real cause to the seat; do not abort the run (#1213).
|
|
221
|
+
const engineError = asError(error, "劳务引擎 spawn 失败");
|
|
222
|
+
const ledgerError = recordCallOrLedgerError({});
|
|
223
|
+
const errno =
|
|
224
|
+
typeof (engineError as NodeJS.ErrnoException).code === "string"
|
|
225
|
+
? (engineError as NodeJS.ErrnoException).code
|
|
226
|
+
: undefined;
|
|
227
|
+
return engineFailureResult({
|
|
228
|
+
text: engineError.message,
|
|
229
|
+
...(errno === undefined ? {} : { errorCode: errno }),
|
|
230
|
+
...(ledgerError === undefined ? {} : { ledgerError }),
|
|
231
|
+
});
|
|
198
232
|
}
|
|
199
233
|
|
|
200
234
|
const stdoutByteLength = engineDetourStdoutByteLength(result.stdout);
|
|
201
235
|
const observed = { code: result.code, stdoutByteLength };
|
|
202
236
|
|
|
203
237
|
// Classify closed-child failure before ledger write so a sitian failure
|
|
204
|
-
// cannot erase nonzero/empty engine facts.
|
|
238
|
+
// cannot erase nonzero/empty engine facts. Still a tool result (#1213).
|
|
205
239
|
if (isEngineDetourFailure(result)) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
240
|
+
const ledgerError = recordCallOrLedgerError(observed);
|
|
241
|
+
return engineFailureResult({
|
|
242
|
+
text: engineDetourFailureSeatText(result),
|
|
243
|
+
code: result.code,
|
|
244
|
+
stdout: result.stdout,
|
|
245
|
+
stderr: result.stderr,
|
|
246
|
+
...(ledgerError === undefined ? {} : { ledgerError }),
|
|
247
|
+
});
|
|
211
248
|
}
|
|
212
249
|
|
|
213
250
|
recordCall(observed);
|
|
@@ -230,10 +267,7 @@ export function createEngineDetourToolDefinition(input: {
|
|
|
230
267
|
* activation signal. Signal is request-scoped via RoleHost flag, with pi
|
|
231
268
|
* child-process env as fallback (resolveEngineName). Returns whether registration occurred.
|
|
232
269
|
*/
|
|
233
|
-
export function registerEngineDetourTool(
|
|
234
|
-
roleHost: RoleHost,
|
|
235
|
-
hostActions: EngineDetourHostActions,
|
|
236
|
-
): boolean {
|
|
270
|
+
export function registerEngineDetourTool(roleHost: RoleHost): boolean {
|
|
237
271
|
const getFlag = (name: string) => roleHost.getFlag(name);
|
|
238
272
|
const engineName = resolveEngineName(getFlag);
|
|
239
273
|
if (engineName === undefined) {
|
|
@@ -244,9 +278,6 @@ export function registerEngineDetourTool(
|
|
|
244
278
|
const definition = createEngineDetourToolDefinition({
|
|
245
279
|
engineName,
|
|
246
280
|
...(engineModel === undefined ? {} : { engineModel }),
|
|
247
|
-
fail(error, toolCallId, ctx) {
|
|
248
|
-
hostActions.failInfrastructure(error, ctx, toolCallId);
|
|
249
|
-
},
|
|
250
281
|
});
|
|
251
282
|
roleHost.registerTool(definition);
|
|
252
283
|
|
package/src/engine-detour.ts
CHANGED
|
@@ -154,27 +154,44 @@ export function isEngineDetourFailure(result: {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
157
|
+
* Seat-visible failure text for the same-session tool result (#1213).
|
|
158
|
+
* Preserve every received stream byte (including whitespace-only) — failure
|
|
159
|
+
* predicates use trim, but content conservation does not. Nonzero exit and
|
|
160
|
+
* empty-stdout reasons also ride this content channel (MCP delivers content,
|
|
161
|
+
* not details). Fully-empty streams → diagnostics only.
|
|
161
162
|
*/
|
|
162
|
-
export function
|
|
163
|
+
export function engineDetourFailureSeatText(result: {
|
|
163
164
|
stderr: string;
|
|
164
165
|
code: number;
|
|
165
166
|
stdout: string;
|
|
166
167
|
}): string {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
// Length, not trim: whitespace-only streams still reach the seat.
|
|
169
|
+
const parts: string[] = [];
|
|
170
|
+
if (result.stdout.length > 0) parts.push(result.stdout);
|
|
171
|
+
if (result.stderr.length > 0) parts.push(result.stderr);
|
|
172
|
+
let text = "";
|
|
173
|
+
if (parts.length > 0) {
|
|
174
|
+
text = parts[0]!;
|
|
175
|
+
for (let index = 1; index < parts.length; index += 1) {
|
|
176
|
+
if (!text.endsWith("\n")) text += "\n";
|
|
177
|
+
text += parts[index]!;
|
|
175
178
|
}
|
|
176
179
|
}
|
|
177
|
-
|
|
180
|
+
const append = (line: string): void => {
|
|
181
|
+
if (text.length > 0 && !text.endsWith("\n")) text += "\n";
|
|
182
|
+
text += line;
|
|
183
|
+
};
|
|
184
|
+
// Exit code must reach the seat-visible content channel on every nonzero
|
|
185
|
+
// failure — including when stderr is present (details-only is not enough).
|
|
186
|
+
if (result.code !== 0) {
|
|
187
|
+
append(`劳务引擎以 code ${result.code} 退出`);
|
|
188
|
+
}
|
|
189
|
+
// Empty-stdout failure reason (isEngineDetourFailure) is independent of
|
|
190
|
+
// whether stream bytes were preserved above.
|
|
191
|
+
if (result.stdout.trim() === "") {
|
|
192
|
+
append(ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC);
|
|
193
|
+
}
|
|
194
|
+
return text.length > 0 ? text : ENGINE_DETOUR_EMPTY_STDOUT_DIAGNOSTIC;
|
|
178
195
|
}
|
|
179
196
|
|
|
180
197
|
/** Non-empty trimmed engine name from process.env, else undefined. */
|
package/src/host-contracts.ts
CHANGED
|
@@ -9,6 +9,13 @@ type HostSessionEntry = { type: string; message?: HostMessage };
|
|
|
9
9
|
export type HostToolResult<T = unknown> = {
|
|
10
10
|
content: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }>;
|
|
11
11
|
details: T;
|
|
12
|
+
/**
|
|
13
|
+
* Native tool-failure flag (Pi AgentToolResult.isError). Resolved execute
|
|
14
|
+
* results that already identify failure must set this true — describing the
|
|
15
|
+
* failure only in content is not enough. Seat-run death stays a separate
|
|
16
|
+
* infrastructure path (details.cause / kind), not this bit.
|
|
17
|
+
*/
|
|
18
|
+
isError?: boolean;
|
|
12
19
|
terminate?: boolean;
|
|
13
20
|
};
|
|
14
21
|
|
package/src/role-envelope.ts
CHANGED
|
@@ -483,10 +483,12 @@ export async function prepareRoleEnvelope(options: {
|
|
|
483
483
|
}
|
|
484
484
|
try {
|
|
485
485
|
const result = await tool.execute(toolCallId, (args ?? {}) as never, undefined, undefined, context);
|
|
486
|
+
// Pass through native isError from the tool result (Pi AgentToolResult).
|
|
487
|
+
// Identified failures must not be projected as tool success (#1213).
|
|
486
488
|
const projected = await projectToolResult(toolCallId, name, {
|
|
487
489
|
content: result.content,
|
|
488
490
|
details: result.details,
|
|
489
|
-
isError:
|
|
491
|
+
isError: result.isError === true,
|
|
490
492
|
});
|
|
491
493
|
if (result.terminate === false) {
|
|
492
494
|
rejection = {
|
package/src/role-runtime.ts
CHANGED
|
@@ -1821,7 +1821,7 @@ export function createRoleRuntimeExtension(
|
|
|
1821
1821
|
// #357 T2 / #378 / #380 / #391 / #818: any role+engine activation registers the package detour tool once.
|
|
1822
1822
|
// Gate is resolveEngineName (RoleHost flag → env fallback) — no per-engine execute branch; no role-module spawn.
|
|
1823
1823
|
if (!engineDetourRegistered) {
|
|
1824
|
-
engineDetourRegistered = registerEngineDetourTool(roleHost
|
|
1824
|
+
engineDetourRegistered = registerEngineDetourTool(roleHost);
|
|
1825
1825
|
}
|
|
1826
1826
|
// Secretariat owns a declared active surface. The shared engine detour is
|
|
1827
1827
|
// registered after role activation, so include it here rather than leave
|