@agwab/pi-workflow 0.1.0 → 0.1.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/README.md +14 -3
- package/agents/researcher.md +17 -7
- package/dist/artifact-graph-runtime.js +1 -0
- package/dist/compiler.js +2 -2
- package/dist/dynamic-generated-task-runtime.js +4 -3
- package/dist/dynamic-runtime-bundle.js +3 -2
- package/dist/extension.js +40 -1
- package/dist/subagent-backend.js +82 -27
- package/dist/tool-metadata.d.ts +1 -0
- package/dist/tool-metadata.js +13 -1
- package/dist/workflow-artifact-extension.js +3 -2
- package/dist/workflow-artifact-tool.js +84 -4
- package/dist/workflow-web-source-extension.d.ts +43 -0
- package/dist/workflow-web-source-extension.js +1194 -0
- package/dist/workflow-web-source.d.ts +171 -0
- package/dist/workflow-web-source.js +897 -0
- package/docs/usage.md +32 -45
- package/node_modules/@agwab/pi-subagent/package.json +1 -1
- package/node_modules/@agwab/pi-subagent/src/api.ts +245 -132
- package/node_modules/@agwab/pi-subagent/src/artifacts/result.ts +243 -163
- package/node_modules/@agwab/pi-subagent/src/core/constants.ts +117 -90
- package/node_modules/@agwab/pi-subagent/src/core/validation.ts +728 -475
- package/node_modules/@agwab/pi-subagent/src/orchestrate/run.ts +305 -209
- package/node_modules/@agwab/pi-subagent/src/runners/headless-model.ts +750 -439
- package/node_modules/@agwab/pi-subagent/src/runners/tmux.ts +422 -268
- package/package.json +3 -4
- package/skills/workflow-guide/scaffolds/object-tool-fallback/schemas/fetch-control.schema.json +1 -1
- package/skills/workflow-guide/scaffolds/object-tool-fallback/spec.json +4 -3
- package/src/artifact-graph-runtime.ts +1 -0
- package/src/compiler.ts +2 -1
- package/src/dynamic-generated-task-runtime.ts +4 -2
- package/src/dynamic-runtime-bundle.ts +3 -2
- package/src/extension.ts +46 -1
- package/src/subagent-backend.ts +121 -37
- package/src/tool-metadata.ts +22 -1
- package/src/workflow-artifact-extension.ts +3 -2
- package/src/workflow-artifact-tool.ts +96 -4
- package/src/workflow-web-source-extension.ts +1411 -0
- package/src/workflow-web-source.ts +1171 -0
- package/workflows/README.md +1 -1
- package/workflows/deep-research/helpers/claim-evidence-gate.mjs +474 -40
- package/workflows/deep-research/helpers/final-audit-packet.mjs +219 -0
- package/workflows/deep-research/helpers/normalize-input-packet.mjs +436 -0
- package/workflows/deep-research/helpers/render-executive.mjs +571 -198
- package/workflows/deep-research/schemas/deep-research-executive-render-control.schema.json +35 -8
- package/workflows/deep-research/schemas/deep-research-normalize-claims-control.schema.json +45 -4
- package/workflows/deep-research/schemas/deep-research-verify-claims-control.schema.json +0 -2
- package/workflows/deep-research/spec.json +36 -21
- package/workflows/deep-review/helpers/render-review-report.mjs +502 -0
- package/workflows/deep-review/schemas/deep-review-render-control.schema.json +50 -0
- package/workflows/deep-review/spec.json +22 -1
- package/docs/release.md +0 -89
- package/node_modules/@pondwader/socks5-server/.DS_Store +0 -0
- package/node_modules/commander/.DS_Store +0 -0
- package/node_modules/jiti/.DS_Store +0 -0
- package/node_modules/node-forge/.DS_Store +0 -0
- package/node_modules/shell-quote/.DS_Store +0 -0
- package/node_modules/zod/.DS_Store +0 -0
|
@@ -1,520 +1,773 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
2
|
+
AGENT_SCOPES,
|
|
3
|
+
ASYNC_DEPENDENCIES,
|
|
4
|
+
BACKENDS,
|
|
5
|
+
EXECUTION_MODES,
|
|
6
|
+
ON_COMPLETE_ACTIONS,
|
|
7
|
+
THINKING_LEVELS,
|
|
8
|
+
WORKSPACE_MODES,
|
|
9
|
+
WORKTREE_POLICIES,
|
|
10
|
+
isAgentScope,
|
|
11
|
+
isAsyncDependency,
|
|
12
|
+
isBackend,
|
|
13
|
+
isExecutionMode,
|
|
14
|
+
isOnCompleteAction,
|
|
15
|
+
isThinkingLevel,
|
|
16
|
+
isWorktreePolicy,
|
|
17
|
+
isWorkspaceMode,
|
|
18
|
+
type Backend,
|
|
19
|
+
type ResolveInput,
|
|
20
|
+
type ResolveValidationFailure,
|
|
21
|
+
type ResolvedBackend,
|
|
22
|
+
type SandboxInput,
|
|
23
|
+
type SandboxOptionsInput,
|
|
24
|
+
type SubagentTaskInput,
|
|
25
|
+
type WorkspaceInput,
|
|
26
26
|
} from "./constants.ts";
|
|
27
27
|
|
|
28
28
|
export type ResolveValidationResult =
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
| { ok: true; input: ResolveInput }
|
|
30
|
+
| { ok: false; failure: ResolveValidationFailure };
|
|
31
31
|
|
|
32
32
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
33
|
-
|
|
33
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
function failure(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
function failure(
|
|
37
|
+
error: string,
|
|
38
|
+
backend?: ResolvedBackend,
|
|
39
|
+
): ResolveValidationResult {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
failure: {
|
|
43
|
+
...(backend ? { backend } : {}),
|
|
44
|
+
status: "failed",
|
|
45
|
+
failureKind: "validation",
|
|
46
|
+
error,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
function failureBackend(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
function failureBackend(
|
|
52
|
+
backend: Backend | undefined,
|
|
53
|
+
): ResolvedBackend | undefined {
|
|
54
|
+
const requested = backend ?? "auto";
|
|
55
|
+
return requested === "auto" ? undefined : requested;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
function formatValue(value: unknown): string {
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
if (typeof value === "string") return `"${value}"`;
|
|
60
|
+
return String(value);
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
function formatOptions(values: readonly string[]): string {
|
|
59
|
-
|
|
64
|
+
return values.map((value) => `"${value}"`).join(", ");
|
|
60
65
|
}
|
|
61
66
|
|
|
62
|
-
function validateString(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
function validateString(
|
|
68
|
+
value: unknown,
|
|
69
|
+
fieldName: string,
|
|
70
|
+
backend: ResolvedBackend | undefined,
|
|
71
|
+
): string | ResolveValidationResult {
|
|
72
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
73
|
+
return failure(
|
|
74
|
+
`${fieldName} must be a non-empty string when provided.`,
|
|
75
|
+
backend,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
67
79
|
}
|
|
68
80
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
const SESSION_ID_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
82
|
+
|
|
83
|
+
function validateSessionId(
|
|
84
|
+
value: unknown,
|
|
85
|
+
fieldName: string,
|
|
86
|
+
backend: ResolvedBackend | undefined,
|
|
87
|
+
): string | ResolveValidationResult {
|
|
88
|
+
const sessionId = validateString(value, fieldName, backend);
|
|
89
|
+
if (typeof sessionId !== "string") return sessionId;
|
|
90
|
+
if (!SESSION_ID_PATTERN.test(sessionId)) {
|
|
91
|
+
return failure(
|
|
92
|
+
`${fieldName} must contain only letters, numbers, dots, underscores, or dashes.`,
|
|
93
|
+
backend,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return sessionId;
|
|
74
97
|
}
|
|
75
98
|
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
function validateBoolean(
|
|
100
|
+
value: unknown,
|
|
101
|
+
fieldName: string,
|
|
102
|
+
backend: ResolvedBackend | undefined,
|
|
103
|
+
): boolean | ResolveValidationResult {
|
|
104
|
+
if (typeof value !== "boolean") {
|
|
105
|
+
return failure(`${fieldName} must be a boolean when provided.`, backend);
|
|
106
|
+
}
|
|
107
|
+
return value;
|
|
81
108
|
}
|
|
82
109
|
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
110
|
+
function validateTimeoutMs(
|
|
111
|
+
value: unknown,
|
|
112
|
+
backend: ResolvedBackend | undefined,
|
|
113
|
+
): number | ResolveValidationResult {
|
|
114
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
115
|
+
return failure(
|
|
116
|
+
"timeoutMs must be a positive finite number when provided.",
|
|
117
|
+
backend,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return value;
|
|
88
121
|
}
|
|
89
122
|
|
|
90
|
-
function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const first = entries[0]![1];
|
|
105
|
-
if (!isThinkingLevel(first)) return undefined;
|
|
106
|
-
if (entries.some((entry) => entry[1] !== first)) {
|
|
107
|
-
return failure(`${fieldName} thinking aliases must agree when more than one is provided.`, backend);
|
|
108
|
-
}
|
|
109
|
-
return first;
|
|
123
|
+
function validateConcurrency(
|
|
124
|
+
value: unknown,
|
|
125
|
+
backend: ResolvedBackend | undefined,
|
|
126
|
+
): number | ResolveValidationResult {
|
|
127
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
128
|
+
return failure(
|
|
129
|
+
"concurrency must be a positive integer when provided.",
|
|
130
|
+
backend,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
110
134
|
}
|
|
111
135
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
136
|
+
function validateThinkingAliases(
|
|
137
|
+
value: Record<string, unknown>,
|
|
138
|
+
fieldName: string,
|
|
139
|
+
backend: ResolvedBackend | undefined,
|
|
140
|
+
): ResolveInput["thinking"] | ResolveValidationResult {
|
|
141
|
+
const entries = [
|
|
142
|
+
["thinking", value.thinking],
|
|
143
|
+
["thinkingLevel", value.thinkingLevel],
|
|
144
|
+
["reasoningLevel", value.reasoningLevel],
|
|
145
|
+
].filter((entry): entry is [string, unknown] => entry[1] !== undefined);
|
|
146
|
+
if (entries.length === 0) return undefined;
|
|
147
|
+
|
|
148
|
+
for (const [key, raw] of entries) {
|
|
149
|
+
if (!isThinkingLevel(raw)) {
|
|
150
|
+
return failure(
|
|
151
|
+
`unsupported ${fieldName}.${key} ${formatValue(raw)}; supported thinking levels are ${formatOptions(THINKING_LEVELS)}.`,
|
|
152
|
+
backend,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const first = entries[0]![1];
|
|
158
|
+
if (!isThinkingLevel(first)) return undefined;
|
|
159
|
+
if (entries.some((entry) => entry[1] !== first)) {
|
|
160
|
+
return failure(
|
|
161
|
+
`${fieldName} thinking aliases must agree when more than one is provided.`,
|
|
162
|
+
backend,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return first;
|
|
125
166
|
}
|
|
126
167
|
|
|
127
|
-
function
|
|
128
|
-
|
|
168
|
+
function validateStringArray(
|
|
169
|
+
value: unknown,
|
|
170
|
+
fieldName: string,
|
|
171
|
+
backend: ResolvedBackend | undefined,
|
|
172
|
+
): string[] | ResolveValidationResult {
|
|
173
|
+
if (!Array.isArray(value)) {
|
|
174
|
+
return failure(
|
|
175
|
+
`${fieldName} must be an array of non-empty strings when provided.`,
|
|
176
|
+
backend,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const items: string[] = [];
|
|
181
|
+
for (const [index, entry] of value.entries()) {
|
|
182
|
+
if (typeof entry !== "string" || entry.length === 0) {
|
|
183
|
+
return failure(
|
|
184
|
+
`${fieldName}[${index}] must be a non-empty string.`,
|
|
185
|
+
backend,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
items.push(entry);
|
|
189
|
+
}
|
|
190
|
+
return Array.from(new Set(items));
|
|
129
191
|
}
|
|
130
192
|
|
|
131
|
-
|
|
193
|
+
function validateTools(
|
|
194
|
+
value: unknown,
|
|
195
|
+
fieldName: string,
|
|
196
|
+
backend: ResolvedBackend | undefined,
|
|
197
|
+
): string[] | ResolveValidationResult {
|
|
198
|
+
return validateStringArray(value, fieldName, backend);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const DOMAIN_PATTERN =
|
|
202
|
+
/^(\*\.)?[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$/;
|
|
132
203
|
|
|
133
204
|
function isAllowedDomainPattern(value: string): boolean {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
205
|
+
if (value === "localhost") return true;
|
|
206
|
+
if (!DOMAIN_PATTERN.test(value)) return false;
|
|
207
|
+
// Reject overly broad wildcards such as "*.com"; require *.example.com shape.
|
|
208
|
+
if (value.startsWith("*.")) return value.slice(2).includes(".");
|
|
209
|
+
return true;
|
|
139
210
|
}
|
|
140
211
|
|
|
141
|
-
function validateSandbox(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
212
|
+
function validateSandbox(
|
|
213
|
+
value: unknown,
|
|
214
|
+
fieldName: string,
|
|
215
|
+
backend: ResolvedBackend | undefined,
|
|
216
|
+
): SandboxInput | null | ResolveValidationResult {
|
|
217
|
+
if (value === null || value === false) return null;
|
|
218
|
+
if (value === true) return true;
|
|
219
|
+
if (isRecord(value)) {
|
|
220
|
+
const sandbox: SandboxOptionsInput = {};
|
|
221
|
+
const unknownKeys = Object.keys(value).filter(
|
|
222
|
+
(key) => key !== "allowedDomains",
|
|
223
|
+
);
|
|
224
|
+
if (unknownKeys.length > 0) {
|
|
225
|
+
return failure(
|
|
226
|
+
`unsupported ${fieldName} option(s): ${unknownKeys.map((key) => `"${key}"`).join(", ")}; supported options are "allowedDomains".`,
|
|
227
|
+
backend,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
if (value.allowedDomains !== undefined) {
|
|
231
|
+
const allowedDomains = validateStringArray(
|
|
232
|
+
value.allowedDomains,
|
|
233
|
+
`${fieldName}.allowedDomains`,
|
|
234
|
+
backend,
|
|
235
|
+
);
|
|
236
|
+
if (!Array.isArray(allowedDomains)) return allowedDomains;
|
|
237
|
+
for (const domain of allowedDomains) {
|
|
238
|
+
if (!isAllowedDomainPattern(domain)) {
|
|
239
|
+
return failure(
|
|
240
|
+
`${fieldName}.allowedDomains entry ${formatValue(domain)} must be a bare domain or *.example.com-style wildcard without protocol, path, or port.`,
|
|
241
|
+
backend,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
sandbox.allowedDomains = allowedDomains;
|
|
246
|
+
}
|
|
247
|
+
return sandbox;
|
|
248
|
+
}
|
|
249
|
+
return failure(
|
|
250
|
+
`${fieldName} must be a boolean or an options object when provided. Use true for an offline sandbox, { allowedDomains: [...] } to allow network egress, or false/null to disable sandboxing.`,
|
|
251
|
+
backend,
|
|
252
|
+
);
|
|
163
253
|
}
|
|
164
254
|
|
|
165
|
-
function validateTaskItem(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
255
|
+
function validateTaskItem(
|
|
256
|
+
value: unknown,
|
|
257
|
+
fieldName: string,
|
|
258
|
+
backend: ResolvedBackend | undefined,
|
|
259
|
+
): SubagentTaskInput | ResolveValidationResult {
|
|
260
|
+
if (!isRecord(value)) {
|
|
261
|
+
return failure(`${fieldName} must be an object.`, backend);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const task: SubagentTaskInput = {};
|
|
265
|
+
|
|
266
|
+
if (value.agent !== undefined) {
|
|
267
|
+
const agent = validateString(value.agent, `${fieldName}.agent`, backend);
|
|
268
|
+
if (typeof agent !== "string") return agent;
|
|
269
|
+
task.agent = agent;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (value.task !== undefined) {
|
|
273
|
+
const taskText = validateString(value.task, `${fieldName}.task`, backend);
|
|
274
|
+
if (typeof taskText !== "string") return taskText;
|
|
275
|
+
task.task = taskText;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (value.roleContext !== undefined) {
|
|
279
|
+
const roleContext = validateString(
|
|
280
|
+
value.roleContext,
|
|
281
|
+
`${fieldName}.roleContext`,
|
|
282
|
+
backend,
|
|
283
|
+
);
|
|
284
|
+
if (typeof roleContext !== "string") return roleContext;
|
|
285
|
+
task.roleContext = roleContext;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (value.agentScope !== undefined) {
|
|
289
|
+
if (!isAgentScope(value.agentScope)) {
|
|
290
|
+
return failure(
|
|
291
|
+
`unsupported ${fieldName}.agentScope ${formatValue(value.agentScope)}; supported agent scopes are ${formatOptions(AGENT_SCOPES)}.`,
|
|
292
|
+
backend,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
task.agentScope = value.agentScope;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (value.confirmProjectAgents !== undefined) {
|
|
299
|
+
const confirm = validateBoolean(
|
|
300
|
+
value.confirmProjectAgents,
|
|
301
|
+
`${fieldName}.confirmProjectAgents`,
|
|
302
|
+
backend,
|
|
303
|
+
);
|
|
304
|
+
if (typeof confirm !== "boolean") return confirm;
|
|
305
|
+
task.confirmProjectAgents = confirm;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (value.sandbox !== undefined) {
|
|
309
|
+
const sandbox = validateSandbox(
|
|
310
|
+
value.sandbox,
|
|
311
|
+
`${fieldName}.sandbox`,
|
|
312
|
+
backend,
|
|
313
|
+
);
|
|
314
|
+
if (sandbox !== null && sandbox !== true && "ok" in sandbox) return sandbox;
|
|
315
|
+
task.sandbox = sandbox;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (value.visible !== undefined) {
|
|
319
|
+
const visible = validateBoolean(
|
|
320
|
+
value.visible,
|
|
321
|
+
`${fieldName}.visible`,
|
|
322
|
+
backend,
|
|
323
|
+
);
|
|
324
|
+
if (typeof visible !== "boolean") return visible;
|
|
325
|
+
task.visible = visible;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (value.cwd !== undefined) {
|
|
329
|
+
const cwd = validateString(value.cwd, `${fieldName}.cwd`, backend);
|
|
330
|
+
if (typeof cwd !== "string") return cwd;
|
|
331
|
+
task.cwd = cwd;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (value.timeoutMs !== undefined) {
|
|
335
|
+
const timeoutMs = validateTimeoutMs(value.timeoutMs, backend);
|
|
336
|
+
if (typeof timeoutMs !== "number") return timeoutMs;
|
|
337
|
+
task.timeoutMs = timeoutMs;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (value.model !== undefined) {
|
|
341
|
+
const model = validateString(value.model, `${fieldName}.model`, backend);
|
|
342
|
+
if (typeof model !== "string") return model;
|
|
343
|
+
task.model = model;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (value.sessionId !== undefined) {
|
|
347
|
+
const sessionId = validateSessionId(
|
|
348
|
+
value.sessionId,
|
|
349
|
+
`${fieldName}.sessionId`,
|
|
350
|
+
backend,
|
|
351
|
+
);
|
|
352
|
+
if (typeof sessionId !== "string") return sessionId;
|
|
353
|
+
task.sessionId = sessionId;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (value.tools !== undefined) {
|
|
357
|
+
const tools = validateTools(value.tools, `${fieldName}.tools`, backend);
|
|
358
|
+
if (!Array.isArray(tools)) return tools;
|
|
359
|
+
task.tools = tools;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (value.systemPrompt !== undefined) {
|
|
363
|
+
const systemPrompt = validateString(
|
|
364
|
+
value.systemPrompt,
|
|
365
|
+
`${fieldName}.systemPrompt`,
|
|
366
|
+
backend,
|
|
367
|
+
);
|
|
368
|
+
if (typeof systemPrompt !== "string") return systemPrompt;
|
|
369
|
+
task.systemPrompt = systemPrompt;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (value.skills !== undefined) {
|
|
373
|
+
const skills = validateStringArray(
|
|
374
|
+
value.skills,
|
|
375
|
+
`${fieldName}.skills`,
|
|
376
|
+
backend,
|
|
377
|
+
);
|
|
378
|
+
if (!Array.isArray(skills)) return skills;
|
|
379
|
+
task.skills = skills;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (value.extensions !== undefined) {
|
|
383
|
+
const extensions = validateStringArray(
|
|
384
|
+
value.extensions,
|
|
385
|
+
`${fieldName}.extensions`,
|
|
386
|
+
backend,
|
|
387
|
+
);
|
|
388
|
+
if (!Array.isArray(extensions)) return extensions;
|
|
389
|
+
task.extensions = extensions;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (value.captureToolCalls !== undefined) {
|
|
393
|
+
const captureToolCalls = validateBoolean(
|
|
394
|
+
value.captureToolCalls,
|
|
395
|
+
`${fieldName}.captureToolCalls`,
|
|
396
|
+
backend,
|
|
397
|
+
);
|
|
398
|
+
if (typeof captureToolCalls !== "boolean") return captureToolCalls;
|
|
399
|
+
task.captureToolCalls = captureToolCalls;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const thinking = validateThinkingAliases(value, fieldName, backend);
|
|
403
|
+
if (thinking && typeof thinking !== "string") return thinking;
|
|
404
|
+
if (thinking !== undefined) task.thinking = thinking;
|
|
405
|
+
|
|
406
|
+
return task;
|
|
269
407
|
}
|
|
270
408
|
|
|
271
|
-
function validateTaskList(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
409
|
+
function validateTaskList(
|
|
410
|
+
value: unknown,
|
|
411
|
+
fieldName: string,
|
|
412
|
+
backend: ResolvedBackend | undefined,
|
|
413
|
+
): SubagentTaskInput[] | ResolveValidationResult {
|
|
414
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
415
|
+
return failure(
|
|
416
|
+
`${fieldName} must be a non-empty array of task objects when provided.`,
|
|
417
|
+
backend,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const tasks: SubagentTaskInput[] = [];
|
|
422
|
+
for (const [index, entry] of value.entries()) {
|
|
423
|
+
const task = validateTaskItem(entry, `${fieldName}[${index}]`, backend);
|
|
424
|
+
if ("ok" in task) return task;
|
|
425
|
+
tasks.push(task);
|
|
426
|
+
}
|
|
427
|
+
return tasks;
|
|
283
428
|
}
|
|
284
429
|
|
|
285
|
-
function validateWorkspace(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
430
|
+
function validateWorkspace(
|
|
431
|
+
value: unknown,
|
|
432
|
+
backend: ResolvedBackend | undefined,
|
|
433
|
+
): WorkspaceInput | ResolveInput["workspace"] | ResolveValidationResult {
|
|
434
|
+
if (isWorkspaceMode(value)) return value;
|
|
435
|
+
if (!isRecord(value)) {
|
|
436
|
+
return failure(
|
|
437
|
+
`workspace must be one of ${formatOptions(WORKSPACE_MODES)} or an object when provided.`,
|
|
438
|
+
backend,
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const workspace: WorkspaceInput = {};
|
|
443
|
+
if (value.mode !== undefined) {
|
|
444
|
+
if (!isWorkspaceMode(value.mode)) {
|
|
445
|
+
return failure(
|
|
446
|
+
`unsupported workspace.mode ${formatValue(value.mode)}; supported workspace modes are ${formatOptions(WORKSPACE_MODES)}.`,
|
|
447
|
+
backend,
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
workspace.mode = value.mode;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (value.path !== undefined) {
|
|
454
|
+
const workspacePath = validateString(value.path, "workspace.path", backend);
|
|
455
|
+
if (typeof workspacePath !== "string") return workspacePath;
|
|
456
|
+
workspace.path = workspacePath;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return workspace;
|
|
306
460
|
}
|
|
307
461
|
|
|
308
|
-
export function validateResolveInput(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
462
|
+
export function validateResolveInput(
|
|
463
|
+
raw: unknown = {},
|
|
464
|
+
): ResolveValidationResult {
|
|
465
|
+
if (raw === undefined) raw = {};
|
|
466
|
+
|
|
467
|
+
if (!isRecord(raw)) {
|
|
468
|
+
return failure("subagent input must be an object.");
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const input: ResolveInput = {};
|
|
472
|
+
let backend: Backend | undefined;
|
|
473
|
+
|
|
474
|
+
if (raw.backend !== undefined) {
|
|
475
|
+
if (!isBackend(raw.backend)) {
|
|
476
|
+
return failure(
|
|
477
|
+
`unsupported backend ${formatValue(raw.backend)}; supported backends are ${BACKENDS.map(
|
|
478
|
+
(value) => `"${value}"`,
|
|
479
|
+
).join(", ")}.`,
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
backend = raw.backend;
|
|
483
|
+
input.backend = backend;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const backendForKnownFailure = failureBackend(backend);
|
|
487
|
+
|
|
488
|
+
if (raw.visible !== undefined) {
|
|
489
|
+
if (typeof raw.visible !== "boolean") {
|
|
490
|
+
return failure(
|
|
491
|
+
"visible must be a boolean when provided.",
|
|
492
|
+
backendForKnownFailure,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
input.visible = raw.visible;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (raw.sandbox !== undefined) {
|
|
499
|
+
const sandbox = validateSandbox(
|
|
500
|
+
raw.sandbox,
|
|
501
|
+
"sandbox",
|
|
502
|
+
backendForKnownFailure,
|
|
503
|
+
);
|
|
504
|
+
if (sandbox !== null && sandbox !== true && "ok" in sandbox) return sandbox;
|
|
505
|
+
input.sandbox = sandbox;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (raw.agent !== undefined) {
|
|
509
|
+
const agent = validateString(raw.agent, "agent", backendForKnownFailure);
|
|
510
|
+
if (typeof agent !== "string") return agent;
|
|
511
|
+
input.agent = agent;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (raw.task !== undefined) {
|
|
515
|
+
const task = validateString(raw.task, "task", backendForKnownFailure);
|
|
516
|
+
if (typeof task !== "string") return task;
|
|
517
|
+
input.task = task;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (raw.roleContext !== undefined) {
|
|
521
|
+
const roleContext = validateString(
|
|
522
|
+
raw.roleContext,
|
|
523
|
+
"roleContext",
|
|
524
|
+
backendForKnownFailure,
|
|
525
|
+
);
|
|
526
|
+
if (typeof roleContext !== "string") return roleContext;
|
|
527
|
+
input.roleContext = roleContext;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if (raw.agentScope !== undefined) {
|
|
531
|
+
if (!isAgentScope(raw.agentScope)) {
|
|
532
|
+
return failure(
|
|
533
|
+
`unsupported agentScope ${formatValue(raw.agentScope)}; supported agent scopes are ${formatOptions(AGENT_SCOPES)}.`,
|
|
534
|
+
backendForKnownFailure,
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
input.agentScope = raw.agentScope;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (raw.confirmProjectAgents !== undefined) {
|
|
541
|
+
const confirmProjectAgents = validateBoolean(
|
|
542
|
+
raw.confirmProjectAgents,
|
|
543
|
+
"confirmProjectAgents",
|
|
544
|
+
backendForKnownFailure,
|
|
545
|
+
);
|
|
546
|
+
if (typeof confirmProjectAgents !== "boolean") return confirmProjectAgents;
|
|
547
|
+
input.confirmProjectAgents = confirmProjectAgents;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (raw.mode !== undefined) {
|
|
551
|
+
if (!isExecutionMode(raw.mode)) {
|
|
552
|
+
return failure(
|
|
553
|
+
`unsupported mode ${formatValue(raw.mode)}; supported modes are ${formatOptions(EXECUTION_MODES)}.`,
|
|
554
|
+
backendForKnownFailure,
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
input.mode = raw.mode;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (raw.tasks !== undefined) {
|
|
561
|
+
const tasks = validateTaskList(raw.tasks, "tasks", backendForKnownFailure);
|
|
562
|
+
if ("ok" in tasks) return tasks;
|
|
563
|
+
input.tasks = tasks;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (raw.concurrency !== undefined) {
|
|
567
|
+
const concurrency = validateConcurrency(
|
|
568
|
+
raw.concurrency,
|
|
569
|
+
backendForKnownFailure,
|
|
570
|
+
);
|
|
571
|
+
if (typeof concurrency !== "number") return concurrency;
|
|
572
|
+
input.concurrency = concurrency;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (raw.chain !== undefined) {
|
|
576
|
+
return failure(
|
|
577
|
+
'chain mode is not supported by pi-subagent; use mode:"parallel" for fanout or have the parent orchestrate sequencing.',
|
|
578
|
+
backendForKnownFailure,
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (raw.workspace !== undefined) {
|
|
583
|
+
const workspace = validateWorkspace(raw.workspace, backendForKnownFailure);
|
|
584
|
+
if (
|
|
585
|
+
typeof workspace === "object" &&
|
|
586
|
+
workspace !== null &&
|
|
587
|
+
"ok" in workspace
|
|
588
|
+
)
|
|
589
|
+
return workspace;
|
|
590
|
+
input.workspace = workspace;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (raw.worktree !== undefined) {
|
|
594
|
+
if (
|
|
595
|
+
typeof raw.worktree !== "boolean" &&
|
|
596
|
+
(typeof raw.worktree !== "string" || raw.worktree.length === 0)
|
|
597
|
+
) {
|
|
598
|
+
return failure(
|
|
599
|
+
"worktree must be a boolean or non-empty string path when provided.",
|
|
600
|
+
backendForKnownFailure,
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
input.worktree = raw.worktree;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (raw.worktreePolicy !== undefined) {
|
|
607
|
+
if (!isWorktreePolicy(raw.worktreePolicy)) {
|
|
608
|
+
return failure(
|
|
609
|
+
`unsupported worktreePolicy ${formatValue(raw.worktreePolicy)}; supported worktree policies are ${formatOptions(WORKTREE_POLICIES)}.`,
|
|
610
|
+
backendForKnownFailure,
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
input.worktreePolicy = raw.worktreePolicy;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (raw.cwd !== undefined) {
|
|
617
|
+
const cwd = validateString(raw.cwd, "cwd", backendForKnownFailure);
|
|
618
|
+
if (typeof cwd !== "string") return cwd;
|
|
619
|
+
input.cwd = cwd;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (raw.runsDir !== undefined) {
|
|
623
|
+
const runsDir = validateString(
|
|
624
|
+
raw.runsDir,
|
|
625
|
+
"runsDir",
|
|
626
|
+
backendForKnownFailure,
|
|
627
|
+
);
|
|
628
|
+
if (typeof runsDir !== "string") return runsDir;
|
|
629
|
+
input.runsDir = runsDir;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (raw.correlationId !== undefined) {
|
|
633
|
+
const correlationId = validateString(
|
|
634
|
+
raw.correlationId,
|
|
635
|
+
"correlationId",
|
|
636
|
+
backendForKnownFailure,
|
|
637
|
+
);
|
|
638
|
+
if (typeof correlationId !== "string") return correlationId;
|
|
639
|
+
input.correlationId = correlationId;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (raw.sessionId !== undefined) {
|
|
643
|
+
if (raw.tasks !== undefined || raw.mode === "parallel") {
|
|
644
|
+
return failure(
|
|
645
|
+
"top-level sessionId is not supported with parallel tasks; set tasks[i].sessionId instead.",
|
|
646
|
+
backendForKnownFailure,
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const sessionId = validateSessionId(
|
|
651
|
+
raw.sessionId,
|
|
652
|
+
"sessionId",
|
|
653
|
+
backendForKnownFailure,
|
|
654
|
+
);
|
|
655
|
+
if (typeof sessionId !== "string") return sessionId;
|
|
656
|
+
input.sessionId = sessionId;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (raw.async !== undefined) {
|
|
660
|
+
const asyncValue = validateBoolean(
|
|
661
|
+
raw.async,
|
|
662
|
+
"async",
|
|
663
|
+
backendForKnownFailure,
|
|
664
|
+
);
|
|
665
|
+
if (typeof asyncValue !== "boolean") return asyncValue;
|
|
666
|
+
input.async = asyncValue;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (raw.onComplete !== undefined) {
|
|
670
|
+
if (!isOnCompleteAction(raw.onComplete)) {
|
|
671
|
+
return failure(
|
|
672
|
+
`unsupported onComplete ${formatValue(raw.onComplete)}; supported onComplete actions are ${formatOptions(ON_COMPLETE_ACTIONS)}.`,
|
|
673
|
+
backendForKnownFailure,
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
input.onComplete = raw.onComplete;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (raw.asyncDependency !== undefined) {
|
|
680
|
+
if (!isAsyncDependency(raw.asyncDependency)) {
|
|
681
|
+
return failure(
|
|
682
|
+
`unsupported asyncDependency ${formatValue(raw.asyncDependency)}; supported async dependencies are ${formatOptions(ASYNC_DEPENDENCIES)}.`,
|
|
683
|
+
backendForKnownFailure,
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
input.asyncDependency = raw.asyncDependency;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (raw.timeoutMs !== undefined) {
|
|
690
|
+
const timeoutMs = validateTimeoutMs(raw.timeoutMs, backendForKnownFailure);
|
|
691
|
+
if (typeof timeoutMs !== "number") return timeoutMs;
|
|
692
|
+
input.timeoutMs = timeoutMs;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (raw.model !== undefined) {
|
|
696
|
+
const model = validateString(raw.model, "model", backendForKnownFailure);
|
|
697
|
+
if (typeof model !== "string") return model;
|
|
698
|
+
input.model = model;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (raw.tools !== undefined) {
|
|
702
|
+
const tools = validateTools(raw.tools, "tools", backendForKnownFailure);
|
|
703
|
+
if (!Array.isArray(tools)) return tools;
|
|
704
|
+
input.tools = tools;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (raw.systemPrompt !== undefined) {
|
|
708
|
+
const systemPrompt = validateString(
|
|
709
|
+
raw.systemPrompt,
|
|
710
|
+
"systemPrompt",
|
|
711
|
+
backendForKnownFailure,
|
|
712
|
+
);
|
|
713
|
+
if (typeof systemPrompt !== "string") return systemPrompt;
|
|
714
|
+
input.systemPrompt = systemPrompt;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (raw.skills !== undefined) {
|
|
718
|
+
const skills = validateStringArray(
|
|
719
|
+
raw.skills,
|
|
720
|
+
"skills",
|
|
721
|
+
backendForKnownFailure,
|
|
722
|
+
);
|
|
723
|
+
if (!Array.isArray(skills)) return skills;
|
|
724
|
+
input.skills = skills;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if (raw.extensions !== undefined) {
|
|
728
|
+
const extensions = validateStringArray(
|
|
729
|
+
raw.extensions,
|
|
730
|
+
"extensions",
|
|
731
|
+
backendForKnownFailure,
|
|
732
|
+
);
|
|
733
|
+
if (!Array.isArray(extensions)) return extensions;
|
|
734
|
+
input.extensions = extensions;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (raw.captureToolCalls !== undefined) {
|
|
738
|
+
const captureToolCalls = validateBoolean(
|
|
739
|
+
raw.captureToolCalls,
|
|
740
|
+
"captureToolCalls",
|
|
741
|
+
backendForKnownFailure,
|
|
742
|
+
);
|
|
743
|
+
if (typeof captureToolCalls !== "boolean") return captureToolCalls;
|
|
744
|
+
input.captureToolCalls = captureToolCalls;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const thinking = validateThinkingAliases(
|
|
748
|
+
raw,
|
|
749
|
+
"input",
|
|
750
|
+
backendForKnownFailure,
|
|
751
|
+
);
|
|
752
|
+
if (thinking && typeof thinking !== "string") return thinking;
|
|
753
|
+
if (thinking !== undefined) input.thinking = thinking;
|
|
754
|
+
|
|
755
|
+
const requested = backend ?? "auto";
|
|
756
|
+
const sandboxed = input.sandbox !== undefined && input.sandbox !== null;
|
|
757
|
+
|
|
758
|
+
if (input.visible === true && requested !== "auto" && requested !== "tmux") {
|
|
759
|
+
return failure(
|
|
760
|
+
'visible execution requires backend "tmux" or "auto"; explicit non-tmux backends cannot run visibly.',
|
|
761
|
+
failureBackend(backend),
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (requested === "inline" && sandboxed) {
|
|
766
|
+
return failure(
|
|
767
|
+
"inline backend cannot provide a per-subagent OS sandbox; choose headless, tmux, or auto.",
|
|
768
|
+
"inline",
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
return { ok: true, input };
|
|
520
773
|
}
|