@runtypelabs/sdk 4.10.0 → 4.12.0
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/index.cjs +935 -119
- package/dist/index.d.cts +1089 -70
- package/dist/index.d.ts +1089 -70
- package/dist/index.mjs +911 -118
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,8 @@ __export(index_exports, {
|
|
|
38
38
|
ClientTokensEndpoint: () => ClientTokensEndpoint,
|
|
39
39
|
ContextTemplatesEndpoint: () => ContextTemplatesEndpoint,
|
|
40
40
|
ConversationsEndpoint: () => ConversationsEndpoint,
|
|
41
|
+
DEFAULT_RECOVERY_AFTER_EMPTY_SESSIONS: () => DEFAULT_RECOVERY_AFTER_EMPTY_SESSIONS,
|
|
42
|
+
DEFAULT_STALL_STOP_AFTER: () => DEFAULT_STALL_STOP_AFTER,
|
|
41
43
|
DispatchEndpoint: () => DispatchEndpoint,
|
|
42
44
|
EvalBuilder: () => EvalBuilder,
|
|
43
45
|
EvalEndpoint: () => EvalEndpoint,
|
|
@@ -71,38 +73,59 @@ __export(index_exports, {
|
|
|
71
73
|
SkillProposalsNamespace: () => SkillProposalsNamespace,
|
|
72
74
|
SkillsNamespace: () => SkillsNamespace,
|
|
73
75
|
SurfacesEndpoint: () => SurfacesEndpoint,
|
|
76
|
+
ToolDriftError: () => ToolDriftError,
|
|
77
|
+
ToolEnsureConflictError: () => ToolEnsureConflictError,
|
|
74
78
|
ToolsEndpoint: () => ToolsEndpoint,
|
|
79
|
+
ToolsNamespace: () => ToolsNamespace,
|
|
75
80
|
UsersEndpoint: () => UsersEndpoint,
|
|
76
81
|
applyGeneratedRuntimeToolProposalToDispatchRequest: () => applyGeneratedRuntimeToolProposalToDispatchRequest,
|
|
77
82
|
attachRuntimeToolsToDispatchRequest: () => attachRuntimeToolsToDispatchRequest,
|
|
83
|
+
buildEmptySessionNudge: () => buildEmptySessionNudge,
|
|
78
84
|
buildGeneratedRuntimeToolGateOutput: () => buildGeneratedRuntimeToolGateOutput,
|
|
79
85
|
buildLedgerOffloadReference: () => buildLedgerOffloadReference,
|
|
86
|
+
buildPolicyGuidance: () => buildPolicyGuidance,
|
|
80
87
|
buildSendViewOffloadMarker: () => buildSendViewOffloadMarker,
|
|
88
|
+
compileWorkflowConfig: () => compileWorkflowConfig,
|
|
81
89
|
computeAgentContentHash: () => computeAgentContentHash,
|
|
82
90
|
computeFlowContentHash: () => computeFlowContentHash,
|
|
91
|
+
computeToolContentHash: () => computeToolContentHash,
|
|
83
92
|
createClient: () => createClient,
|
|
84
93
|
createExternalTool: () => createExternalTool,
|
|
85
94
|
defaultWorkflow: () => defaultWorkflow,
|
|
95
|
+
defaultWorkflowConfig: () => defaultWorkflowConfig,
|
|
86
96
|
defineAgent: () => defineAgent,
|
|
87
97
|
defineFlow: () => defineFlow,
|
|
98
|
+
definePlaybook: () => definePlaybook,
|
|
99
|
+
defineTool: () => defineTool,
|
|
88
100
|
deployWorkflow: () => deployWorkflow,
|
|
101
|
+
ensureDefaultWorkflowHooks: () => ensureDefaultWorkflowHooks,
|
|
89
102
|
evaluateGeneratedRuntimeToolProposal: () => evaluateGeneratedRuntimeToolProposal,
|
|
90
103
|
extractDeclaredToolResultChars: () => extractDeclaredToolResultChars,
|
|
91
104
|
gameWorkflow: () => gameWorkflow,
|
|
92
105
|
getDefaultPlanPath: () => getDefaultPlanPath,
|
|
93
106
|
getLikelySupportingCandidatePaths: () => getLikelySupportingCandidatePaths,
|
|
107
|
+
interpolateWorkflowTemplate: () => interpolateWorkflowTemplate,
|
|
94
108
|
isDiscoveryToolName: () => isDiscoveryToolName,
|
|
95
109
|
isMarathonArtifactPath: () => isMarathonArtifactPath,
|
|
96
110
|
isPreservationSensitiveTask: () => isPreservationSensitiveTask,
|
|
111
|
+
isWorkflowHookRef: () => isWorkflowHookRef,
|
|
112
|
+
listWorkflowHooks: () => listWorkflowHooks,
|
|
97
113
|
normalizeAgentDefinition: () => normalizeAgentDefinition,
|
|
98
114
|
normalizeCandidatePath: () => normalizeCandidatePath,
|
|
115
|
+
normalizeToolDefinition: () => normalizeToolDefinition,
|
|
99
116
|
parseFinalBuffer: () => parseFinalBuffer,
|
|
100
117
|
parseLedgerArtifactRelativePath: () => parseLedgerArtifactRelativePath,
|
|
101
118
|
parseOffloadedOutputId: () => parseOffloadedOutputId,
|
|
102
119
|
parseSSEChunk: () => parseSSEChunk,
|
|
103
120
|
processStream: () => processStream,
|
|
121
|
+
registerWorkflowHook: () => registerWorkflowHook,
|
|
122
|
+
resolveStallStopAfter: () => resolveStallStopAfter,
|
|
123
|
+
resolveWorkflowHook: () => resolveWorkflowHook,
|
|
104
124
|
sanitizeTaskSlug: () => sanitizeTaskSlug,
|
|
105
|
-
|
|
125
|
+
shouldInjectEmptySessionNudge: () => shouldInjectEmptySessionNudge,
|
|
126
|
+
shouldRequestModelEscalation: () => shouldRequestModelEscalation,
|
|
127
|
+
streamEvents: () => streamEvents,
|
|
128
|
+
unregisterWorkflowHook: () => unregisterWorkflowHook
|
|
106
129
|
});
|
|
107
130
|
module.exports = __toCommonJS(index_exports);
|
|
108
131
|
|
|
@@ -1202,20 +1225,20 @@ var FlowBuilder = class {
|
|
|
1202
1225
|
*/
|
|
1203
1226
|
build() {
|
|
1204
1227
|
const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
|
|
1205
|
-
const
|
|
1228
|
+
const request3 = { flow };
|
|
1206
1229
|
if (this.recordConfig) {
|
|
1207
|
-
|
|
1230
|
+
request3.record = this.recordConfig;
|
|
1208
1231
|
}
|
|
1209
1232
|
if (this.messagesConfig) {
|
|
1210
|
-
|
|
1233
|
+
request3.messages = this.messagesConfig;
|
|
1211
1234
|
}
|
|
1212
1235
|
if (this.inputsConfig) {
|
|
1213
|
-
|
|
1236
|
+
request3.inputs = this.inputsConfig;
|
|
1214
1237
|
}
|
|
1215
1238
|
if (Object.keys(this.optionsConfig).length > 0) {
|
|
1216
|
-
|
|
1239
|
+
request3.options = this.optionsConfig;
|
|
1217
1240
|
}
|
|
1218
|
-
return
|
|
1241
|
+
return request3;
|
|
1219
1242
|
}
|
|
1220
1243
|
/**
|
|
1221
1244
|
* Validate this prospective flow against the public validation endpoint
|
|
@@ -1538,6 +1561,9 @@ function collectStepNonPortableToolRefs(config, path) {
|
|
|
1538
1561
|
scanArray(tools.codeModeConfig.toolPool, `${path}.tools.codeModeConfig.toolPool`);
|
|
1539
1562
|
}
|
|
1540
1563
|
}
|
|
1564
|
+
if (isAccountScoped(config.toolId)) {
|
|
1565
|
+
found.push(`${path}.toolId`);
|
|
1566
|
+
}
|
|
1541
1567
|
for (const branch of ["trueSteps", "falseSteps"]) {
|
|
1542
1568
|
const nested = config[branch];
|
|
1543
1569
|
if (!Array.isArray(nested)) continue;
|
|
@@ -1591,7 +1617,7 @@ function defineFlow(input) {
|
|
|
1591
1617
|
const nonPortable = collectStepNonPortableToolRefs(config, `steps[${index}].config`);
|
|
1592
1618
|
if (nonPortable.length > 0) {
|
|
1593
1619
|
throw new Error(
|
|
1594
|
-
`defineFlow: account-scoped tool reference(s) at ${nonPortable.join(", ")}. Definitions must be environment-portable \u2014 tool_\u2026 IDs belong to one account/environment. Use builtin:/platform:/mcp: references
|
|
1620
|
+
`defineFlow: account-scoped tool reference(s) at ${nonPortable.join(", ")}. Definitions must be environment-portable \u2014 tool_\u2026 IDs belong to one account/environment. Use builtin:/platform:/mcp: references, or reference a saved tool by name with tool:<name> instead.`
|
|
1595
1621
|
);
|
|
1596
1622
|
}
|
|
1597
1623
|
}
|
|
@@ -2590,15 +2616,15 @@ var RuntypeFlowBuilder = class {
|
|
|
2590
2616
|
build() {
|
|
2591
2617
|
const flowMode = this.mode === "existing" ? "existing" : this.mode;
|
|
2592
2618
|
const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
|
|
2593
|
-
const
|
|
2619
|
+
const request3 = { flow };
|
|
2594
2620
|
if (this.recordConfig) {
|
|
2595
|
-
|
|
2621
|
+
request3.record = this.recordConfig;
|
|
2596
2622
|
}
|
|
2597
2623
|
if (this.messagesConfig) {
|
|
2598
|
-
|
|
2624
|
+
request3.messages = this.messagesConfig;
|
|
2599
2625
|
}
|
|
2600
2626
|
if (this.inputsConfig) {
|
|
2601
|
-
|
|
2627
|
+
request3.inputs = this.inputsConfig;
|
|
2602
2628
|
}
|
|
2603
2629
|
const options = {
|
|
2604
2630
|
flowMode,
|
|
@@ -2616,8 +2642,8 @@ var RuntypeFlowBuilder = class {
|
|
|
2616
2642
|
if (this.mode === "upsert" && Object.keys(this.upsertOptions).length > 0) {
|
|
2617
2643
|
options.upsertOptions = this.upsertOptions;
|
|
2618
2644
|
}
|
|
2619
|
-
|
|
2620
|
-
return
|
|
2645
|
+
request3.options = options;
|
|
2646
|
+
return request3;
|
|
2621
2647
|
}
|
|
2622
2648
|
/**
|
|
2623
2649
|
* Validate this prospective flow against the public validation endpoint
|
|
@@ -3507,7 +3533,7 @@ function defineAgent(input) {
|
|
|
3507
3533
|
const nonPortable = collectNonPortableToolRefs(config);
|
|
3508
3534
|
if (nonPortable.length > 0) {
|
|
3509
3535
|
throw new Error(
|
|
3510
|
-
`defineAgent: account-scoped tool reference(s) at ${nonPortable.join(", ")}. Definitions must be environment-portable \u2014 tool_\u2026 IDs belong to one account/environment. Use builtin:/platform:/mcp: references
|
|
3536
|
+
`defineAgent: account-scoped tool reference(s) at ${nonPortable.join(", ")}. Definitions must be environment-portable \u2014 tool_\u2026 IDs belong to one account/environment. Use builtin:/platform:/mcp: references, or reference a saved tool by name with tool:<name> instead.`
|
|
3511
3537
|
);
|
|
3512
3538
|
}
|
|
3513
3539
|
return {
|
|
@@ -3649,6 +3675,242 @@ var AgentsNamespace = class {
|
|
|
3649
3675
|
}
|
|
3650
3676
|
};
|
|
3651
3677
|
|
|
3678
|
+
// src/tools-ensure.ts
|
|
3679
|
+
function isPlainObject3(value) {
|
|
3680
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3681
|
+
}
|
|
3682
|
+
function normalizeValue2(value) {
|
|
3683
|
+
if (Array.isArray(value)) {
|
|
3684
|
+
return value.map((item) => normalizeValue2(item));
|
|
3685
|
+
}
|
|
3686
|
+
if (isPlainObject3(value)) {
|
|
3687
|
+
const normalized = {};
|
|
3688
|
+
for (const key of Object.keys(value).sort()) {
|
|
3689
|
+
const entry = value[key];
|
|
3690
|
+
if (entry === void 0 || entry === null) continue;
|
|
3691
|
+
normalized[key] = normalizeValue2(entry);
|
|
3692
|
+
}
|
|
3693
|
+
return normalized;
|
|
3694
|
+
}
|
|
3695
|
+
return value;
|
|
3696
|
+
}
|
|
3697
|
+
function normalizeToolDefinition(definition) {
|
|
3698
|
+
const parametersSchema = isPlainObject3(definition.parametersSchema) ? normalizeValue2(definition.parametersSchema) : {};
|
|
3699
|
+
const config = isPlainObject3(definition.config) ? normalizeValue2(definition.config) : {};
|
|
3700
|
+
return {
|
|
3701
|
+
toolType: definition.toolType,
|
|
3702
|
+
...definition.description ? { description: definition.description } : {},
|
|
3703
|
+
parametersSchema,
|
|
3704
|
+
config
|
|
3705
|
+
};
|
|
3706
|
+
}
|
|
3707
|
+
async function computeToolContentHash(definition) {
|
|
3708
|
+
const serialized = JSON.stringify(normalizeToolDefinition(definition));
|
|
3709
|
+
const encoded = new TextEncoder().encode(serialized);
|
|
3710
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
3711
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3712
|
+
}
|
|
3713
|
+
var DEFINE_TOOL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
3714
|
+
"name",
|
|
3715
|
+
"description",
|
|
3716
|
+
"toolType",
|
|
3717
|
+
"parametersSchema",
|
|
3718
|
+
"config"
|
|
3719
|
+
]);
|
|
3720
|
+
var TOOL_DEFINITION_TYPES = /* @__PURE__ */ new Set([
|
|
3721
|
+
"flow",
|
|
3722
|
+
"custom",
|
|
3723
|
+
"external",
|
|
3724
|
+
"graphql",
|
|
3725
|
+
"mcp",
|
|
3726
|
+
"local",
|
|
3727
|
+
"subagent"
|
|
3728
|
+
]);
|
|
3729
|
+
function defineTool(input) {
|
|
3730
|
+
if (!input || typeof input !== "object") {
|
|
3731
|
+
throw new Error("defineTool requires a definition object");
|
|
3732
|
+
}
|
|
3733
|
+
if (typeof input.name !== "string" || input.name.length === 0) {
|
|
3734
|
+
throw new Error('defineTool requires a non-empty string "name"');
|
|
3735
|
+
}
|
|
3736
|
+
if (typeof input.description !== "string" || input.description.length === 0) {
|
|
3737
|
+
throw new Error('defineTool requires a non-empty string "description"');
|
|
3738
|
+
}
|
|
3739
|
+
if (typeof input.toolType !== "string" || !TOOL_DEFINITION_TYPES.has(input.toolType)) {
|
|
3740
|
+
throw new Error(
|
|
3741
|
+
`defineTool requires "toolType" to be one of: ${[...TOOL_DEFINITION_TYPES].join(", ")}`
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
if (!isPlainObject3(input.parametersSchema)) {
|
|
3745
|
+
throw new Error('defineTool requires a "parametersSchema" object (a JSON Schema)');
|
|
3746
|
+
}
|
|
3747
|
+
if (!isPlainObject3(input.config)) {
|
|
3748
|
+
throw new Error('defineTool requires a "config" object');
|
|
3749
|
+
}
|
|
3750
|
+
const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOOL_TOP_LEVEL_KEYS.has(key));
|
|
3751
|
+
if (unknownKeys.length > 0) {
|
|
3752
|
+
throw new Error(
|
|
3753
|
+
`defineTool: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, toolType, parametersSchema, config.`
|
|
3754
|
+
);
|
|
3755
|
+
}
|
|
3756
|
+
return {
|
|
3757
|
+
name: input.name,
|
|
3758
|
+
description: input.description,
|
|
3759
|
+
toolType: input.toolType,
|
|
3760
|
+
parametersSchema: input.parametersSchema,
|
|
3761
|
+
config: input.config
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3764
|
+
var ToolEnsureConflictError = class extends Error {
|
|
3765
|
+
constructor(body) {
|
|
3766
|
+
super(body.error ?? `Tool ensure conflict: ${body.code}`);
|
|
3767
|
+
this.name = "ToolEnsureConflictError";
|
|
3768
|
+
this.code = body.code;
|
|
3769
|
+
this.lastModifiedSource = body.lastModifiedSource;
|
|
3770
|
+
this.modifiedAt = body.modifiedAt;
|
|
3771
|
+
this.currentHash = body.currentHash;
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3774
|
+
var ToolDriftError = class extends Error {
|
|
3775
|
+
constructor(plan) {
|
|
3776
|
+
super(
|
|
3777
|
+
`Tool "${plan.toolId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.tools.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
|
|
3778
|
+
);
|
|
3779
|
+
this.name = "ToolDriftError";
|
|
3780
|
+
this.plan = plan;
|
|
3781
|
+
}
|
|
3782
|
+
};
|
|
3783
|
+
function parseRequestError3(err) {
|
|
3784
|
+
if (!(err instanceof Error)) return { status: null, body: null };
|
|
3785
|
+
const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
|
|
3786
|
+
if (!match) return { status: null, body: null };
|
|
3787
|
+
try {
|
|
3788
|
+
return { status: Number(match[1]), body: JSON.parse(match[2]) };
|
|
3789
|
+
} catch {
|
|
3790
|
+
return { status: Number(match[1]), body: null };
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
function toConflictError3(err) {
|
|
3794
|
+
const { status, body } = parseRequestError3(err);
|
|
3795
|
+
if (status !== 409 || !isPlainObject3(body)) return null;
|
|
3796
|
+
const code = body.code;
|
|
3797
|
+
if (code !== "external_modification" && code !== "remote_changed") return null;
|
|
3798
|
+
return new ToolEnsureConflictError(
|
|
3799
|
+
body
|
|
3800
|
+
);
|
|
3801
|
+
}
|
|
3802
|
+
var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
|
|
3803
|
+
function memoFor3(client) {
|
|
3804
|
+
let memo = serverHashMemo3.get(client);
|
|
3805
|
+
if (!memo) {
|
|
3806
|
+
memo = /* @__PURE__ */ new Map();
|
|
3807
|
+
serverHashMemo3.set(client, memo);
|
|
3808
|
+
}
|
|
3809
|
+
return memo;
|
|
3810
|
+
}
|
|
3811
|
+
function memoize2(memo, memoKey, result) {
|
|
3812
|
+
if (result.result !== "plan") memo.set(memoKey, result.contentHash);
|
|
3813
|
+
}
|
|
3814
|
+
async function request2(client, body) {
|
|
3815
|
+
try {
|
|
3816
|
+
return await client.post(
|
|
3817
|
+
"/tools/ensure",
|
|
3818
|
+
body
|
|
3819
|
+
);
|
|
3820
|
+
} catch (err) {
|
|
3821
|
+
const conflict = toConflictError3(err);
|
|
3822
|
+
if (conflict) throw conflict;
|
|
3823
|
+
throw err;
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
async function ensureTool(client, definition, options = {}) {
|
|
3827
|
+
const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
|
|
3828
|
+
const passthrough = {
|
|
3829
|
+
...onConflict ? { onConflict } : {},
|
|
3830
|
+
...expectedRemoteHash ? { expectedRemoteHash } : {}
|
|
3831
|
+
};
|
|
3832
|
+
if (dryRun || expectNoChanges) {
|
|
3833
|
+
const plan = await request2(client, {
|
|
3834
|
+
name: definition.name,
|
|
3835
|
+
definition,
|
|
3836
|
+
dryRun: true,
|
|
3837
|
+
...passthrough
|
|
3838
|
+
});
|
|
3839
|
+
if (plan.result !== "plan") {
|
|
3840
|
+
throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
|
|
3841
|
+
}
|
|
3842
|
+
if (expectNoChanges && plan.changes !== "none") {
|
|
3843
|
+
throw new ToolDriftError(plan);
|
|
3844
|
+
}
|
|
3845
|
+
return plan;
|
|
3846
|
+
}
|
|
3847
|
+
const memo = memoFor3(client);
|
|
3848
|
+
const localHash = await computeToolContentHash(definition);
|
|
3849
|
+
const memoKey = `${definition.name} ${localHash}`;
|
|
3850
|
+
const contentHash = memo.get(memoKey) ?? localHash;
|
|
3851
|
+
const probe = await request2(client, {
|
|
3852
|
+
name: definition.name,
|
|
3853
|
+
contentHash,
|
|
3854
|
+
...passthrough
|
|
3855
|
+
});
|
|
3856
|
+
if (probe.result !== "definitionRequired") {
|
|
3857
|
+
memoize2(memo, memoKey, probe);
|
|
3858
|
+
return probe;
|
|
3859
|
+
}
|
|
3860
|
+
const converged = await request2(client, {
|
|
3861
|
+
name: definition.name,
|
|
3862
|
+
definition,
|
|
3863
|
+
...passthrough
|
|
3864
|
+
});
|
|
3865
|
+
if (converged.result === "definitionRequired") {
|
|
3866
|
+
throw new Error("Server reported definitionRequired for a full-definition request");
|
|
3867
|
+
}
|
|
3868
|
+
memoize2(memo, memoKey, converged);
|
|
3869
|
+
return converged;
|
|
3870
|
+
}
|
|
3871
|
+
async function pullTool(client, name) {
|
|
3872
|
+
return client.get("/tools/pull", { name });
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
// src/tools-namespace.ts
|
|
3876
|
+
var ToolsNamespace = class {
|
|
3877
|
+
constructor(getClient) {
|
|
3878
|
+
this.getClient = getClient;
|
|
3879
|
+
}
|
|
3880
|
+
/**
|
|
3881
|
+
* Idempotently converge a `defineTool` definition onto the platform.
|
|
3882
|
+
* Hash-first: the steady state is one tiny probe request. Creates or updates
|
|
3883
|
+
* the saved tool; never deletes. Identity is name + account scope.
|
|
3884
|
+
*
|
|
3885
|
+
* @example
|
|
3886
|
+
* ```typescript
|
|
3887
|
+
* const weather = defineTool({
|
|
3888
|
+
* name: 'Weather Lookup',
|
|
3889
|
+
* description: 'Fetch the current weather for a city',
|
|
3890
|
+
* toolType: 'external',
|
|
3891
|
+
* parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
|
|
3892
|
+
* config: { url: 'https://api.example.com/weather', method: 'GET' },
|
|
3893
|
+
* })
|
|
3894
|
+
*
|
|
3895
|
+
* // Converge (CI/deploy).
|
|
3896
|
+
* const result = await Runtype.tools.ensure(weather)
|
|
3897
|
+
*
|
|
3898
|
+
* // PR drift gate.
|
|
3899
|
+
* await Runtype.tools.ensure(weather, { expectNoChanges: true })
|
|
3900
|
+
* ```
|
|
3901
|
+
*/
|
|
3902
|
+
async ensure(definition, options = {}) {
|
|
3903
|
+
return ensureTool(this.getClient(), definition, options);
|
|
3904
|
+
}
|
|
3905
|
+
/**
|
|
3906
|
+
* Pull the canonical definition + provenance for a tool by name — the
|
|
3907
|
+
* absorb-drift direction of the ensure protocol.
|
|
3908
|
+
*/
|
|
3909
|
+
async pull(name) {
|
|
3910
|
+
return pullTool(this.getClient(), name);
|
|
3911
|
+
}
|
|
3912
|
+
};
|
|
3913
|
+
|
|
3652
3914
|
// src/transform.ts
|
|
3653
3915
|
function transformResponse(data) {
|
|
3654
3916
|
return data;
|
|
@@ -4037,6 +4299,34 @@ var Runtype = class {
|
|
|
4037
4299
|
static get agents() {
|
|
4038
4300
|
return new AgentsNamespace(() => this.getClient());
|
|
4039
4301
|
}
|
|
4302
|
+
/**
|
|
4303
|
+
* Tools namespace - Tool config-as-code (define / ensure / pull)
|
|
4304
|
+
*
|
|
4305
|
+
* @example
|
|
4306
|
+
* ```typescript
|
|
4307
|
+
* import { defineTool, Runtype } from '@runtypelabs/sdk'
|
|
4308
|
+
*
|
|
4309
|
+
* const weather = defineTool({
|
|
4310
|
+
* name: 'Weather Lookup',
|
|
4311
|
+
* description: 'Fetch the current weather for a city',
|
|
4312
|
+
* toolType: 'external',
|
|
4313
|
+
* parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
|
|
4314
|
+
* config: { url: 'https://api.example.com/weather', method: 'GET' },
|
|
4315
|
+
* })
|
|
4316
|
+
*
|
|
4317
|
+
* // Converge at deploy time (idempotent; one tiny probe in steady state)
|
|
4318
|
+
* await Runtype.tools.ensure(weather)
|
|
4319
|
+
*
|
|
4320
|
+
* // CI drift gate
|
|
4321
|
+
* await Runtype.tools.ensure(weather, { expectNoChanges: true })
|
|
4322
|
+
*
|
|
4323
|
+
* // Absorb a dashboard edit back into the repo
|
|
4324
|
+
* const { definition } = await Runtype.tools.pull('Weather Lookup')
|
|
4325
|
+
* ```
|
|
4326
|
+
*/
|
|
4327
|
+
static get tools() {
|
|
4328
|
+
return new ToolsNamespace(() => this.getClient());
|
|
4329
|
+
}
|
|
4040
4330
|
};
|
|
4041
4331
|
|
|
4042
4332
|
// src/generated-tool-gate.ts
|
|
@@ -4259,8 +4549,8 @@ function buildGeneratedRuntimeToolGateOutput(proposal, options = {}) {
|
|
|
4259
4549
|
...decision.tool ? { tool: decision.tool } : {}
|
|
4260
4550
|
};
|
|
4261
4551
|
}
|
|
4262
|
-
function attachRuntimeToolsToDispatchRequest(
|
|
4263
|
-
const stepList =
|
|
4552
|
+
function attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options = {}) {
|
|
4553
|
+
const stepList = request3.flow.steps;
|
|
4264
4554
|
if (!stepList || !Array.isArray(stepList) || stepList.length === 0) {
|
|
4265
4555
|
throw new Error("Cannot attach runtime tools: dispatch request must include flow.steps");
|
|
4266
4556
|
}
|
|
@@ -4303,9 +4593,9 @@ function attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options = {
|
|
|
4303
4593
|
}
|
|
4304
4594
|
};
|
|
4305
4595
|
return {
|
|
4306
|
-
...
|
|
4596
|
+
...request3,
|
|
4307
4597
|
flow: {
|
|
4308
|
-
...
|
|
4598
|
+
...request3.flow,
|
|
4309
4599
|
// `clonedSteps` is a structural clone of `request.flow.steps` (already
|
|
4310
4600
|
// `FlowStepDefinition[]`); only the prompt step's `config.tools` was
|
|
4311
4601
|
// merged, so every step's `type` discriminant is preserved. The clone is
|
|
@@ -4315,12 +4605,12 @@ function attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options = {
|
|
|
4315
4605
|
}
|
|
4316
4606
|
};
|
|
4317
4607
|
}
|
|
4318
|
-
function applyGeneratedRuntimeToolProposalToDispatchRequest(
|
|
4608
|
+
function applyGeneratedRuntimeToolProposalToDispatchRequest(request3, proposal, options = {}) {
|
|
4319
4609
|
const decision = evaluateGeneratedRuntimeToolProposal(proposal, options.gate);
|
|
4320
4610
|
if (!decision.approved || !decision.tool) {
|
|
4321
|
-
return { decision, request:
|
|
4611
|
+
return { decision, request: request3 };
|
|
4322
4612
|
}
|
|
4323
|
-
const nextRequest = attachRuntimeToolsToDispatchRequest(
|
|
4613
|
+
const nextRequest = attachRuntimeToolsToDispatchRequest(request3, [decision.tool], options.attach);
|
|
4324
4614
|
return {
|
|
4325
4615
|
decision,
|
|
4326
4616
|
request: nextRequest
|
|
@@ -4418,6 +4708,261 @@ function sanitizeTaskSlug(taskName) {
|
|
|
4418
4708
|
return taskName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
4419
4709
|
}
|
|
4420
4710
|
|
|
4711
|
+
// src/workflows/hook-registry.ts
|
|
4712
|
+
var BUILTIN_NAMESPACE = "builtin";
|
|
4713
|
+
var HOOK_REF_PATTERN = /^[a-z0-9_-]+:[a-z0-9_-]+$/;
|
|
4714
|
+
function isWorkflowHookRef(value) {
|
|
4715
|
+
return typeof value === "string" && HOOK_REF_PATTERN.test(value);
|
|
4716
|
+
}
|
|
4717
|
+
var registry = /* @__PURE__ */ new Map();
|
|
4718
|
+
function registerWorkflowHook(name, entry) {
|
|
4719
|
+
if (!isWorkflowHookRef(name)) {
|
|
4720
|
+
throw new Error(
|
|
4721
|
+
`Invalid workflow hook name "${name}": must be "<namespace>:<id>" using lowercase letters, digits, "-" or "_" (e.g. "acme:my-completion").`
|
|
4722
|
+
);
|
|
4723
|
+
}
|
|
4724
|
+
if (name.startsWith(`${BUILTIN_NAMESPACE}:`)) {
|
|
4725
|
+
throw new Error(
|
|
4726
|
+
`Cannot register "${name}": the "builtin:" namespace is reserved. Register under your own namespace and reference it from the workflow config instead.`
|
|
4727
|
+
);
|
|
4728
|
+
}
|
|
4729
|
+
registry.set(name, entry);
|
|
4730
|
+
}
|
|
4731
|
+
function registerBuiltinWorkflowHook(name, entry) {
|
|
4732
|
+
if (!name.startsWith(`${BUILTIN_NAMESPACE}:`) || !isWorkflowHookRef(name)) {
|
|
4733
|
+
throw new Error(`Builtin workflow hooks must be named "builtin:<id>" (got "${name}").`);
|
|
4734
|
+
}
|
|
4735
|
+
if (registry.has(name)) return;
|
|
4736
|
+
registry.set(name, entry);
|
|
4737
|
+
}
|
|
4738
|
+
function resolveWorkflowHook(name, expectedKind) {
|
|
4739
|
+
const entry = registry.get(name);
|
|
4740
|
+
if (!entry) {
|
|
4741
|
+
const known = listWorkflowHooks().filter((hook) => hook.kind === expectedKind).map((hook) => hook.name);
|
|
4742
|
+
throw new Error(
|
|
4743
|
+
`Unknown workflow hook "${name}". ` + (known.length > 0 ? `Registered '${expectedKind}' hooks: ${known.join(", ")}.` : `No '${expectedKind}' hooks are registered.`) + " Custom hooks must be registered (e.g. via a playbook plugin) before the workflow is compiled."
|
|
4744
|
+
);
|
|
4745
|
+
}
|
|
4746
|
+
if (entry.kind !== expectedKind) {
|
|
4747
|
+
throw new Error(
|
|
4748
|
+
`Workflow hook "${name}" is registered as '${entry.kind}' but referenced from a '${expectedKind}' slot.`
|
|
4749
|
+
);
|
|
4750
|
+
}
|
|
4751
|
+
return entry.fn;
|
|
4752
|
+
}
|
|
4753
|
+
function listWorkflowHooks() {
|
|
4754
|
+
return [...registry.entries()].map(([name, entry]) => ({ name, kind: entry.kind }));
|
|
4755
|
+
}
|
|
4756
|
+
function unregisterWorkflowHook(name) {
|
|
4757
|
+
if (name.startsWith(`${BUILTIN_NAMESPACE}:`)) return false;
|
|
4758
|
+
return registry.delete(name);
|
|
4759
|
+
}
|
|
4760
|
+
|
|
4761
|
+
// src/workflows/workflow-config.ts
|
|
4762
|
+
var DISCOVERY_TOOLS = /* @__PURE__ */ new Set([
|
|
4763
|
+
"search_repo",
|
|
4764
|
+
"glob_files",
|
|
4765
|
+
"tree_directory",
|
|
4766
|
+
"list_directory"
|
|
4767
|
+
]);
|
|
4768
|
+
var DEFAULT_RECOVERY_AFTER_EMPTY_SESSIONS = 2;
|
|
4769
|
+
function definePlaybook(playbook) {
|
|
4770
|
+
return playbook;
|
|
4771
|
+
}
|
|
4772
|
+
function interpolateWorkflowTemplate(template, state) {
|
|
4773
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
4774
|
+
const value = state[key];
|
|
4775
|
+
if (value === void 0 || value === null) return `{{${key}}}`;
|
|
4776
|
+
return String(value);
|
|
4777
|
+
});
|
|
4778
|
+
}
|
|
4779
|
+
function buildIsComplete(criteria, configName, milestoneName) {
|
|
4780
|
+
if (!criteria) return () => false;
|
|
4781
|
+
switch (criteria.type) {
|
|
4782
|
+
case "evidence":
|
|
4783
|
+
return (ctx) => {
|
|
4784
|
+
const minFiles = criteria.minReadFiles ?? 1;
|
|
4785
|
+
return (ctx.state.recentReadPaths?.length ?? 0) >= minFiles;
|
|
4786
|
+
};
|
|
4787
|
+
case "sessions": {
|
|
4788
|
+
let baselineSessionCount;
|
|
4789
|
+
return (ctx) => {
|
|
4790
|
+
const minSessions = criteria.minSessions ?? 1;
|
|
4791
|
+
if (baselineSessionCount === void 0) {
|
|
4792
|
+
baselineSessionCount = ctx.state.sessions.length;
|
|
4793
|
+
}
|
|
4794
|
+
return ctx.state.sessions.length - baselineSessionCount >= minSessions;
|
|
4795
|
+
};
|
|
4796
|
+
}
|
|
4797
|
+
case "planWritten":
|
|
4798
|
+
return (ctx) => {
|
|
4799
|
+
return ctx.trace.planWritten;
|
|
4800
|
+
};
|
|
4801
|
+
case "never":
|
|
4802
|
+
return () => false;
|
|
4803
|
+
default: {
|
|
4804
|
+
if (isWorkflowHookRef(criteria.type)) {
|
|
4805
|
+
return resolveWorkflowHook(criteria.type, "completion");
|
|
4806
|
+
}
|
|
4807
|
+
throw new Error(
|
|
4808
|
+
`Workflow config '${configName}': milestone '${milestoneName}' has unknown completionCriteria.type "${criteria.type}" (expected evidence | sessions | planWritten | never, or a 'completion' hook reference).`
|
|
4809
|
+
);
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
}
|
|
4813
|
+
function buildPolicyIntercept(policy, configName, deps) {
|
|
4814
|
+
if (!policy.blockedTools?.length && !policy.blockDiscoveryTools && !policy.allowedReadGlobs?.length && !policy.allowedWriteGlobs?.length && !policy.requirePlanBeforeWrite) {
|
|
4815
|
+
return void 0;
|
|
4816
|
+
}
|
|
4817
|
+
const blockedSet = new Set(
|
|
4818
|
+
(policy.blockedTools ?? []).map((t) => t.trim()).filter(Boolean)
|
|
4819
|
+
);
|
|
4820
|
+
const readGlobs = policy.allowedReadGlobs ?? [];
|
|
4821
|
+
const writeGlobs = policy.allowedWriteGlobs ?? [];
|
|
4822
|
+
const matchPathGlobs = deps.matchPathGlobs;
|
|
4823
|
+
if ((readGlobs.length > 0 || writeGlobs.length > 0) && !matchPathGlobs) {
|
|
4824
|
+
throw new Error(
|
|
4825
|
+
`Workflow config '${configName}': policy uses allowedReadGlobs/allowedWriteGlobs but no glob matcher was provided to compileWorkflowConfig (pass deps.matchPathGlobs).`
|
|
4826
|
+
);
|
|
4827
|
+
}
|
|
4828
|
+
return (toolName, args, ctx) => {
|
|
4829
|
+
if (blockedSet.has(toolName)) {
|
|
4830
|
+
return `Blocked by playbook policy: ${toolName} is not allowed for this task.`;
|
|
4831
|
+
}
|
|
4832
|
+
if (policy.blockDiscoveryTools && DISCOVERY_TOOLS.has(toolName)) {
|
|
4833
|
+
return `Blocked by playbook policy: discovery tools are disabled for this task.`;
|
|
4834
|
+
}
|
|
4835
|
+
const pathArg = typeof args.path === "string" && args.path.trim() ? ctx.normalizePath(String(args.path)) : void 0;
|
|
4836
|
+
if (pathArg) {
|
|
4837
|
+
const isWrite = toolName === "write_file" || toolName === "restore_file_checkpoint";
|
|
4838
|
+
const isRead = toolName === "read_file";
|
|
4839
|
+
if (isRead && readGlobs.length > 0) {
|
|
4840
|
+
const allowed = matchPathGlobs(pathArg, readGlobs);
|
|
4841
|
+
if (!allowed) {
|
|
4842
|
+
return `Blocked by playbook policy: ${toolName} path "${pathArg}" is outside allowed read globs: ${readGlobs.join(", ")}`;
|
|
4843
|
+
}
|
|
4844
|
+
}
|
|
4845
|
+
if (isWrite && writeGlobs.length > 0) {
|
|
4846
|
+
const planPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
4847
|
+
if (planPath && pathArg === planPath) {
|
|
4848
|
+
} else {
|
|
4849
|
+
const allowed = matchPathGlobs(pathArg, writeGlobs);
|
|
4850
|
+
if (!allowed) {
|
|
4851
|
+
return `Blocked by playbook policy: ${toolName} path "${pathArg}" is outside allowed write globs: ${writeGlobs.join(", ")}`;
|
|
4852
|
+
}
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
if (isWrite && policy.requirePlanBeforeWrite && !ctx.state.planWritten && !ctx.trace.planWritten) {
|
|
4856
|
+
const planPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
4857
|
+
if (!planPath || pathArg !== planPath) {
|
|
4858
|
+
return `Blocked by playbook policy: write the plan before creating other files.`;
|
|
4859
|
+
}
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
return void 0;
|
|
4863
|
+
};
|
|
4864
|
+
}
|
|
4865
|
+
function buildPolicyGuidance(policy) {
|
|
4866
|
+
if (!policy) return [];
|
|
4867
|
+
const lines = [];
|
|
4868
|
+
if (policy.requirePlanBeforeWrite) {
|
|
4869
|
+
lines.push(
|
|
4870
|
+
"Policy: write the plan file before any other file. Once the plan is written, other writes are allowed in the same turn."
|
|
4871
|
+
);
|
|
4872
|
+
}
|
|
4873
|
+
if (policy.allowedWriteGlobs?.length) {
|
|
4874
|
+
lines.push(
|
|
4875
|
+
`Policy: file writes are only allowed for paths matching: ${policy.allowedWriteGlobs.join(", ")} (the plan file is always allowed).`
|
|
4876
|
+
);
|
|
4877
|
+
}
|
|
4878
|
+
if (policy.outputRoot) {
|
|
4879
|
+
lines.push(`Policy: create new files under "${policy.outputRoot.replace(/\/$/, "")}/".`);
|
|
4880
|
+
}
|
|
4881
|
+
if (policy.allowedReadGlobs?.length) {
|
|
4882
|
+
lines.push(
|
|
4883
|
+
`Policy: file reads are only allowed for paths matching: ${policy.allowedReadGlobs.join(", ")}.`
|
|
4884
|
+
);
|
|
4885
|
+
}
|
|
4886
|
+
if (policy.blockDiscoveryTools) {
|
|
4887
|
+
lines.push(
|
|
4888
|
+
"Policy: broad discovery tools (search_repo, glob_files, tree_directory, list_directory) are disabled for this task."
|
|
4889
|
+
);
|
|
4890
|
+
}
|
|
4891
|
+
if (policy.blockedTools?.length) {
|
|
4892
|
+
lines.push(`Policy: these tools are disabled for this task: ${policy.blockedTools.join(", ")}.`);
|
|
4893
|
+
}
|
|
4894
|
+
return lines;
|
|
4895
|
+
}
|
|
4896
|
+
function resolveSlotHook(value, kind) {
|
|
4897
|
+
if (value === void 0) return void 0;
|
|
4898
|
+
if (typeof value === "function") return value;
|
|
4899
|
+
return resolveWorkflowHook(value, kind);
|
|
4900
|
+
}
|
|
4901
|
+
function compileMilestone(milestone, config, policyIntercept, policyGuidance) {
|
|
4902
|
+
const buildInstructions = typeof milestone.instructions === "function" ? milestone.instructions : isWorkflowHookRef(milestone.instructions) ? resolveWorkflowHook(milestone.instructions, "instructions") : (state) => {
|
|
4903
|
+
const header = `--- Workflow Phase: ${milestone.name} ---`;
|
|
4904
|
+
const desc = milestone.description ? `
|
|
4905
|
+
${milestone.description}` : "";
|
|
4906
|
+
const instructions = interpolateWorkflowTemplate(
|
|
4907
|
+
milestone.instructions,
|
|
4908
|
+
state
|
|
4909
|
+
);
|
|
4910
|
+
return `${header}${desc}
|
|
4911
|
+
${instructions}`;
|
|
4912
|
+
};
|
|
4913
|
+
const guidanceHook = typeof milestone.toolGuidance === "function" ? milestone.toolGuidance : milestone.toolGuidance !== void 0 && isWorkflowHookRef(milestone.toolGuidance) ? resolveWorkflowHook(milestone.toolGuidance, "toolGuidance") : void 0;
|
|
4914
|
+
const buildToolGuidance = (state) => {
|
|
4915
|
+
const base = guidanceHook ? guidanceHook(state) : milestone.toolGuidance ?? [];
|
|
4916
|
+
return policyGuidance.length > 0 ? [...base, ...policyGuidance] : base;
|
|
4917
|
+
};
|
|
4918
|
+
const customIntercept = resolveSlotHook(milestone.intercept, "intercept");
|
|
4919
|
+
const interceptToolCall = policyIntercept && customIntercept ? (toolName, args, ctx) => policyIntercept(toolName, args, ctx) ?? customIntercept(toolName, args, ctx) : policyIntercept ?? customIntercept;
|
|
4920
|
+
const transitionHook = typeof milestone.transitionSummary === "function" ? milestone.transitionSummary : milestone.transitionSummary !== void 0 && isWorkflowHookRef(milestone.transitionSummary) ? resolveWorkflowHook(milestone.transitionSummary, "transitionSummary") : void 0;
|
|
4921
|
+
const buildTransitionSummary = milestone.transitionSummary === void 0 ? void 0 : transitionHook ?? ((state, nextPhaseName) => interpolateWorkflowTemplate(milestone.transitionSummary, state).replace(
|
|
4922
|
+
/\{\{nextPhase\}\}/g,
|
|
4923
|
+
nextPhaseName
|
|
4924
|
+
));
|
|
4925
|
+
const recoveryHook = typeof milestone.recovery === "function" ? milestone.recovery : milestone.recovery !== void 0 && isWorkflowHookRef(milestone.recovery) ? resolveWorkflowHook(milestone.recovery, "recovery") : void 0;
|
|
4926
|
+
const buildRecoveryMessage = milestone.recovery === void 0 ? void 0 : recoveryHook ?? ((state) => {
|
|
4927
|
+
const inline = milestone.recovery;
|
|
4928
|
+
const threshold = inline.afterEmptySessions ?? DEFAULT_RECOVERY_AFTER_EMPTY_SESSIONS;
|
|
4929
|
+
if ((state.consecutiveEmptySessions ?? 0) < threshold) return void 0;
|
|
4930
|
+
return interpolateWorkflowTemplate(inline.message, state);
|
|
4931
|
+
});
|
|
4932
|
+
const canAcceptCompletion = milestone.canAcceptCompletion === void 0 ? void 0 : typeof milestone.canAcceptCompletion === "function" ? milestone.canAcceptCompletion : isWorkflowHookRef(milestone.canAcceptCompletion) ? resolveWorkflowHook(milestone.canAcceptCompletion, "acceptCompletion") : () => milestone.canAcceptCompletion;
|
|
4933
|
+
const isComplete = typeof milestone.completionCriteria === "function" ? milestone.completionCriteria : buildIsComplete(milestone.completionCriteria, config.name, milestone.name);
|
|
4934
|
+
return {
|
|
4935
|
+
name: milestone.name,
|
|
4936
|
+
description: milestone.description,
|
|
4937
|
+
buildInstructions,
|
|
4938
|
+
buildToolGuidance,
|
|
4939
|
+
isComplete,
|
|
4940
|
+
...interceptToolCall ? { interceptToolCall } : {},
|
|
4941
|
+
...buildTransitionSummary ? { buildTransitionSummary } : {},
|
|
4942
|
+
...buildRecoveryMessage ? { buildRecoveryMessage } : {},
|
|
4943
|
+
...milestone.forceEndTurn ? { shouldForceEndTurn: resolveSlotHook(milestone.forceEndTurn, "forceEndTurn") } : {},
|
|
4944
|
+
...canAcceptCompletion ? { canAcceptCompletion } : {}
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
function compileWorkflowConfig(config, deps = {}) {
|
|
4948
|
+
const policyIntercept = config.policy ? buildPolicyIntercept(config.policy, config.name, deps) : void 0;
|
|
4949
|
+
const policyGuidance = buildPolicyGuidance(config.policy);
|
|
4950
|
+
const phases = config.milestones.map(
|
|
4951
|
+
(milestone) => compileMilestone(milestone, config, policyIntercept, policyGuidance)
|
|
4952
|
+
);
|
|
4953
|
+
const classifyVariant4 = resolveSlotHook(config.classifyVariant, "classify");
|
|
4954
|
+
const generateBootstrapContext2 = resolveSlotHook(config.bootstrap, "bootstrap");
|
|
4955
|
+
const buildCandidateBlock2 = resolveSlotHook(config.candidateBlock, "candidateBlock");
|
|
4956
|
+
return {
|
|
4957
|
+
name: config.name,
|
|
4958
|
+
phases,
|
|
4959
|
+
...config.stallPolicy ? { stallPolicy: config.stallPolicy } : {},
|
|
4960
|
+
...classifyVariant4 ? { classifyVariant: classifyVariant4 } : {},
|
|
4961
|
+
...generateBootstrapContext2 ? { generateBootstrapContext: generateBootstrapContext2 } : {},
|
|
4962
|
+
...buildCandidateBlock2 ? { buildCandidateBlock: buildCandidateBlock2 } : {}
|
|
4963
|
+
};
|
|
4964
|
+
}
|
|
4965
|
+
|
|
4421
4966
|
// src/workflows/default-workflow.ts
|
|
4422
4967
|
function isExternalTask(state) {
|
|
4423
4968
|
return state.workflowVariant === "external";
|
|
@@ -4567,6 +5112,45 @@ function summarizeTextBlock(value, maxLines = 4) {
|
|
|
4567
5112
|
if (!text) return "";
|
|
4568
5113
|
return text.split("\n").map((line) => line.trim()).filter(Boolean).slice(0, maxLines).join(" | ").slice(0, 240);
|
|
4569
5114
|
}
|
|
5115
|
+
function interceptProductWriteTarget(toolName, normalizedPathArg, ctx, guardLabel) {
|
|
5116
|
+
const normalizedPlanPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
5117
|
+
const normalizedBestCandidatePath = ctx.state.bestCandidatePath ? ctx.normalizePath(ctx.state.bestCandidatePath) : void 0;
|
|
5118
|
+
if (!ctx.state.isCreationTask && normalizedPathArg && normalizedPathArg !== normalizedPlanPath) {
|
|
5119
|
+
const allowedWriteTargets = new Set(
|
|
5120
|
+
[
|
|
5121
|
+
normalizedPlanPath,
|
|
5122
|
+
normalizedBestCandidatePath,
|
|
5123
|
+
...(ctx.state.recentReadPaths || []).map((readPath) => ctx.normalizePath(readPath)),
|
|
5124
|
+
...ctx.trace.readPaths.map((readPath) => ctx.normalizePath(readPath))
|
|
5125
|
+
].filter((value) => Boolean(value))
|
|
5126
|
+
);
|
|
5127
|
+
if (!allowedWriteTargets.has(normalizedPathArg)) {
|
|
5128
|
+
return [
|
|
5129
|
+
`Blocked by marathon ${guardLabel}: ${toolName} is limited to the confirmed target, the plan file, or files already discovered/read for this task.`,
|
|
5130
|
+
`Do not create scratch files like "${normalizedPathArg}".`,
|
|
5131
|
+
normalizedBestCandidatePath ? `Edit "${normalizedBestCandidatePath}" or another previously discovered repo file instead.` : "Read the current target file before writing."
|
|
5132
|
+
].join(" ");
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
if (ctx.state.isCreationTask && normalizedPathArg && normalizedPathArg !== normalizedPlanPath) {
|
|
5136
|
+
const outputRoot = ctx.state.outputRoot ? ctx.state.outputRoot.trim().replace(/\\/g, "/").replace(/\/+/g, "/").replace(/\/$/, "") || void 0 : void 0;
|
|
5137
|
+
if (!outputRoot) {
|
|
5138
|
+
return [
|
|
5139
|
+
`Blocked by marathon ${guardLabel}: creation tasks require outputRoot. Writes outside the plan are not allowed.`,
|
|
5140
|
+
`Plan path: "${normalizedPlanPath}". Create files only under the configured output root.`
|
|
5141
|
+
].join(" ");
|
|
5142
|
+
}
|
|
5143
|
+
const rootPrefix = outputRoot + "/";
|
|
5144
|
+
const isUnderRoot = normalizedPathArg === outputRoot || normalizedPathArg.startsWith(rootPrefix);
|
|
5145
|
+
if (!isUnderRoot) {
|
|
5146
|
+
return [
|
|
5147
|
+
`Blocked by marathon ${guardLabel}: ${toolName} must target the plan or paths under outputRoot "${outputRoot}/".`,
|
|
5148
|
+
`"${normalizedPathArg}" is outside the allowed output root.`
|
|
5149
|
+
].join(" ");
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
return void 0;
|
|
5153
|
+
}
|
|
4570
5154
|
var researchPhase = {
|
|
4571
5155
|
name: "research",
|
|
4572
5156
|
description: "Inspect the repo and identify the correct target file",
|
|
@@ -4651,11 +5235,15 @@ var researchPhase = {
|
|
|
4651
5235
|
const normalizedPathArg2 = typeof _args.path === "string" && _args.path.trim() ? ctx.normalizePath(String(_args.path)) : void 0;
|
|
4652
5236
|
const normalizedPlanPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
4653
5237
|
if (normalizedPathArg2 && normalizedPlanPath && normalizedPathArg2 !== normalizedPlanPath) {
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
5238
|
+
const planWritten = ctx.trace.planWritten || Boolean(ctx.state.planWritten);
|
|
5239
|
+
if (!planWritten) {
|
|
5240
|
+
return [
|
|
5241
|
+
`Blocked by marathon research guard: ${toolName} cannot create product files during the research phase.`,
|
|
5242
|
+
"Complete research first, then the system will advance you to planning.",
|
|
5243
|
+
`You may write the plan to "${normalizedPlanPath}" once research is complete.`
|
|
5244
|
+
].join(" ");
|
|
5245
|
+
}
|
|
5246
|
+
return interceptProductWriteTarget(toolName, normalizedPathArg2, ctx, "research guard");
|
|
4659
5247
|
}
|
|
4660
5248
|
}
|
|
4661
5249
|
return void 0;
|
|
@@ -4778,19 +5366,24 @@ var planningPhase = {
|
|
|
4778
5366
|
"Research is complete. Write the implementation plan for building this from scratch.",
|
|
4779
5367
|
`Write the plan markdown to exactly: ${planPath}`,
|
|
4780
5368
|
"List the files you will create, their locations, purpose, and any dependencies to install.",
|
|
5369
|
+
...state.outputRoot ? [
|
|
5370
|
+
`All new files must be created under "${state.outputRoot}" \u2014 writes outside that directory are blocked, so plan every file location inside it.`
|
|
5371
|
+
] : [],
|
|
4781
5372
|
'Include a "Verification steps" section listing the concrete checks you will run before TASK_COMPLETE.',
|
|
4782
|
-
"If the plan already exists, update that same plan file instead of creating a different one."
|
|
5373
|
+
"If the plan already exists, update that same plan file instead of creating a different one.",
|
|
5374
|
+
"Once the plan is written, you may begin creating the planned files in the same turn."
|
|
4783
5375
|
].join("\n");
|
|
4784
5376
|
}
|
|
4785
5377
|
return [
|
|
4786
5378
|
"--- Workflow Phase: Planning ---",
|
|
4787
5379
|
"Research is complete. Your current job is to write the implementation plan before any product-file edits.",
|
|
4788
5380
|
`Write the plan markdown to exactly: ${planPath}`,
|
|
4789
|
-
"Do NOT edit the target product file
|
|
5381
|
+
"Do NOT edit the target product file before the plan exists.",
|
|
4790
5382
|
"The plan should summarize UX findings, explain why the current best candidate is the right file, and list concrete execution steps.",
|
|
4791
5383
|
'The plan must include a "Preserve existing functionality" section that lists current behaviors, linked files, integrations, and constraints that must keep working.',
|
|
4792
5384
|
'The plan must include a "Verification steps" section listing the concrete checks you will run before TASK_COMPLETE.',
|
|
4793
|
-
"If the plan already exists, update that same plan file instead of creating a different one."
|
|
5385
|
+
"If the plan already exists, update that same plan file instead of creating a different one.",
|
|
5386
|
+
"Once the plan is written, you may begin editing the target file in the same turn."
|
|
4794
5387
|
].join("\n");
|
|
4795
5388
|
},
|
|
4796
5389
|
buildToolGuidance(state) {
|
|
@@ -4818,10 +5411,14 @@ var planningPhase = {
|
|
|
4818
5411
|
const normalizedPlanPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
4819
5412
|
const isWriteLikeTool = toolName === "write_file" || toolName === "edit_file" || toolName === "restore_file_checkpoint";
|
|
4820
5413
|
if (isWriteLikeTool && normalizedPathArg && normalizedPlanPath && normalizedPathArg !== normalizedPlanPath) {
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
5414
|
+
const planWritten = ctx.trace.planWritten || Boolean(ctx.state.planWritten);
|
|
5415
|
+
if (!planWritten) {
|
|
5416
|
+
return [
|
|
5417
|
+
`Blocked by marathon planning guard: ${toolName} must target the exact plan path during planning.`,
|
|
5418
|
+
`Write the plan to "${normalizedPlanPath}" before editing any product files.`
|
|
5419
|
+
].join(" ");
|
|
5420
|
+
}
|
|
5421
|
+
return interceptProductWriteTarget(toolName, normalizedPathArg, ctx, "planning guard");
|
|
4825
5422
|
}
|
|
4826
5423
|
return void 0;
|
|
4827
5424
|
},
|
|
@@ -4881,6 +5478,9 @@ var executionPhase = {
|
|
|
4881
5478
|
},
|
|
4882
5479
|
buildToolGuidance(state) {
|
|
4883
5480
|
return [
|
|
5481
|
+
...state.isCreationTask && state.outputRoot ? [
|
|
5482
|
+
`Creation guard: create new files under "${state.outputRoot}". Writes outside it are blocked \u2014 the plan file is the only exception.`
|
|
5483
|
+
] : [],
|
|
4884
5484
|
...state.bestCandidatePath ? [
|
|
4885
5485
|
`Execution-phase guard: broad discovery tools (search_repo, glob_files, tree_directory, list_directory) are locked while executing against "${state.bestCandidatePath}".`
|
|
4886
5486
|
] : [
|
|
@@ -4922,40 +5522,13 @@ var executionPhase = {
|
|
|
4922
5522
|
`After that, you may update "${normalizedPlanPath}" with progress.`
|
|
4923
5523
|
].join(" ");
|
|
4924
5524
|
}
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
].filter((value) => Boolean(value))
|
|
4933
|
-
);
|
|
4934
|
-
if (!allowedWriteTargets.has(normalizedPathArg)) {
|
|
4935
|
-
return [
|
|
4936
|
-
`Blocked by marathon execution guard: ${toolName} is limited to the confirmed target, the plan file, or files already discovered/read for this task.`,
|
|
4937
|
-
`Do not create scratch files like "${normalizedPathArg}".`,
|
|
4938
|
-
normalizedBestCandidatePath ? `Edit "${normalizedBestCandidatePath}" or another previously discovered repo file instead.` : "Read the current target file before writing."
|
|
4939
|
-
].join(" ");
|
|
4940
|
-
}
|
|
4941
|
-
}
|
|
4942
|
-
if (ctx.state.isCreationTask && normalizedPathArg && normalizedPathArg !== normalizedPlanPath) {
|
|
4943
|
-
const outputRoot = ctx.state.outputRoot ? ctx.state.outputRoot.trim().replace(/\\/g, "/").replace(/\/+/g, "/").replace(/\/$/, "") || void 0 : void 0;
|
|
4944
|
-
if (!outputRoot) {
|
|
4945
|
-
return [
|
|
4946
|
-
`Blocked by marathon execution guard: creation tasks require outputRoot. Writes outside the plan are not allowed.`,
|
|
4947
|
-
`Plan path: "${normalizedPlanPath}". Create files only under the configured output root.`
|
|
4948
|
-
].join(" ");
|
|
4949
|
-
}
|
|
4950
|
-
const rootPrefix = outputRoot + "/";
|
|
4951
|
-
const isUnderRoot = normalizedPathArg === outputRoot || normalizedPathArg.startsWith(rootPrefix);
|
|
4952
|
-
if (!isUnderRoot) {
|
|
4953
|
-
return [
|
|
4954
|
-
`Blocked by marathon execution guard: ${toolName} must target the plan or paths under outputRoot "${outputRoot}/".`,
|
|
4955
|
-
`"${normalizedPathArg}" is outside the allowed output root.`
|
|
4956
|
-
].join(" ");
|
|
4957
|
-
}
|
|
4958
|
-
}
|
|
5525
|
+
const writeTargetBlock = interceptProductWriteTarget(
|
|
5526
|
+
toolName,
|
|
5527
|
+
normalizedPathArg,
|
|
5528
|
+
ctx,
|
|
5529
|
+
"execution guard"
|
|
5530
|
+
);
|
|
5531
|
+
if (writeTargetBlock) return writeTargetBlock;
|
|
4959
5532
|
}
|
|
4960
5533
|
return void 0;
|
|
4961
5534
|
},
|
|
@@ -5188,13 +5761,163 @@ function buildCandidateBlock(state) {
|
|
|
5188
5761
|
...state.bestCandidateReason ? [`Why: ${state.bestCandidateReason}`] : []
|
|
5189
5762
|
].join("\n");
|
|
5190
5763
|
}
|
|
5191
|
-
var
|
|
5764
|
+
var builtinHooksRegistered = false;
|
|
5765
|
+
function ensureDefaultWorkflowHooks() {
|
|
5766
|
+
if (builtinHooksRegistered) return;
|
|
5767
|
+
builtinHooksRegistered = true;
|
|
5768
|
+
registerBuiltinWorkflowHook("builtin:classify-task-variant", {
|
|
5769
|
+
kind: "classify",
|
|
5770
|
+
fn: classifyVariant
|
|
5771
|
+
});
|
|
5772
|
+
registerBuiltinWorkflowHook("builtin:repo-bootstrap-discovery", {
|
|
5773
|
+
kind: "bootstrap",
|
|
5774
|
+
fn: generateBootstrapContext
|
|
5775
|
+
});
|
|
5776
|
+
registerBuiltinWorkflowHook("builtin:best-candidate-block", {
|
|
5777
|
+
kind: "candidateBlock",
|
|
5778
|
+
fn: buildCandidateBlock
|
|
5779
|
+
});
|
|
5780
|
+
registerBuiltinWorkflowHook("builtin:research-instructions", {
|
|
5781
|
+
kind: "instructions",
|
|
5782
|
+
fn: researchPhase.buildInstructions
|
|
5783
|
+
});
|
|
5784
|
+
registerBuiltinWorkflowHook("builtin:research-tool-guidance", {
|
|
5785
|
+
kind: "toolGuidance",
|
|
5786
|
+
fn: researchPhase.buildToolGuidance
|
|
5787
|
+
});
|
|
5788
|
+
registerBuiltinWorkflowHook("builtin:research-complete", {
|
|
5789
|
+
kind: "completion",
|
|
5790
|
+
fn: researchPhase.isComplete
|
|
5791
|
+
});
|
|
5792
|
+
registerBuiltinWorkflowHook("builtin:research-transition-summary", {
|
|
5793
|
+
kind: "transitionSummary",
|
|
5794
|
+
fn: researchPhase.buildTransitionSummary
|
|
5795
|
+
});
|
|
5796
|
+
registerBuiltinWorkflowHook("builtin:research-guard", {
|
|
5797
|
+
kind: "intercept",
|
|
5798
|
+
fn: researchPhase.interceptToolCall
|
|
5799
|
+
});
|
|
5800
|
+
registerBuiltinWorkflowHook("builtin:research-recovery", {
|
|
5801
|
+
kind: "recovery",
|
|
5802
|
+
fn: researchPhase.buildRecoveryMessage
|
|
5803
|
+
});
|
|
5804
|
+
registerBuiltinWorkflowHook("builtin:research-force-end-turn", {
|
|
5805
|
+
kind: "forceEndTurn",
|
|
5806
|
+
fn: researchPhase.shouldForceEndTurn
|
|
5807
|
+
});
|
|
5808
|
+
registerBuiltinWorkflowHook("builtin:research-accept-completion", {
|
|
5809
|
+
kind: "acceptCompletion",
|
|
5810
|
+
fn: researchPhase.canAcceptCompletion
|
|
5811
|
+
});
|
|
5812
|
+
registerBuiltinWorkflowHook("builtin:planning-instructions", {
|
|
5813
|
+
kind: "instructions",
|
|
5814
|
+
fn: planningPhase.buildInstructions
|
|
5815
|
+
});
|
|
5816
|
+
registerBuiltinWorkflowHook("builtin:planning-tool-guidance", {
|
|
5817
|
+
kind: "toolGuidance",
|
|
5818
|
+
fn: planningPhase.buildToolGuidance
|
|
5819
|
+
});
|
|
5820
|
+
registerBuiltinWorkflowHook("builtin:planning-complete", {
|
|
5821
|
+
kind: "completion",
|
|
5822
|
+
fn: planningPhase.isComplete
|
|
5823
|
+
});
|
|
5824
|
+
registerBuiltinWorkflowHook("builtin:planning-transition-summary", {
|
|
5825
|
+
kind: "transitionSummary",
|
|
5826
|
+
fn: planningPhase.buildTransitionSummary
|
|
5827
|
+
});
|
|
5828
|
+
registerBuiltinWorkflowHook("builtin:planning-guard", {
|
|
5829
|
+
kind: "intercept",
|
|
5830
|
+
fn: planningPhase.interceptToolCall
|
|
5831
|
+
});
|
|
5832
|
+
registerBuiltinWorkflowHook("builtin:planning-recovery", {
|
|
5833
|
+
kind: "recovery",
|
|
5834
|
+
fn: planningPhase.buildRecoveryMessage
|
|
5835
|
+
});
|
|
5836
|
+
registerBuiltinWorkflowHook("builtin:planning-force-end-turn", {
|
|
5837
|
+
kind: "forceEndTurn",
|
|
5838
|
+
fn: planningPhase.shouldForceEndTurn
|
|
5839
|
+
});
|
|
5840
|
+
registerBuiltinWorkflowHook("builtin:execution-instructions", {
|
|
5841
|
+
kind: "instructions",
|
|
5842
|
+
fn: executionPhase.buildInstructions
|
|
5843
|
+
});
|
|
5844
|
+
registerBuiltinWorkflowHook("builtin:execution-tool-guidance", {
|
|
5845
|
+
kind: "toolGuidance",
|
|
5846
|
+
fn: executionPhase.buildToolGuidance
|
|
5847
|
+
});
|
|
5848
|
+
registerBuiltinWorkflowHook("builtin:execution-guard", {
|
|
5849
|
+
kind: "intercept",
|
|
5850
|
+
fn: executionPhase.interceptToolCall
|
|
5851
|
+
});
|
|
5852
|
+
registerBuiltinWorkflowHook("builtin:execution-recovery", {
|
|
5853
|
+
kind: "recovery",
|
|
5854
|
+
fn: executionPhase.buildRecoveryMessage
|
|
5855
|
+
});
|
|
5856
|
+
registerBuiltinWorkflowHook("builtin:execution-force-end-turn", {
|
|
5857
|
+
kind: "forceEndTurn",
|
|
5858
|
+
fn: executionPhase.shouldForceEndTurn
|
|
5859
|
+
});
|
|
5860
|
+
registerBuiltinWorkflowHook("builtin:execution-accept-completion", {
|
|
5861
|
+
kind: "acceptCompletion",
|
|
5862
|
+
fn: executionPhase.canAcceptCompletion
|
|
5863
|
+
});
|
|
5864
|
+
}
|
|
5865
|
+
var defaultWorkflowConfig = {
|
|
5192
5866
|
name: "default",
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5867
|
+
// Empty-session escalation. The counter only counts tool actions, so
|
|
5868
|
+
// narration-only sessions ("I'll create the files now" with no tool calls)
|
|
5869
|
+
// escalate here even though the phase recovery conditions keyed on
|
|
5870
|
+
// hadTextOutput skip them: nudge after the first actionless session, signal
|
|
5871
|
+
// model escalation after the second (a no-op unless the caller configured a
|
|
5872
|
+
// fallback model), and stop as 'stalled' after the third — the same total
|
|
5873
|
+
// session budget as before stallPolicy existed.
|
|
5874
|
+
stallPolicy: { nudgeAfter: 1, escalateModelAfter: 2, stopAfter: 3 },
|
|
5875
|
+
classifyVariant: "builtin:classify-task-variant",
|
|
5876
|
+
bootstrap: "builtin:repo-bootstrap-discovery",
|
|
5877
|
+
candidateBlock: "builtin:best-candidate-block",
|
|
5878
|
+
milestones: [
|
|
5879
|
+
{
|
|
5880
|
+
name: "research",
|
|
5881
|
+
description: "Inspect the repo and identify the correct target file",
|
|
5882
|
+
instructions: "builtin:research-instructions",
|
|
5883
|
+
toolGuidance: "builtin:research-tool-guidance",
|
|
5884
|
+
completionCriteria: { type: "builtin:research-complete" },
|
|
5885
|
+
intercept: "builtin:research-guard",
|
|
5886
|
+
transitionSummary: "builtin:research-transition-summary",
|
|
5887
|
+
recovery: "builtin:research-recovery",
|
|
5888
|
+
forceEndTurn: "builtin:research-force-end-turn",
|
|
5889
|
+
canAcceptCompletion: "builtin:research-accept-completion"
|
|
5890
|
+
},
|
|
5891
|
+
{
|
|
5892
|
+
name: "planning",
|
|
5893
|
+
description: "Write the implementation plan before editing product files",
|
|
5894
|
+
instructions: "builtin:planning-instructions",
|
|
5895
|
+
toolGuidance: "builtin:planning-tool-guidance",
|
|
5896
|
+
completionCriteria: { type: "builtin:planning-complete" },
|
|
5897
|
+
intercept: "builtin:planning-guard",
|
|
5898
|
+
transitionSummary: "builtin:planning-transition-summary",
|
|
5899
|
+
recovery: "builtin:planning-recovery",
|
|
5900
|
+
forceEndTurn: "builtin:planning-force-end-turn"
|
|
5901
|
+
// canAcceptCompletion intentionally absent: the hand-written planning
|
|
5902
|
+
// phase never defined it, and the SDK accepts completion when the slot
|
|
5903
|
+
// is undefined. Keep parity.
|
|
5904
|
+
},
|
|
5905
|
+
{
|
|
5906
|
+
name: "execution",
|
|
5907
|
+
description: "Execute the plan by editing target files",
|
|
5908
|
+
instructions: "builtin:execution-instructions",
|
|
5909
|
+
toolGuidance: "builtin:execution-tool-guidance",
|
|
5910
|
+
// Execution never auto-advances; completion is agent-driven via TASK_COMPLETE
|
|
5911
|
+
completionCriteria: { type: "never" },
|
|
5912
|
+
intercept: "builtin:execution-guard",
|
|
5913
|
+
recovery: "builtin:execution-recovery",
|
|
5914
|
+
forceEndTurn: "builtin:execution-force-end-turn",
|
|
5915
|
+
canAcceptCompletion: "builtin:execution-accept-completion"
|
|
5916
|
+
}
|
|
5917
|
+
]
|
|
5197
5918
|
};
|
|
5919
|
+
ensureDefaultWorkflowHooks();
|
|
5920
|
+
var defaultWorkflow = compileWorkflowConfig(defaultWorkflowConfig);
|
|
5198
5921
|
|
|
5199
5922
|
// src/workflows/deploy-workflow.ts
|
|
5200
5923
|
var scaffoldPhase = {
|
|
@@ -5606,6 +6329,34 @@ var gameWorkflow = {
|
|
|
5606
6329
|
}
|
|
5607
6330
|
};
|
|
5608
6331
|
|
|
6332
|
+
// src/workflows/stall-policy.ts
|
|
6333
|
+
var DEFAULT_STALL_STOP_AFTER = 3;
|
|
6334
|
+
function isPositiveInteger(value) {
|
|
6335
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
6336
|
+
}
|
|
6337
|
+
function resolveStallStopAfter(policy) {
|
|
6338
|
+
return isPositiveInteger(policy?.stopAfter) ? policy.stopAfter : DEFAULT_STALL_STOP_AFTER;
|
|
6339
|
+
}
|
|
6340
|
+
function shouldRequestModelEscalation(policy, consecutiveEmptySessions) {
|
|
6341
|
+
const threshold = policy?.escalateModelAfter;
|
|
6342
|
+
if (!isPositiveInteger(threshold)) return false;
|
|
6343
|
+
return consecutiveEmptySessions === threshold;
|
|
6344
|
+
}
|
|
6345
|
+
function shouldInjectEmptySessionNudge(policy, consecutiveEmptySessions) {
|
|
6346
|
+
const threshold = policy?.nudgeAfter;
|
|
6347
|
+
if (!isPositiveInteger(threshold)) return false;
|
|
6348
|
+
return consecutiveEmptySessions >= threshold;
|
|
6349
|
+
}
|
|
6350
|
+
function buildEmptySessionNudge(consecutiveEmptySessions) {
|
|
6351
|
+
const sessionPhrase = consecutiveEmptySessions === 1 ? "Your previous session ended" : `Your previous ${consecutiveEmptySessions} sessions ended`;
|
|
6352
|
+
return [
|
|
6353
|
+
"Recovery instruction:",
|
|
6354
|
+
`${sessionPhrase} without a single tool call. Describing what you plan to do does nothing \u2014 only tool calls make progress.`,
|
|
6355
|
+
"Your next response MUST include at least one tool call (for example write_file, edit_file, read_file, or run_check) that advances the task.",
|
|
6356
|
+
"If a previous tool call was blocked, re-read the block message and satisfy its requirement instead of ending the turn."
|
|
6357
|
+
].join("\n");
|
|
6358
|
+
}
|
|
6359
|
+
|
|
5609
6360
|
// src/endpoints.ts
|
|
5610
6361
|
var FlowsEndpoint = class {
|
|
5611
6362
|
constructor(client) {
|
|
@@ -5768,6 +6519,19 @@ var RecordsEndpoint = class {
|
|
|
5768
6519
|
async getResults(id, params) {
|
|
5769
6520
|
return this.client.get(`/records/${id}/results`, params);
|
|
5770
6521
|
}
|
|
6522
|
+
/**
|
|
6523
|
+
* Get unified step-level execution results for a record, with filtering and
|
|
6524
|
+
* pagination.
|
|
6525
|
+
*/
|
|
6526
|
+
async getStepResults(id, params) {
|
|
6527
|
+
return this.client.get(`/records/${id}/step-results`, params);
|
|
6528
|
+
}
|
|
6529
|
+
/**
|
|
6530
|
+
* Get the aggregated cost breakdown (by model) for a record's executions.
|
|
6531
|
+
*/
|
|
6532
|
+
async getCosts(id) {
|
|
6533
|
+
return this.client.get(`/records/${id}/costs`);
|
|
6534
|
+
}
|
|
5771
6535
|
/**
|
|
5772
6536
|
* Delete a specific result for a record
|
|
5773
6537
|
*/
|
|
@@ -6096,15 +6860,15 @@ var DispatchEndpoint = class {
|
|
|
6096
6860
|
* Attach approved runtime tools to a prompt step in a redispatch request.
|
|
6097
6861
|
* Returns a new request object and does not mutate the original.
|
|
6098
6862
|
*/
|
|
6099
|
-
attachApprovedRuntimeTools(
|
|
6100
|
-
return attachRuntimeToolsToDispatchRequest(
|
|
6863
|
+
attachApprovedRuntimeTools(request3, runtimeTools, options) {
|
|
6864
|
+
return attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options);
|
|
6101
6865
|
}
|
|
6102
6866
|
/**
|
|
6103
6867
|
* Validate a generated runtime tool proposal and attach it to the redispatch
|
|
6104
6868
|
* request if approved, in one call.
|
|
6105
6869
|
*/
|
|
6106
|
-
applyGeneratedRuntimeToolProposal(
|
|
6107
|
-
return applyGeneratedRuntimeToolProposalToDispatchRequest(
|
|
6870
|
+
applyGeneratedRuntimeToolProposal(request3, proposal, options) {
|
|
6871
|
+
return applyGeneratedRuntimeToolProposalToDispatchRequest(request3, proposal, options);
|
|
6108
6872
|
}
|
|
6109
6873
|
};
|
|
6110
6874
|
var ChatEndpoint = class {
|
|
@@ -6656,8 +7420,8 @@ var GENERATED_RUNTIME_TOOL_PROPOSAL_SCHEMA = {
|
|
|
6656
7420
|
},
|
|
6657
7421
|
required: ["name", "description", "toolType", "parametersSchema", "config"]
|
|
6658
7422
|
};
|
|
6659
|
-
function appendRuntimeToolsToAgentRequest(
|
|
6660
|
-
const existing =
|
|
7423
|
+
function appendRuntimeToolsToAgentRequest(request3, runtimeTools) {
|
|
7424
|
+
const existing = request3.tools?.runtimeTools || [];
|
|
6661
7425
|
const existingNames = new Set(existing.map((tool) => tool.name));
|
|
6662
7426
|
const converted = runtimeTools.filter((tool) => !existingNames.has(tool.name)).map((tool) => ({
|
|
6663
7427
|
name: tool.name,
|
|
@@ -6667,9 +7431,9 @@ function appendRuntimeToolsToAgentRequest(request2, runtimeTools) {
|
|
|
6667
7431
|
...tool.config ? { config: tool.config } : {}
|
|
6668
7432
|
}));
|
|
6669
7433
|
return {
|
|
6670
|
-
...
|
|
7434
|
+
...request3,
|
|
6671
7435
|
tools: {
|
|
6672
|
-
...
|
|
7436
|
+
...request3.tools,
|
|
6673
7437
|
runtimeTools: [...existing, ...converted]
|
|
6674
7438
|
}
|
|
6675
7439
|
};
|
|
@@ -6745,21 +7509,21 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
6745
7509
|
* Attach approved runtime tools to an agent execute request.
|
|
6746
7510
|
* Returns a new request object and does not mutate the original.
|
|
6747
7511
|
*/
|
|
6748
|
-
attachApprovedRuntimeTools(
|
|
6749
|
-
return appendRuntimeToolsToAgentRequest(
|
|
7512
|
+
attachApprovedRuntimeTools(request3, runtimeTools) {
|
|
7513
|
+
return appendRuntimeToolsToAgentRequest(request3, runtimeTools);
|
|
6750
7514
|
}
|
|
6751
7515
|
/**
|
|
6752
7516
|
* Validate a generated runtime tool proposal and append it to an agent execute
|
|
6753
7517
|
* request if approved, in one call.
|
|
6754
7518
|
*/
|
|
6755
|
-
applyGeneratedRuntimeToolProposal(
|
|
7519
|
+
applyGeneratedRuntimeToolProposal(request3, proposal, options) {
|
|
6756
7520
|
const decision = evaluateGeneratedRuntimeToolProposal(proposal, options);
|
|
6757
7521
|
if (!decision.approved || !decision.tool) {
|
|
6758
|
-
return { decision, request:
|
|
7522
|
+
return { decision, request: request3 };
|
|
6759
7523
|
}
|
|
6760
7524
|
return {
|
|
6761
7525
|
decision,
|
|
6762
|
-
request: appendRuntimeToolsToAgentRequest(
|
|
7526
|
+
request: appendRuntimeToolsToAgentRequest(request3, [decision.tool])
|
|
6763
7527
|
};
|
|
6764
7528
|
}
|
|
6765
7529
|
/**
|
|
@@ -7518,11 +8282,13 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
7518
8282
|
* setting. This never mutates persisted marathon history; masking/offloading
|
|
7519
8283
|
* is a send-time view over the full-fidelity ledger/history.
|
|
7520
8284
|
*/
|
|
7521
|
-
deriveToolContextMessages(messages, taskName, mode, window) {
|
|
8285
|
+
deriveToolContextMessages(messages, taskName, mode, window, offloadRecorder) {
|
|
7522
8286
|
if (mode === "full-inline") return [...messages];
|
|
7523
8287
|
const maskMessage = (msg) => ({
|
|
7524
8288
|
...msg,
|
|
7525
|
-
toolResults: (msg.toolResults ?? []).map(
|
|
8289
|
+
toolResults: (msg.toolResults ?? []).map(
|
|
8290
|
+
(tr) => this.compactOneResult(tr, taskName, mode, offloadRecorder)
|
|
8291
|
+
)
|
|
7526
8292
|
});
|
|
7527
8293
|
const view = [...messages];
|
|
7528
8294
|
if (window === "session") {
|
|
@@ -7556,12 +8322,18 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
7556
8322
|
}
|
|
7557
8323
|
return view;
|
|
7558
8324
|
}
|
|
7559
|
-
compactOneResult(tr, taskName, mode) {
|
|
8325
|
+
compactOneResult(tr, taskName, mode, offloadRecorder) {
|
|
7560
8326
|
if (typeof tr.result === "string" && tr.result.startsWith("[")) return tr;
|
|
7561
8327
|
if (mode === "hot-tail") {
|
|
7562
8328
|
return {
|
|
7563
8329
|
...tr,
|
|
7564
|
-
result: this.offloadToolResult(
|
|
8330
|
+
result: this.offloadToolResult(
|
|
8331
|
+
taskName,
|
|
8332
|
+
tr.toolCallId,
|
|
8333
|
+
tr.toolName,
|
|
8334
|
+
tr.result,
|
|
8335
|
+
offloadRecorder
|
|
8336
|
+
)
|
|
7565
8337
|
};
|
|
7566
8338
|
}
|
|
7567
8339
|
return { ...tr, result: `[Output from ${tr.toolName} masked \u2014 re-run the tool if needed]` };
|
|
@@ -7577,9 +8349,16 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
7577
8349
|
return taskName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
7578
8350
|
}
|
|
7579
8351
|
// chars
|
|
7580
|
-
offloadToolResult(taskName, toolCallId, toolName, result) {
|
|
8352
|
+
offloadToolResult(taskName, toolCallId, toolName, result, offloadRecorder) {
|
|
7581
8353
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
7582
8354
|
if (resultStr.length <= this.TOOL_OUTPUT_INLINE_THRESHOLD) return result;
|
|
8355
|
+
if (offloadRecorder) {
|
|
8356
|
+
try {
|
|
8357
|
+
const recorded = offloadRecorder({ toolCallId, toolName, content: resultStr });
|
|
8358
|
+
if (recorded?.reference) return recorded.reference;
|
|
8359
|
+
} catch {
|
|
8360
|
+
}
|
|
8361
|
+
}
|
|
7583
8362
|
let fs;
|
|
7584
8363
|
try {
|
|
7585
8364
|
const dynamicRequire = (0, eval)('typeof require !== "undefined" ? require : undefined');
|
|
@@ -8152,8 +8931,11 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
8152
8931
|
}
|
|
8153
8932
|
buildStuckTurnRecoveryMessage(state, workflow) {
|
|
8154
8933
|
const currentPhase = workflow.phases.find((p) => p.name === state.workflowPhase);
|
|
8155
|
-
|
|
8156
|
-
|
|
8934
|
+
const phaseMessage = currentPhase?.buildRecoveryMessage?.(state);
|
|
8935
|
+
if (phaseMessage) return phaseMessage;
|
|
8936
|
+
const emptySessions = state.consecutiveEmptySessions || 0;
|
|
8937
|
+
if (shouldInjectEmptySessionNudge(workflow.stallPolicy, emptySessions)) {
|
|
8938
|
+
return buildEmptySessionNudge(emptySessions);
|
|
8157
8939
|
}
|
|
8158
8940
|
return void 0;
|
|
8159
8941
|
}
|
|
@@ -8279,6 +9061,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
8279
9061
|
state.originalMessage = options.message;
|
|
8280
9062
|
}
|
|
8281
9063
|
const queuedSteeringMessages = options.getQueuedUserMessages?.() ?? [];
|
|
9064
|
+
if (queuedSteeringMessages.length > 0) {
|
|
9065
|
+
state.consecutiveEmptySessions = 0;
|
|
9066
|
+
state.stallEscalationRequested = void 0;
|
|
9067
|
+
}
|
|
8282
9068
|
const preparedSession = await this.prepareSessionContext(
|
|
8283
9069
|
options.message,
|
|
8284
9070
|
state,
|
|
@@ -8299,7 +9085,8 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
8299
9085
|
onContextCompaction: options.onContextCompaction,
|
|
8300
9086
|
onContextNotice: options.onContextNotice,
|
|
8301
9087
|
toolContextMode: options.toolContextMode || "hot-tail",
|
|
8302
|
-
toolWindow: options.toolWindow ?? "session"
|
|
9088
|
+
toolWindow: options.toolWindow ?? "session",
|
|
9089
|
+
offloadRecorder: options.offloadRecorder
|
|
8303
9090
|
},
|
|
8304
9091
|
queuedSteeringMessages
|
|
8305
9092
|
);
|
|
@@ -8519,11 +9306,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
8519
9306
|
} else {
|
|
8520
9307
|
state.lastCompletionRejectionReason = void 0;
|
|
8521
9308
|
}
|
|
8522
|
-
const sessionHadActions = sessionTrace.wroteFiles || sessionTrace.readFiles || sessionTrace.discoveryPerformed || sessionTrace.verificationAttempted;
|
|
9309
|
+
const sessionHadActions = sessionTrace.wroteFiles || sessionTrace.readFiles || sessionTrace.discoveryPerformed || sessionTrace.verificationAttempted || options.hasQueuedUserMessages?.() === true;
|
|
8523
9310
|
if (sessionHadActions) {
|
|
8524
9311
|
state.consecutiveEmptySessions = 0;
|
|
9312
|
+
state.stallEscalationRequested = void 0;
|
|
8525
9313
|
} else {
|
|
8526
9314
|
state.consecutiveEmptySessions = (state.consecutiveEmptySessions || 0) + 1;
|
|
9315
|
+
if (shouldRequestModelEscalation(workflow.stallPolicy, state.consecutiveEmptySessions)) {
|
|
9316
|
+
state.stallEscalationRequested = true;
|
|
9317
|
+
}
|
|
8527
9318
|
}
|
|
8528
9319
|
if (sessionResult.stopReason === "complete" && !detectedTaskCompletion) {
|
|
8529
9320
|
const currentPhase = workflow.phases.find((p) => p.name === state.workflowPhase);
|
|
@@ -8552,7 +9343,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
|
|
|
8552
9343
|
state.status = "budget_exceeded";
|
|
8553
9344
|
} else if (acceptedTaskCompletion) {
|
|
8554
9345
|
state.status = "complete";
|
|
8555
|
-
} else if ((state.consecutiveEmptySessions || 0) >=
|
|
9346
|
+
} else if ((state.consecutiveEmptySessions || 0) >= resolveStallStopAfter(workflow.stallPolicy)) {
|
|
8556
9347
|
state.status = "stalled";
|
|
8557
9348
|
} else if (maxCost && state.totalCost >= maxCost) {
|
|
8558
9349
|
state.status = "budget_exceeded";
|
|
@@ -9155,7 +9946,8 @@ Do NOT redo any of the above work.`
|
|
|
9155
9946
|
sourceReplayHistoryMessages,
|
|
9156
9947
|
state.taskName,
|
|
9157
9948
|
compactionOptions?.toolContextMode || "hot-tail",
|
|
9158
|
-
compactionOptions?.toolWindow ?? "session"
|
|
9949
|
+
compactionOptions?.toolWindow ?? "session",
|
|
9950
|
+
compactionOptions?.offloadRecorder
|
|
9159
9951
|
);
|
|
9160
9952
|
const continuationGuardrail = this.buildContinuationGuardrail(state);
|
|
9161
9953
|
const defaultContinueMessage = "Continue the task. Review your prior work above and proceed with any remaining work. If everything is already complete, respond with TASK_COMPLETE.";
|
|
@@ -9318,7 +10110,8 @@ Do NOT redo any of the above work.`
|
|
|
9318
10110
|
sourceHistoryMessages,
|
|
9319
10111
|
state.taskName,
|
|
9320
10112
|
compactionOptions?.toolContextMode || "hot-tail",
|
|
9321
|
-
compactionOptions?.toolWindow ?? "session"
|
|
10113
|
+
compactionOptions?.toolWindow ?? "session",
|
|
10114
|
+
compactionOptions?.offloadRecorder
|
|
9322
10115
|
);
|
|
9323
10116
|
const historyArtifactReferences = this.extractArtifactReferencesFromMessages(historyMessages);
|
|
9324
10117
|
const summaryText = this.generateCompactSummary(
|
|
@@ -9965,7 +10758,7 @@ var RuntypeClient2 = class {
|
|
|
9965
10758
|
clearApiKey() {
|
|
9966
10759
|
delete this.headers.Authorization;
|
|
9967
10760
|
}
|
|
9968
|
-
async runWithLocalTools(
|
|
10761
|
+
async runWithLocalTools(request3, localTools, arg3, arg4) {
|
|
9969
10762
|
const isOptionsObject = (val) => typeof val === "object" && val !== null && "scope" in val;
|
|
9970
10763
|
const callbacks = isOptionsObject(arg3) ? void 0 : arg3;
|
|
9971
10764
|
const options = (isOptionsObject(arg3) ? arg3 : arg4) ?? {};
|
|
@@ -9979,12 +10772,12 @@ var RuntypeClient2 = class {
|
|
|
9979
10772
|
...entry.pageOrigin ? { pageOrigin: entry.pageOrigin } : {}
|
|
9980
10773
|
})) : [];
|
|
9981
10774
|
const modifiedRequest = {
|
|
9982
|
-
...
|
|
10775
|
+
...request3,
|
|
9983
10776
|
...derivedClientTools.length > 0 ? {
|
|
9984
|
-
clientTools: [...
|
|
10777
|
+
clientTools: [...request3.clientTools ?? [], ...derivedClientTools]
|
|
9985
10778
|
} : {},
|
|
9986
10779
|
options: {
|
|
9987
|
-
...
|
|
10780
|
+
...request3.options || {},
|
|
9988
10781
|
streamResponse: isStreaming
|
|
9989
10782
|
}
|
|
9990
10783
|
};
|
|
@@ -10422,20 +11215,20 @@ var BatchBuilder = class {
|
|
|
10422
11215
|
if (!this.recordType) {
|
|
10423
11216
|
throw new Error("BatchBuilder: recordType is required. Call .forRecordType(type) first.");
|
|
10424
11217
|
}
|
|
10425
|
-
const
|
|
11218
|
+
const request3 = {
|
|
10426
11219
|
flowId: this.flowId,
|
|
10427
11220
|
recordType: this.recordType
|
|
10428
11221
|
};
|
|
10429
11222
|
if (Object.keys(this.batchOptions).length > 0) {
|
|
10430
|
-
|
|
11223
|
+
request3.options = this.batchOptions;
|
|
10431
11224
|
}
|
|
10432
11225
|
if (this.filterConfig) {
|
|
10433
|
-
|
|
11226
|
+
request3.filter = this.filterConfig;
|
|
10434
11227
|
}
|
|
10435
11228
|
if (this.limitConfig !== void 0) {
|
|
10436
|
-
|
|
11229
|
+
request3.limit = this.limitConfig;
|
|
10437
11230
|
}
|
|
10438
|
-
return
|
|
11231
|
+
return request3;
|
|
10439
11232
|
}
|
|
10440
11233
|
/**
|
|
10441
11234
|
* Execute the batch operation
|
|
@@ -10592,32 +11385,32 @@ var EvalBuilder = class {
|
|
|
10592
11385
|
"EvalBuilder: records are required. Call .forRecordType(type) or .withRecords([...]) first."
|
|
10593
11386
|
);
|
|
10594
11387
|
}
|
|
10595
|
-
const
|
|
11388
|
+
const request3 = {};
|
|
10596
11389
|
if (this.flowId) {
|
|
10597
|
-
|
|
11390
|
+
request3.flowId = this.flowId;
|
|
10598
11391
|
} else if (this.virtualFlow) {
|
|
10599
|
-
|
|
11392
|
+
request3.flow = this.virtualFlow;
|
|
10600
11393
|
}
|
|
10601
11394
|
if (this.recordType) {
|
|
10602
|
-
|
|
11395
|
+
request3.recordType = this.recordType;
|
|
10603
11396
|
} else if (this.inlineRecords) {
|
|
10604
|
-
|
|
11397
|
+
request3.records = this.inlineRecords;
|
|
10605
11398
|
}
|
|
10606
11399
|
if (this.modelOverrides) {
|
|
10607
|
-
|
|
11400
|
+
request3.modelOverrides = this.modelOverrides;
|
|
10608
11401
|
} else if (this.modelConfigs) {
|
|
10609
|
-
|
|
11402
|
+
request3.modelConfigs = this.modelConfigs;
|
|
10610
11403
|
}
|
|
10611
11404
|
if (Object.keys(this.evalOptions).length > 0) {
|
|
10612
|
-
|
|
11405
|
+
request3.options = this.evalOptions;
|
|
10613
11406
|
}
|
|
10614
11407
|
if (this.filterConfig) {
|
|
10615
|
-
|
|
11408
|
+
request3.filter = this.filterConfig;
|
|
10616
11409
|
}
|
|
10617
11410
|
if (this.limitConfig !== void 0) {
|
|
10618
|
-
|
|
11411
|
+
request3.limit = this.limitConfig;
|
|
10619
11412
|
}
|
|
10620
|
-
return
|
|
11413
|
+
return request3;
|
|
10621
11414
|
}
|
|
10622
11415
|
/**
|
|
10623
11416
|
* Execute the evaluation
|
|
@@ -11102,6 +11895,8 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11102
11895
|
ClientTokensEndpoint,
|
|
11103
11896
|
ContextTemplatesEndpoint,
|
|
11104
11897
|
ConversationsEndpoint,
|
|
11898
|
+
DEFAULT_RECOVERY_AFTER_EMPTY_SESSIONS,
|
|
11899
|
+
DEFAULT_STALL_STOP_AFTER,
|
|
11105
11900
|
DispatchEndpoint,
|
|
11106
11901
|
EvalBuilder,
|
|
11107
11902
|
EvalEndpoint,
|
|
@@ -11135,36 +11930,57 @@ var STEP_TYPE_TO_METHOD = {
|
|
|
11135
11930
|
SkillProposalsNamespace,
|
|
11136
11931
|
SkillsNamespace,
|
|
11137
11932
|
SurfacesEndpoint,
|
|
11933
|
+
ToolDriftError,
|
|
11934
|
+
ToolEnsureConflictError,
|
|
11138
11935
|
ToolsEndpoint,
|
|
11936
|
+
ToolsNamespace,
|
|
11139
11937
|
UsersEndpoint,
|
|
11140
11938
|
applyGeneratedRuntimeToolProposalToDispatchRequest,
|
|
11141
11939
|
attachRuntimeToolsToDispatchRequest,
|
|
11940
|
+
buildEmptySessionNudge,
|
|
11142
11941
|
buildGeneratedRuntimeToolGateOutput,
|
|
11143
11942
|
buildLedgerOffloadReference,
|
|
11943
|
+
buildPolicyGuidance,
|
|
11144
11944
|
buildSendViewOffloadMarker,
|
|
11945
|
+
compileWorkflowConfig,
|
|
11145
11946
|
computeAgentContentHash,
|
|
11146
11947
|
computeFlowContentHash,
|
|
11948
|
+
computeToolContentHash,
|
|
11147
11949
|
createClient,
|
|
11148
11950
|
createExternalTool,
|
|
11149
11951
|
defaultWorkflow,
|
|
11952
|
+
defaultWorkflowConfig,
|
|
11150
11953
|
defineAgent,
|
|
11151
11954
|
defineFlow,
|
|
11955
|
+
definePlaybook,
|
|
11956
|
+
defineTool,
|
|
11152
11957
|
deployWorkflow,
|
|
11958
|
+
ensureDefaultWorkflowHooks,
|
|
11153
11959
|
evaluateGeneratedRuntimeToolProposal,
|
|
11154
11960
|
extractDeclaredToolResultChars,
|
|
11155
11961
|
gameWorkflow,
|
|
11156
11962
|
getDefaultPlanPath,
|
|
11157
11963
|
getLikelySupportingCandidatePaths,
|
|
11964
|
+
interpolateWorkflowTemplate,
|
|
11158
11965
|
isDiscoveryToolName,
|
|
11159
11966
|
isMarathonArtifactPath,
|
|
11160
11967
|
isPreservationSensitiveTask,
|
|
11968
|
+
isWorkflowHookRef,
|
|
11969
|
+
listWorkflowHooks,
|
|
11161
11970
|
normalizeAgentDefinition,
|
|
11162
11971
|
normalizeCandidatePath,
|
|
11972
|
+
normalizeToolDefinition,
|
|
11163
11973
|
parseFinalBuffer,
|
|
11164
11974
|
parseLedgerArtifactRelativePath,
|
|
11165
11975
|
parseOffloadedOutputId,
|
|
11166
11976
|
parseSSEChunk,
|
|
11167
11977
|
processStream,
|
|
11978
|
+
registerWorkflowHook,
|
|
11979
|
+
resolveStallStopAfter,
|
|
11980
|
+
resolveWorkflowHook,
|
|
11168
11981
|
sanitizeTaskSlug,
|
|
11169
|
-
|
|
11982
|
+
shouldInjectEmptySessionNudge,
|
|
11983
|
+
shouldRequestModelEscalation,
|
|
11984
|
+
streamEvents,
|
|
11985
|
+
unregisterWorkflowHook
|
|
11170
11986
|
});
|