@hachej/boring-agent 0.1.79 → 0.1.81
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/{chunk-X4WT3TPU.js → chunk-24VL7G32.js} +9 -2
- package/dist/{chunk-LCEBDU6G.js → chunk-2AVRA73A.js} +13 -7
- package/dist/{chunk-P23XFC4W.js → chunk-3RSYCAHO.js} +1 -1
- package/dist/{chunk-RFHSFIHF.js → chunk-I7JNWIYM.js} +585 -96
- package/dist/{chunk-Q42DWR3T.js → chunk-S2HYQYJP.js} +3 -1
- package/dist/{chunk-YVON2BHN.js → chunk-YV6D7GCQ.js} +10 -0
- package/dist/core/index.d.ts +5 -4
- package/dist/core/index.js +2 -2
- package/dist/{createHarness-XHMR3QN3.js → createHarness-4VZW2XEV.js} +2 -2
- package/dist/front/index.d.ts +1 -1
- package/dist/front/index.js +2 -2
- package/dist/{harness-DD0zj704.d.ts → harness-If4r1n-K.d.ts} +8 -2
- package/dist/{piChatEvent-D0yuLiJh.d.ts → piChatEvent-DtqYMcID.d.ts} +23 -14
- package/dist/server/index.d.ts +103 -19
- package/dist/server/index.js +10 -6
- package/dist/server/worker/index.js +6 -6
- package/dist/shared/index.d.ts +285 -25
- package/dist/shared/index.js +173 -3
- package/dist/{workspaceAgentDispatcher-D3ZEBsH1.d.ts → workspaceAgentDispatcher-BbNd3y7u.d.ts} +6 -3
- package/docs/ERROR_CODES.md +3 -0
- package/package.json +2 -2
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AgentDefinitionValidationError,
|
|
3
|
+
AgentDeploymentValidationError,
|
|
4
|
+
OpaqueRefSchema,
|
|
5
|
+
Sha256DigestSchema,
|
|
3
6
|
createAgentAssetDigest,
|
|
4
7
|
createAgentDefinitionDigest,
|
|
8
|
+
createAgentDeploymentDigest,
|
|
5
9
|
validateAgentDefinition,
|
|
10
|
+
validateAgentDeployment,
|
|
6
11
|
validateTool
|
|
7
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-S2HYQYJP.js";
|
|
8
13
|
import {
|
|
9
14
|
createAgentRuntimeBridge
|
|
10
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2AVRA73A.js";
|
|
11
16
|
import {
|
|
12
17
|
sessionStreamPath
|
|
13
18
|
} from "./chunk-WSQ5QNIY.js";
|
|
@@ -22,7 +27,7 @@ import {
|
|
|
22
27
|
StopReceiptSchema,
|
|
23
28
|
extractToolUiMetadata,
|
|
24
29
|
sanitizeToolUiMetadata2 as sanitizeToolUiMetadata
|
|
25
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-3RSYCAHO.js";
|
|
26
31
|
import {
|
|
27
32
|
createLogger,
|
|
28
33
|
createPiCodingAgentHarness,
|
|
@@ -33,14 +38,15 @@ import {
|
|
|
33
38
|
registerConfiguredModelProviders,
|
|
34
39
|
setEnvDefault,
|
|
35
40
|
withPiHarnessDefaults
|
|
36
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-24VL7G32.js";
|
|
37
42
|
import {
|
|
38
43
|
safeCapture
|
|
39
44
|
} from "./chunk-AQBXNPMD.js";
|
|
40
45
|
import {
|
|
41
46
|
AgentDefinitionErrorCode,
|
|
47
|
+
AgentDeploymentErrorCode,
|
|
42
48
|
ErrorCode
|
|
43
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-YV6D7GCQ.js";
|
|
44
50
|
|
|
45
51
|
// src/server/sandbox/direct/createDirectSandbox.ts
|
|
46
52
|
import { spawn } from "child_process";
|
|
@@ -8446,11 +8452,12 @@ function createAgentRuntimeBridge2(config, options = {}) {
|
|
|
8446
8452
|
}
|
|
8447
8453
|
return createAgentRuntimeBridge({
|
|
8448
8454
|
runtimeFactory: () => createRuntime(config, options),
|
|
8455
|
+
readiness: config.readiness,
|
|
8449
8456
|
readinessRequirements: config.readinessRequirements
|
|
8450
8457
|
});
|
|
8451
8458
|
}
|
|
8452
8459
|
async function createRuntime(config, options) {
|
|
8453
|
-
const harnessFactory = config.harnessFactory ?? (await import("./createHarness-
|
|
8460
|
+
const harnessFactory = config.harnessFactory ?? (await import("./createHarness-4VZW2XEV.js")).createPiCodingAgentHarness;
|
|
8454
8461
|
const harnessInput = {
|
|
8455
8462
|
tools: config.tools ?? [],
|
|
8456
8463
|
cwd: config.workdir ?? DEFAULT_WORKDIR,
|
|
@@ -8702,15 +8709,155 @@ async function compileAgentDirectory(directory) {
|
|
|
8702
8709
|
return Object.freeze({ definition, definitionDigest, assets });
|
|
8703
8710
|
}
|
|
8704
8711
|
|
|
8712
|
+
// src/server/agentDefinition/resolveAgentDeployment.ts
|
|
8713
|
+
import { z } from "zod";
|
|
8714
|
+
var AuthorizedAgentDeploymentBindingSchema = z.object({
|
|
8715
|
+
workspaceId: OpaqueRefSchema,
|
|
8716
|
+
defaultDeploymentId: OpaqueRefSchema,
|
|
8717
|
+
workspaceCompositionDigest: Sha256DigestSchema
|
|
8718
|
+
});
|
|
8719
|
+
var RESOLVED_AGENT_DIGEST_DOMAIN = "boring-agent/resolved-agent:v1";
|
|
8720
|
+
var ResolvedAgentDigestInputSchema = z.object({
|
|
8721
|
+
workspaceId: OpaqueRefSchema,
|
|
8722
|
+
defaultDeploymentId: OpaqueRefSchema,
|
|
8723
|
+
workspaceCompositionDigest: Sha256DigestSchema,
|
|
8724
|
+
definitionDigest: Sha256DigestSchema,
|
|
8725
|
+
deploymentDigest: Sha256DigestSchema
|
|
8726
|
+
}).strict();
|
|
8727
|
+
async function createResolvedAgentDigest(input) {
|
|
8728
|
+
const parsed = ResolvedAgentDigestInputSchema.safeParse(input);
|
|
8729
|
+
if (!parsed.success) {
|
|
8730
|
+
const field = parsed.error.issues[0]?.path[0];
|
|
8731
|
+
const digestField = typeof field === "string" ? field : "workspaceId";
|
|
8732
|
+
throw invalidDeployment(digestField, `${digestField} is invalid`);
|
|
8733
|
+
}
|
|
8734
|
+
return createAgentAssetDigest(JSON.stringify({ domain: RESOLVED_AGENT_DIGEST_DOMAIN, ...parsed.data }));
|
|
8735
|
+
}
|
|
8736
|
+
function invalidDefinition(field, message) {
|
|
8737
|
+
return new AgentDefinitionValidationError({
|
|
8738
|
+
code: AgentDefinitionErrorCode.enum.AGENT_DEFINITION_INVALID,
|
|
8739
|
+
field,
|
|
8740
|
+
message
|
|
8741
|
+
});
|
|
8742
|
+
}
|
|
8743
|
+
function invalidDeployment(field, message) {
|
|
8744
|
+
return new AgentDeploymentValidationError({
|
|
8745
|
+
code: AgentDeploymentErrorCode.enum.AGENT_DEPLOYMENT_INVALID,
|
|
8746
|
+
field,
|
|
8747
|
+
message
|
|
8748
|
+
});
|
|
8749
|
+
}
|
|
8750
|
+
function parseBinding(raw) {
|
|
8751
|
+
const parsed = AuthorizedAgentDeploymentBindingSchema.safeParse(raw);
|
|
8752
|
+
if (parsed.success) return parsed.data;
|
|
8753
|
+
const issue = parsed.error.issues[0];
|
|
8754
|
+
const field = issue.path[0];
|
|
8755
|
+
const bindingField = typeof field === "string" ? field : "workspaceId";
|
|
8756
|
+
throw invalidDeployment(bindingField, `${bindingField} ${issue.message}`);
|
|
8757
|
+
}
|
|
8758
|
+
function assertEqual(actual, expected, field) {
|
|
8759
|
+
if (actual !== expected) {
|
|
8760
|
+
throw invalidDeployment(field, `${field} does not match the compiled agent bundle`);
|
|
8761
|
+
}
|
|
8762
|
+
}
|
|
8763
|
+
async function resolveAgentDeployment(bundle, deployment, authorizedBinding) {
|
|
8764
|
+
const binding = parseBinding(authorizedBinding);
|
|
8765
|
+
const definitionDigest = await createAgentDefinitionDigest({
|
|
8766
|
+
definition: bundle.definition,
|
|
8767
|
+
assets: bundle.assets
|
|
8768
|
+
});
|
|
8769
|
+
if (definitionDigest !== bundle.definitionDigest) {
|
|
8770
|
+
throw invalidDefinition(
|
|
8771
|
+
"definitionDigest",
|
|
8772
|
+
"definitionDigest does not match the compiled agent bundle"
|
|
8773
|
+
);
|
|
8774
|
+
}
|
|
8775
|
+
const validatedDeployment = validateAgentDeployment(deployment);
|
|
8776
|
+
if (!validatedDeployment.valid) {
|
|
8777
|
+
throw new AgentDeploymentValidationError(validatedDeployment.issues[0]);
|
|
8778
|
+
}
|
|
8779
|
+
const deploymentSnapshot = validatedDeployment.value;
|
|
8780
|
+
const deploymentDigest = await createAgentDeploymentDigest(deploymentSnapshot);
|
|
8781
|
+
assertEqual(
|
|
8782
|
+
deploymentSnapshot.definition.definitionId,
|
|
8783
|
+
bundle.definition.definitionId,
|
|
8784
|
+
"definition.definitionId"
|
|
8785
|
+
);
|
|
8786
|
+
assertEqual(
|
|
8787
|
+
deploymentSnapshot.definition.version,
|
|
8788
|
+
bundle.definition.version,
|
|
8789
|
+
"definition.version"
|
|
8790
|
+
);
|
|
8791
|
+
assertEqual(deploymentSnapshot.definition.digest, definitionDigest, "definition.digest");
|
|
8792
|
+
if (deploymentSnapshot.agentId !== "default") {
|
|
8793
|
+
throw invalidDeployment("agentId", "agentId must be default in schema version 1");
|
|
8794
|
+
}
|
|
8795
|
+
if (binding.defaultDeploymentId !== deploymentSnapshot.deploymentId) {
|
|
8796
|
+
throw invalidDeployment(
|
|
8797
|
+
"defaultDeploymentId",
|
|
8798
|
+
"defaultDeploymentId does not match the resolved deployment"
|
|
8799
|
+
);
|
|
8800
|
+
}
|
|
8801
|
+
const instructions = bundle.assets.find(
|
|
8802
|
+
(asset) => asset.path === bundle.definition.instructionsRef
|
|
8803
|
+
);
|
|
8804
|
+
if (instructions === void 0) {
|
|
8805
|
+
throw invalidDefinition(
|
|
8806
|
+
"instructionsRef",
|
|
8807
|
+
"instructionsRef must name an included verified asset"
|
|
8808
|
+
);
|
|
8809
|
+
}
|
|
8810
|
+
const resolvedDigest = await createResolvedAgentDigest({
|
|
8811
|
+
workspaceId: binding.workspaceId,
|
|
8812
|
+
defaultDeploymentId: binding.defaultDeploymentId,
|
|
8813
|
+
workspaceCompositionDigest: binding.workspaceCompositionDigest,
|
|
8814
|
+
definitionDigest,
|
|
8815
|
+
deploymentDigest
|
|
8816
|
+
});
|
|
8817
|
+
const workspace = Object.freeze({
|
|
8818
|
+
workspaceId: binding.workspaceId,
|
|
8819
|
+
defaultDeploymentId: binding.defaultDeploymentId,
|
|
8820
|
+
compositionDigest: binding.workspaceCompositionDigest
|
|
8821
|
+
});
|
|
8822
|
+
const resolvedDeployment = Object.freeze({
|
|
8823
|
+
deploymentId: deploymentSnapshot.deploymentId,
|
|
8824
|
+
version: deploymentSnapshot.version,
|
|
8825
|
+
agentId: deploymentSnapshot.agentId,
|
|
8826
|
+
digest: deploymentDigest
|
|
8827
|
+
});
|
|
8828
|
+
const definition = Object.freeze({
|
|
8829
|
+
definitionId: bundle.definition.definitionId,
|
|
8830
|
+
version: bundle.definition.version,
|
|
8831
|
+
digest: definitionDigest,
|
|
8832
|
+
instructionsRef: bundle.definition.instructionsRef
|
|
8833
|
+
});
|
|
8834
|
+
const resolvedInstructions = Object.freeze({
|
|
8835
|
+
ref: bundle.definition.instructionsRef,
|
|
8836
|
+
content: instructions.content
|
|
8837
|
+
});
|
|
8838
|
+
return Object.freeze({
|
|
8839
|
+
workspace,
|
|
8840
|
+
deployment: resolvedDeployment,
|
|
8841
|
+
definition,
|
|
8842
|
+
instructions: resolvedInstructions,
|
|
8843
|
+
resolvedDigest
|
|
8844
|
+
});
|
|
8845
|
+
}
|
|
8846
|
+
|
|
8705
8847
|
// src/server/mcp/managedAgentDelegate.ts
|
|
8706
|
-
import { randomUUID } from "crypto";
|
|
8848
|
+
import { createHash as createHash6, randomUUID } from "crypto";
|
|
8707
8849
|
var MANAGED_AGENT_MCP_ORIGIN_SURFACE = "mcp-managed-agent";
|
|
8708
|
-
var MANAGED_AGENT_MCP_DELIVERY_RULE = "M1
|
|
8709
|
-
var
|
|
8710
|
-
var
|
|
8850
|
+
var MANAGED_AGENT_MCP_DELIVERY_RULE = "M1 DELIVERY v0: delegate_task returns bounded final assistant text and at most one complete authorized inline Markdown artifact; no artifact paths, truncation, or share-link delivery.";
|
|
8851
|
+
var MAX_FINAL_ASSISTANT_TEXT_BYTES = 96 * 1024;
|
|
8852
|
+
var MAX_ARTIFACT_BYTES = 256 * 1024;
|
|
8853
|
+
var MAX_SERIALIZED_RESULT_BYTES = 384 * 1024;
|
|
8854
|
+
var MARKDOWN_MEDIA_TYPE = "text/markdown";
|
|
8855
|
+
var DEFAULT_MAX_BRIEF_BYTES = 32 * 1024;
|
|
8711
8856
|
var DEFAULT_TERMINAL_RETENTION_MS = 15 * 6e4;
|
|
8712
8857
|
var DEFAULT_MAX_DELEGATIONS = 100;
|
|
8713
8858
|
var MAX_RETAINED_PROGRESS = 100;
|
|
8859
|
+
var utf8Encoder = new TextEncoder();
|
|
8860
|
+
var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
8714
8861
|
var ManagedAgentMcpError = class extends Error {
|
|
8715
8862
|
code;
|
|
8716
8863
|
constructor(code, message) {
|
|
@@ -8724,8 +8871,8 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8724
8871
|
this.options = options;
|
|
8725
8872
|
this.createDelegationId = options.createDelegationId ?? randomUUID;
|
|
8726
8873
|
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
8727
|
-
this.
|
|
8728
|
-
this.
|
|
8874
|
+
this.maxBriefBytes = options.maxBriefBytes ?? DEFAULT_MAX_BRIEF_BYTES;
|
|
8875
|
+
this.maxBriefChars = options.maxBriefChars;
|
|
8729
8876
|
this.terminalRetentionMs = Math.max(0, options.terminalRetentionMs ?? DEFAULT_TERMINAL_RETENTION_MS);
|
|
8730
8877
|
this.maxDelegations = Math.max(1, Math.floor(options.maxDelegations ?? DEFAULT_MAX_DELEGATIONS));
|
|
8731
8878
|
this.redactionCanaries = options.redactionCanaries ?? [];
|
|
@@ -8734,8 +8881,8 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8734
8881
|
delegations = /* @__PURE__ */ new Map();
|
|
8735
8882
|
createDelegationId;
|
|
8736
8883
|
now;
|
|
8884
|
+
maxBriefBytes;
|
|
8737
8885
|
maxBriefChars;
|
|
8738
|
-
maxInlineArtifactContentChars;
|
|
8739
8886
|
terminalRetentionMs;
|
|
8740
8887
|
maxDelegations;
|
|
8741
8888
|
redactionCanaries;
|
|
@@ -8755,19 +8902,13 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8755
8902
|
await input.onDelegationCreated?.(this.getStatus(delegationId, ctx));
|
|
8756
8903
|
this.assertNotAborted(input.signal);
|
|
8757
8904
|
const actor = await this.resolveActor(brief, ctx, request);
|
|
8758
|
-
const
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
ctx,
|
|
8762
|
-
originSurface: MANAGED_AGENT_MCP_ORIGIN_SURFACE
|
|
8763
|
-
});
|
|
8764
|
-
if (input.signal?.aborted) {
|
|
8765
|
-
await this.stopDelegatedSession(receipt.sessionId, ctx);
|
|
8766
|
-
throw new ManagedAgentMcpError(ErrorCode.enum.ABORTED, "delegation was cancelled");
|
|
8767
|
-
}
|
|
8905
|
+
const bound = await this.resolveRunnerWorkspace(brief, ctx, request, actor);
|
|
8906
|
+
this.assertNotAborted(input.signal);
|
|
8907
|
+
let activeSessionId;
|
|
8768
8908
|
let abortStopPromise;
|
|
8769
8909
|
const abortListener = () => {
|
|
8770
|
-
|
|
8910
|
+
if (!activeSessionId) return;
|
|
8911
|
+
abortStopPromise ??= this.stopDelegatedSession(bound.runner, activeSessionId, ctx);
|
|
8771
8912
|
};
|
|
8772
8913
|
input.signal?.addEventListener("abort", abortListener, { once: true });
|
|
8773
8914
|
await this.pushProgress(record, "agent-started", "Agent session accepted for delegated task.", input.onProgress);
|
|
@@ -8775,11 +8916,21 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8775
8916
|
let terminal = false;
|
|
8776
8917
|
let terminalStatus;
|
|
8777
8918
|
try {
|
|
8778
|
-
for await (const event of
|
|
8919
|
+
for await (const event of bound.runner.run({
|
|
8920
|
+
brief,
|
|
8921
|
+
ctx,
|
|
8922
|
+
request,
|
|
8923
|
+
actor,
|
|
8924
|
+
signal: input.signal,
|
|
8925
|
+
onSessionStarted: (sessionId) => {
|
|
8926
|
+
activeSessionId = sessionId;
|
|
8927
|
+
}
|
|
8928
|
+
})) {
|
|
8779
8929
|
if (input.signal?.aborted) {
|
|
8780
8930
|
await abortStopPromise;
|
|
8781
8931
|
throw new ManagedAgentMcpError(ErrorCode.enum.ABORTED, "delegation was cancelled");
|
|
8782
8932
|
}
|
|
8933
|
+
activeSessionId = event.sessionId;
|
|
8783
8934
|
events.push(event);
|
|
8784
8935
|
await this.observeEvent(record, event, input.onProgress);
|
|
8785
8936
|
if (isTerminalAgentEvent(event)) {
|
|
@@ -8801,20 +8952,21 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8801
8952
|
if (terminalStatus !== "ok") {
|
|
8802
8953
|
throw terminalError(terminalStatus, events);
|
|
8803
8954
|
}
|
|
8804
|
-
const finalAssistantText = extractFinalAssistantText(events);
|
|
8955
|
+
const finalAssistantText = this.validateFinalAssistantText(extractFinalAssistantText(events));
|
|
8805
8956
|
const artifacts = await this.collectArtifacts({
|
|
8806
8957
|
delegationId,
|
|
8807
|
-
sessionId:
|
|
8958
|
+
sessionId: activeSessionId ?? "",
|
|
8808
8959
|
ctx,
|
|
8960
|
+
request,
|
|
8809
8961
|
finalAssistantText,
|
|
8810
8962
|
events
|
|
8811
|
-
});
|
|
8963
|
+
}, bound.workspace);
|
|
8812
8964
|
const result = {
|
|
8813
8965
|
delegationId,
|
|
8814
8966
|
status: "completed",
|
|
8815
8967
|
finalAssistantText,
|
|
8816
|
-
|
|
8817
|
-
|
|
8968
|
+
deliveryRule: MANAGED_AGENT_MCP_DELIVERY_RULE,
|
|
8969
|
+
...artifacts[0] ? { artifact: artifacts[0] } : {}
|
|
8818
8970
|
};
|
|
8819
8971
|
this.assertPublicPayloadSafe(result);
|
|
8820
8972
|
record.result = result;
|
|
@@ -8896,9 +9048,12 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8896
9048
|
if (typeof value !== "string") throw new ManagedAgentMcpError(ErrorCode.enum.TOOL_INVALID_INPUT, "brief must be a string");
|
|
8897
9049
|
const brief = value.trim();
|
|
8898
9050
|
if (!brief) throw new ManagedAgentMcpError(ErrorCode.enum.TOOL_INVALID_INPUT, "brief is required");
|
|
8899
|
-
if (brief.length > this.maxBriefChars) {
|
|
9051
|
+
if (this.maxBriefChars !== void 0 && brief.length > this.maxBriefChars) {
|
|
8900
9052
|
throw new ManagedAgentMcpError(ErrorCode.enum.TOOL_INVALID_INPUT, `brief must be ${this.maxBriefChars} characters or fewer`);
|
|
8901
9053
|
}
|
|
9054
|
+
if (utf8ByteLength(brief) > this.maxBriefBytes) {
|
|
9055
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.TOOL_INVALID_INPUT, `brief must be ${this.maxBriefBytes} UTF-8 bytes or fewer`);
|
|
9056
|
+
}
|
|
8902
9057
|
return brief;
|
|
8903
9058
|
}
|
|
8904
9059
|
async resolveSessionCtx(brief, request) {
|
|
@@ -8911,11 +9066,56 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8911
9066
|
}
|
|
8912
9067
|
return { workspaceId: ctx.workspaceId, userId: ctx.userId };
|
|
8913
9068
|
}
|
|
9069
|
+
async resolveWorkspace(brief, ctx, request) {
|
|
9070
|
+
const resolveWorkspace = this.options.resolveWorkspace;
|
|
9071
|
+
if (!resolveWorkspace) {
|
|
9072
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.CONFIG_INVALID, "MCP delegate requires a host-resolved Workspace");
|
|
9073
|
+
}
|
|
9074
|
+
const workspace = await resolveWorkspace({ brief, ctx, request });
|
|
9075
|
+
if (!workspace || typeof workspace.stat !== "function" || typeof workspace.readFile !== "function") {
|
|
9076
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.CONFIG_INVALID, "MCP delegate requires a host-resolved Workspace");
|
|
9077
|
+
}
|
|
9078
|
+
return workspace;
|
|
9079
|
+
}
|
|
9080
|
+
async resolveRunnerWorkspace(brief, ctx, request, actor) {
|
|
9081
|
+
const resolved = this.options.resolveRunnerWorkspace ? await this.options.resolveRunnerWorkspace({ brief, ctx, request, actor }) : {
|
|
9082
|
+
runner: this.createAgentDelegateRunner(),
|
|
9083
|
+
workspace: await this.resolveWorkspace(brief, ctx, request)
|
|
9084
|
+
};
|
|
9085
|
+
if (!resolved || !resolved.runner || typeof resolved.runner.run !== "function") {
|
|
9086
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.CONFIG_INVALID, "MCP delegate requires a host-resolved runner");
|
|
9087
|
+
}
|
|
9088
|
+
if (!resolved.workspace || typeof resolved.workspace.stat !== "function" || typeof resolved.workspace.readFile !== "function") {
|
|
9089
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.CONFIG_INVALID, "MCP delegate requires a host-resolved Workspace");
|
|
9090
|
+
}
|
|
9091
|
+
return resolved;
|
|
9092
|
+
}
|
|
9093
|
+
createAgentDelegateRunner() {
|
|
9094
|
+
const agent = this.options.agent;
|
|
9095
|
+
if (!agent) {
|
|
9096
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.CONFIG_INVALID, "MCP delegate requires a host-resolved runner");
|
|
9097
|
+
}
|
|
9098
|
+
return {
|
|
9099
|
+
async *run(input) {
|
|
9100
|
+
const receipt = await agent.start({
|
|
9101
|
+
content: input.brief,
|
|
9102
|
+
actor: input.actor,
|
|
9103
|
+
ctx: input.ctx,
|
|
9104
|
+
originSurface: MANAGED_AGENT_MCP_ORIGIN_SURFACE
|
|
9105
|
+
});
|
|
9106
|
+
input.onSessionStarted?.(receipt.sessionId);
|
|
9107
|
+
yield* agent.stream(receipt.sessionId, { startIndex: receipt.startIndex, ctx: input.ctx });
|
|
9108
|
+
},
|
|
9109
|
+
async stop(sessionId, ctx) {
|
|
9110
|
+
await agent.stop(sessionId, ctx);
|
|
9111
|
+
}
|
|
9112
|
+
};
|
|
9113
|
+
}
|
|
8914
9114
|
assertNotAborted(signal) {
|
|
8915
9115
|
if (signal?.aborted) throw new ManagedAgentMcpError(ErrorCode.enum.ABORTED, "delegation was cancelled");
|
|
8916
9116
|
}
|
|
8917
|
-
async stopDelegatedSession(sessionId, ctx) {
|
|
8918
|
-
await
|
|
9117
|
+
async stopDelegatedSession(runner, sessionId, ctx) {
|
|
9118
|
+
await Promise.resolve(runner.stop?.(sessionId, ctx)).catch(() => void 0);
|
|
8919
9119
|
}
|
|
8920
9120
|
async resolveActor(brief, ctx, request) {
|
|
8921
9121
|
const actor = await this.options.resolveActor?.({ brief, ctx, request });
|
|
@@ -8943,13 +9143,40 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8943
9143
|
} catch {
|
|
8944
9144
|
}
|
|
8945
9145
|
}
|
|
8946
|
-
|
|
9146
|
+
validateFinalAssistantText(value) {
|
|
9147
|
+
const byteSize = utf8ByteLength(value);
|
|
9148
|
+
if (byteSize > MAX_FINAL_ASSISTANT_TEXT_BYTES) {
|
|
9149
|
+
throw new ManagedAgentMcpError(
|
|
9150
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_TOO_LARGE,
|
|
9151
|
+
`final assistant text must be ${MAX_FINAL_ASSISTANT_TEXT_BYTES} bytes or fewer`
|
|
9152
|
+
);
|
|
9153
|
+
}
|
|
9154
|
+
if (looksLikeSinglePath(value)) {
|
|
9155
|
+
throw new ManagedAgentMcpError(
|
|
9156
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID,
|
|
9157
|
+
"final assistant text must not be only an artifact path"
|
|
9158
|
+
);
|
|
9159
|
+
}
|
|
9160
|
+
return value;
|
|
9161
|
+
}
|
|
9162
|
+
async collectArtifacts(input, workspace) {
|
|
8947
9163
|
const supplied = await this.options.collectArtifacts?.(input);
|
|
8948
|
-
const
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
9164
|
+
const rawCandidates = supplied ?? extractArtifactRefs(input.events);
|
|
9165
|
+
if (!Array.isArray(rawCandidates)) {
|
|
9166
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact references must be an array");
|
|
9167
|
+
}
|
|
9168
|
+
const candidates = rawCandidates.map((artifact2) => normalizeArtifactCandidate(artifact2));
|
|
9169
|
+
this.assertPublicPayloadSafe(candidates);
|
|
9170
|
+
if (candidates.length === 0) return [];
|
|
9171
|
+
if (candidates.length > 1) {
|
|
9172
|
+
throw new ManagedAgentMcpError(
|
|
9173
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID,
|
|
9174
|
+
"MCP delegate delivery supports at most one artifact"
|
|
9175
|
+
);
|
|
9176
|
+
}
|
|
9177
|
+
const artifact = await resolveMarkdownArtifact(candidates[0], workspace);
|
|
9178
|
+
this.assertPublicPayloadSafe(artifact);
|
|
9179
|
+
return [artifact];
|
|
8953
9180
|
}
|
|
8954
9181
|
toSafeError(error) {
|
|
8955
9182
|
if (error instanceof ManagedAgentMcpError) {
|
|
@@ -8962,6 +9189,12 @@ var ManagedAgentMcpDelegateController = class {
|
|
|
8962
9189
|
}
|
|
8963
9190
|
assertPublicPayloadSafe(payload) {
|
|
8964
9191
|
const serialized = JSON.stringify(payload);
|
|
9192
|
+
if (utf8ByteLength(serialized) > MAX_SERIALIZED_RESULT_BYTES) {
|
|
9193
|
+
throw new ManagedAgentMcpError(
|
|
9194
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_TOO_LARGE,
|
|
9195
|
+
`MCP delegate result must be ${MAX_SERIALIZED_RESULT_BYTES} bytes or fewer`
|
|
9196
|
+
);
|
|
9197
|
+
}
|
|
8965
9198
|
if (this.containsSecret(serialized)) {
|
|
8966
9199
|
throw new ManagedAgentMcpError(ErrorCode.enum.INTERNAL_ERROR, "MCP delegate payload failed secret redaction guard");
|
|
8967
9200
|
}
|
|
@@ -9052,39 +9285,178 @@ function extractArtifactRefs(events) {
|
|
|
9052
9285
|
}
|
|
9053
9286
|
return artifacts;
|
|
9054
9287
|
}
|
|
9055
|
-
function
|
|
9056
|
-
|
|
9057
|
-
|
|
9288
|
+
function normalizeArtifactCandidate(artifact) {
|
|
9289
|
+
if (!artifact || typeof artifact !== "object") {
|
|
9290
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact reference is invalid");
|
|
9291
|
+
}
|
|
9292
|
+
const record = artifact;
|
|
9293
|
+
if (record.content !== void 0) {
|
|
9294
|
+
throw new ManagedAgentMcpError(
|
|
9295
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID,
|
|
9296
|
+
"artifact content must be resolved through the authorized workspace"
|
|
9297
|
+
);
|
|
9298
|
+
}
|
|
9299
|
+
if (record.truncated !== void 0) {
|
|
9300
|
+
throw new ManagedAgentMcpError(
|
|
9301
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID,
|
|
9302
|
+
"artifact content must be complete and untruncated"
|
|
9303
|
+
);
|
|
9304
|
+
}
|
|
9305
|
+
const path4 = normalizeArtifactPath(record.path);
|
|
9306
|
+
const mediaType = optionalNonEmptyString(record.mediaType);
|
|
9307
|
+
if (mediaType !== void 0 && mediaType.toLowerCase().split(";", 1)[0]?.trim() !== MARKDOWN_MEDIA_TYPE) {
|
|
9308
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact must be Markdown");
|
|
9309
|
+
}
|
|
9310
|
+
if (mediaType === void 0 && !isMarkdownPath(path4)) {
|
|
9311
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact must be Markdown");
|
|
9312
|
+
}
|
|
9313
|
+
const candidate = {
|
|
9058
9314
|
path: path4,
|
|
9059
|
-
mediaType:
|
|
9060
|
-
title: optionalNonEmptyString(artifact.title)
|
|
9315
|
+
mediaType: MARKDOWN_MEDIA_TYPE
|
|
9061
9316
|
};
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
}
|
|
9066
|
-
if (artifact.content.length <= maxInlineArtifactContentChars) {
|
|
9067
|
-
normalized.content = artifact.content;
|
|
9068
|
-
} else {
|
|
9069
|
-
normalized.truncated = true;
|
|
9070
|
-
}
|
|
9071
|
-
}
|
|
9072
|
-
if (artifact.truncated === true) normalized.truncated = true;
|
|
9073
|
-
return normalized;
|
|
9317
|
+
const title = optionalNonEmptyString(record.title);
|
|
9318
|
+
if (title !== void 0) candidate.title = title;
|
|
9319
|
+
return candidate;
|
|
9074
9320
|
}
|
|
9075
9321
|
function normalizeArtifactPath(path4) {
|
|
9076
|
-
if (typeof path4 !== "string") throw new ManagedAgentMcpError(ErrorCode.enum.
|
|
9322
|
+
if (typeof path4 !== "string") throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path must be a string");
|
|
9077
9323
|
const trimmed = path4.trim();
|
|
9078
|
-
if (!trimmed) throw new ManagedAgentMcpError(ErrorCode.enum.
|
|
9079
|
-
if (trimmed.includes("\0")) throw new ManagedAgentMcpError(ErrorCode.enum.
|
|
9080
|
-
|
|
9081
|
-
|
|
9324
|
+
if (!trimmed) throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path is required");
|
|
9325
|
+
if (trimmed.includes("\0")) throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path is invalid");
|
|
9326
|
+
const decoded = safeDecodeArtifactPath(trimmed);
|
|
9327
|
+
const traversalCandidate = decoded.replace(/\\/g, "/");
|
|
9328
|
+
if (trimmed.startsWith("/") || traversalCandidate.startsWith("/") || /^[A-Za-z]:[\\/]/.test(trimmed) || /^[A-Za-z]:[\\/]/.test(traversalCandidate) || /^[A-Za-z][A-Za-z0-9+.-]*:/.test(trimmed)) {
|
|
9329
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path must be workspace-relative");
|
|
9330
|
+
}
|
|
9331
|
+
const parts = traversalCandidate.split("/");
|
|
9332
|
+
if (traversalCandidate.startsWith("~") || traversalCandidate.startsWith("$") || /[\r\n]/.test(traversalCandidate) || parts.some((part) => part === ".." || part.startsWith(".."))) {
|
|
9333
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path must stay within the workspace");
|
|
9334
|
+
}
|
|
9335
|
+
const normalized = parts.filter((part) => part && part !== ".").join("/");
|
|
9336
|
+
if (!normalized) throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path is required");
|
|
9337
|
+
return normalized;
|
|
9338
|
+
}
|
|
9339
|
+
async function resolveMarkdownArtifact(candidate, workspace) {
|
|
9340
|
+
const { content, bytes, byteSize } = await readStableArtifact(candidate.path, workspace);
|
|
9341
|
+
validateMarkdownContent(content);
|
|
9342
|
+
const artifact = {
|
|
9343
|
+
content,
|
|
9344
|
+
sha256: sha256(bytes),
|
|
9345
|
+
byteSize,
|
|
9346
|
+
mediaType: MARKDOWN_MEDIA_TYPE,
|
|
9347
|
+
...candidate.title ? { title: candidate.title } : {}
|
|
9348
|
+
};
|
|
9349
|
+
return artifact;
|
|
9350
|
+
}
|
|
9351
|
+
async function readStableArtifact(path4, workspace) {
|
|
9352
|
+
const before = await statArtifact(workspace, path4);
|
|
9353
|
+
assertArtifactStat(before);
|
|
9354
|
+
if (before.size > MAX_ARTIFACT_BYTES) {
|
|
9355
|
+
throw new ManagedAgentMcpError(
|
|
9356
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_TOO_LARGE,
|
|
9357
|
+
`artifact must be ${MAX_ARTIFACT_BYTES} bytes or fewer`
|
|
9358
|
+
);
|
|
9082
9359
|
}
|
|
9083
|
-
const
|
|
9084
|
-
|
|
9085
|
-
|
|
9360
|
+
const read = await readArtifactContent(workspace, path4);
|
|
9361
|
+
const after = await statArtifact(workspace, path4);
|
|
9362
|
+
assertArtifactStat(after);
|
|
9363
|
+
if (!sameStat(before, after) || read.byteSize !== before.size) {
|
|
9364
|
+
throw new ManagedAgentMcpError(
|
|
9365
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_UNAVAILABLE,
|
|
9366
|
+
"artifact changed while it was being read"
|
|
9367
|
+
);
|
|
9086
9368
|
}
|
|
9087
|
-
|
|
9369
|
+
if (read.byteSize > MAX_ARTIFACT_BYTES) {
|
|
9370
|
+
throw new ManagedAgentMcpError(
|
|
9371
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_TOO_LARGE,
|
|
9372
|
+
`artifact must be ${MAX_ARTIFACT_BYTES} bytes or fewer`
|
|
9373
|
+
);
|
|
9374
|
+
}
|
|
9375
|
+
return read;
|
|
9376
|
+
}
|
|
9377
|
+
async function statArtifact(workspace, path4) {
|
|
9378
|
+
try {
|
|
9379
|
+
return await workspace.stat(path4);
|
|
9380
|
+
} catch (error) {
|
|
9381
|
+
throw artifactReadError(error);
|
|
9382
|
+
}
|
|
9383
|
+
}
|
|
9384
|
+
function assertArtifactStat(stat13) {
|
|
9385
|
+
if (stat13.kind !== "file") {
|
|
9386
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact must be a file");
|
|
9387
|
+
}
|
|
9388
|
+
if (!Number.isFinite(stat13.size) || stat13.size < 0) {
|
|
9389
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact size is invalid");
|
|
9390
|
+
}
|
|
9391
|
+
}
|
|
9392
|
+
async function readArtifactContent(workspace, path4) {
|
|
9393
|
+
try {
|
|
9394
|
+
if (!workspace.readBinaryFile) {
|
|
9395
|
+
throw new ManagedAgentMcpError(
|
|
9396
|
+
ErrorCode.enum.MCP_AGENT_ARTIFACT_UNAVAILABLE,
|
|
9397
|
+
"artifact bytes are unavailable through the authorized workspace"
|
|
9398
|
+
);
|
|
9399
|
+
}
|
|
9400
|
+
const bytes = await workspace.readBinaryFile(path4);
|
|
9401
|
+
const content = decodeUtf82(bytes);
|
|
9402
|
+
return { content, bytes, byteSize: bytes.byteLength };
|
|
9403
|
+
} catch (error) {
|
|
9404
|
+
if (error instanceof ManagedAgentMcpError) throw error;
|
|
9405
|
+
throw artifactReadError(error);
|
|
9406
|
+
}
|
|
9407
|
+
}
|
|
9408
|
+
function artifactReadError(error) {
|
|
9409
|
+
const code = error?.code;
|
|
9410
|
+
const reason = error?.reason;
|
|
9411
|
+
if (code === ErrorCode.enum.PATH_ESCAPE || code === ErrorCode.enum.PATH_ABSOLUTE || code === ErrorCode.enum.PATH_NULL_BYTE || code === ErrorCode.enum.PATH_SYMLINK_ESCAPE || reason === "path-escape" || reason === "absolute-path" || reason === "null-byte" || reason === "symlink-escape") {
|
|
9412
|
+
return new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact path is invalid");
|
|
9413
|
+
}
|
|
9414
|
+
return new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_UNAVAILABLE, "artifact is unavailable");
|
|
9415
|
+
}
|
|
9416
|
+
function decodeUtf82(bytes) {
|
|
9417
|
+
try {
|
|
9418
|
+
return strictUtf8Decoder.decode(bytes);
|
|
9419
|
+
} catch {
|
|
9420
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact must be well-formed UTF-8");
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9423
|
+
function validateMarkdownContent(content) {
|
|
9424
|
+
if (!content.trim()) {
|
|
9425
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact Markdown must not be empty");
|
|
9426
|
+
}
|
|
9427
|
+
for (let index = 0; index < content.length; index += 1) {
|
|
9428
|
+
const code = content.charCodeAt(index);
|
|
9429
|
+
if (code === 0 || code < 32 && code !== 9 && code !== 10 && code !== 13) {
|
|
9430
|
+
throw new ManagedAgentMcpError(ErrorCode.enum.MCP_AGENT_ARTIFACT_INVALID, "artifact must be text Markdown");
|
|
9431
|
+
}
|
|
9432
|
+
}
|
|
9433
|
+
}
|
|
9434
|
+
function sameStat(left, right) {
|
|
9435
|
+
return left.kind === right.kind && left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
9436
|
+
}
|
|
9437
|
+
function sha256(bytes) {
|
|
9438
|
+
return `sha256:${createHash6("sha256").update(bytes).digest("hex")}`;
|
|
9439
|
+
}
|
|
9440
|
+
function safeDecodeArtifactPath(path4) {
|
|
9441
|
+
try {
|
|
9442
|
+
return decodeURIComponent(path4);
|
|
9443
|
+
} catch {
|
|
9444
|
+
return path4;
|
|
9445
|
+
}
|
|
9446
|
+
}
|
|
9447
|
+
function utf8ByteLength(value) {
|
|
9448
|
+
return utf8Encoder.encode(value).byteLength;
|
|
9449
|
+
}
|
|
9450
|
+
function isMarkdownPath(path4) {
|
|
9451
|
+
return /\.(md|markdown)$/i.test(path4);
|
|
9452
|
+
}
|
|
9453
|
+
function looksLikeSinglePath(value) {
|
|
9454
|
+
const trimmed = value.trim();
|
|
9455
|
+
if (!trimmed || /\s/.test(trimmed)) return false;
|
|
9456
|
+
if (!isMarkdownPath(trimmed)) return false;
|
|
9457
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(trimmed)) return true;
|
|
9458
|
+
if (trimmed.startsWith("/") || /^[A-Za-z]:[\\/]/.test(trimmed)) return true;
|
|
9459
|
+
return trimmed.includes("/") || trimmed.includes("\\");
|
|
9088
9460
|
}
|
|
9089
9461
|
function optionalNonEmptyString(value) {
|
|
9090
9462
|
if (value === void 0) return void 0;
|
|
@@ -9099,18 +9471,21 @@ function sameSessionCtx(a, b) {
|
|
|
9099
9471
|
// src/server/mcp/managedAgentMcpServer.ts
|
|
9100
9472
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9101
9473
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
9102
|
-
import { z } from "zod";
|
|
9103
|
-
var
|
|
9474
|
+
import { z as z2 } from "zod";
|
|
9475
|
+
var DEFAULT_MAX_BRIEF_SCHEMA_CHARS = 32 * 1024;
|
|
9104
9476
|
var delegateTaskStatusInputSchema = {
|
|
9105
|
-
delegationId:
|
|
9477
|
+
delegationId: z2.string().min(1)
|
|
9106
9478
|
};
|
|
9107
|
-
function createManagedAgentMcpServer(options
|
|
9479
|
+
function createManagedAgentMcpServer(options) {
|
|
9480
|
+
return createManagedAgentMcpServerWithController(options, createManagedAgentMcpDelegateController(options));
|
|
9481
|
+
}
|
|
9482
|
+
function createManagedAgentMcpServerWithController(options, controller) {
|
|
9108
9483
|
const server = new McpServer({
|
|
9109
9484
|
name: options.name ?? "boring-managed-agent",
|
|
9110
9485
|
version: options.version ?? "0.0.0"
|
|
9111
9486
|
});
|
|
9112
9487
|
const registerTool = server.registerTool.bind(server);
|
|
9113
|
-
const delegateTaskInputSchema = createDelegateTaskInputSchema(options.maxBriefChars ??
|
|
9488
|
+
const delegateTaskInputSchema = createDelegateTaskInputSchema(options.maxBriefChars ?? DEFAULT_MAX_BRIEF_SCHEMA_CHARS);
|
|
9114
9489
|
registerTool(
|
|
9115
9490
|
"delegate_task",
|
|
9116
9491
|
{
|
|
@@ -9186,7 +9561,7 @@ function createManagedAgentMcpServer(options, controller = createManagedAgentMcp
|
|
|
9186
9561
|
function createManagedAgentMcpHttpHandler(options) {
|
|
9187
9562
|
const controller = options.controller ?? createManagedAgentMcpDelegateController(options);
|
|
9188
9563
|
return async (req, res, parsedBody) => {
|
|
9189
|
-
const server =
|
|
9564
|
+
const server = createManagedAgentMcpServerWithController(options, controller);
|
|
9190
9565
|
const transport = new StreamableHTTPServerTransport({
|
|
9191
9566
|
sessionIdGenerator: void 0,
|
|
9192
9567
|
enableJsonResponse: false
|
|
@@ -9207,7 +9582,7 @@ function requestContextFromExtra(extra) {
|
|
|
9207
9582
|
}
|
|
9208
9583
|
function createDelegateTaskInputSchema(maxBriefChars) {
|
|
9209
9584
|
return {
|
|
9210
|
-
brief:
|
|
9585
|
+
brief: z2.string().min(1).max(maxBriefChars)
|
|
9211
9586
|
};
|
|
9212
9587
|
}
|
|
9213
9588
|
async function sendMcpProgress(extra, progress, message) {
|
|
@@ -11363,7 +11738,9 @@ function pathForWorkspaceEditor(workspaceRoot, filePath) {
|
|
|
11363
11738
|
function skillsRoutes(app, opts, done) {
|
|
11364
11739
|
const cached = /* @__PURE__ */ new Map();
|
|
11365
11740
|
async function resolveSkillsForRequest(request, refresh = false) {
|
|
11366
|
-
const
|
|
11741
|
+
const workspace = opts.getWorkspace ? await opts.getWorkspace(request) : opts.workspace;
|
|
11742
|
+
if (!workspace) throw new Error("skills route requires workspace or getWorkspace");
|
|
11743
|
+
const workspaceRoot = workspace.root;
|
|
11367
11744
|
const additionalSkillPaths = opts.getAdditionalSkillPaths ? await opts.getAdditionalSkillPaths(request) : opts.additionalSkillPaths;
|
|
11368
11745
|
const piPackages = opts.getPiPackages ? await opts.getPiPackages(request) : opts.piPackages;
|
|
11369
11746
|
const noSkills = (opts.getNoSkills ? await opts.getNoSkills(request) : opts.noSkills) ?? withPiHarnessDefaults().noSkills;
|
|
@@ -11420,26 +11797,26 @@ function skillsRoutes(app, opts, done) {
|
|
|
11420
11797
|
|
|
11421
11798
|
// src/server/http/routes/piChat.ts
|
|
11422
11799
|
import { PassThrough } from "stream";
|
|
11423
|
-
import { z as
|
|
11800
|
+
import { z as z3 } from "zod";
|
|
11424
11801
|
var DEFAULT_WORKSPACE_ID2 = "default";
|
|
11425
11802
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 25e3;
|
|
11426
11803
|
var DEFAULT_SESSION_LIST_LIMIT = 50;
|
|
11427
11804
|
var MAX_SESSION_LIST_LIMIT = 100;
|
|
11428
11805
|
var SAFE_SESSION_LIST_INCLUDE_ID = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
11429
|
-
var SessionParamsSchema =
|
|
11430
|
-
sessionId:
|
|
11806
|
+
var SessionParamsSchema = z3.object({
|
|
11807
|
+
sessionId: z3.string().min(1).max(128)
|
|
11431
11808
|
});
|
|
11432
|
-
var CursorValueSchema =
|
|
11809
|
+
var CursorValueSchema = z3.preprocess((value) => {
|
|
11433
11810
|
if (value === void 0) return 0;
|
|
11434
11811
|
if (typeof value === "string" && value.length > 0) return Number(value);
|
|
11435
11812
|
return value;
|
|
11436
|
-
},
|
|
11437
|
-
var EventsQuerySchema =
|
|
11813
|
+
}, z3.number().int().nonnegative());
|
|
11814
|
+
var EventsQuerySchema = z3.object({
|
|
11438
11815
|
cursor: CursorValueSchema
|
|
11439
11816
|
});
|
|
11440
|
-
var EmptyBodySchema =
|
|
11441
|
-
var CreateSessionBodySchema =
|
|
11442
|
-
title:
|
|
11817
|
+
var EmptyBodySchema = z3.preprocess((value) => value ?? {}, z3.object({}).strict());
|
|
11818
|
+
var CreateSessionBodySchema = z3.preprocess((value) => value ?? {}, z3.object({
|
|
11819
|
+
title: z3.string().min(1).max(200).optional()
|
|
11443
11820
|
}).strict());
|
|
11444
11821
|
var PiChatRouteError = class extends Error {
|
|
11445
11822
|
statusCode;
|
|
@@ -12238,8 +12615,8 @@ function requirePath(value, reply) {
|
|
|
12238
12615
|
}
|
|
12239
12616
|
function gitRoutes(app, opts, done) {
|
|
12240
12617
|
async function resolveWorkspaceRoot(request) {
|
|
12241
|
-
|
|
12242
|
-
return
|
|
12618
|
+
const workspace = opts.getWorkspace ? await opts.getWorkspace(request) : opts.workspace;
|
|
12619
|
+
return workspace === void 0 ? void 0 : getNodeWorkspaceHostRoot(workspace);
|
|
12243
12620
|
}
|
|
12244
12621
|
app.get("/api/v1/git/file-url", async (request, reply) => {
|
|
12245
12622
|
const query = request.query;
|
|
@@ -12402,6 +12779,92 @@ function createWorkspaceAgentDispatcherError(code, message, statusCode) {
|
|
|
12402
12779
|
return error;
|
|
12403
12780
|
}
|
|
12404
12781
|
|
|
12782
|
+
// src/server/agentReadiness.ts
|
|
12783
|
+
var READINESS_PROBE_TOOL = {
|
|
12784
|
+
name: "agent_readiness_probe",
|
|
12785
|
+
description: "Internal readiness probe.",
|
|
12786
|
+
parameters: { type: "object", properties: {} },
|
|
12787
|
+
async execute() {
|
|
12788
|
+
return { content: [] };
|
|
12789
|
+
}
|
|
12790
|
+
};
|
|
12791
|
+
function collectToolReadinessRequirements(tools) {
|
|
12792
|
+
const requirements = /* @__PURE__ */ new Set();
|
|
12793
|
+
for (const tool of tools) {
|
|
12794
|
+
for (const requirement of tool.readinessRequirements ?? []) requirements.add(requirement);
|
|
12795
|
+
}
|
|
12796
|
+
return [...requirements];
|
|
12797
|
+
}
|
|
12798
|
+
function createAgentReadinessFromTracker(options) {
|
|
12799
|
+
const requirements = [...new Set(options.requirements)];
|
|
12800
|
+
return {
|
|
12801
|
+
requirements,
|
|
12802
|
+
async status() {
|
|
12803
|
+
return requirements.map((requirement) => readinessStatusForRequirement(requirement, options));
|
|
12804
|
+
}
|
|
12805
|
+
};
|
|
12806
|
+
}
|
|
12807
|
+
function readinessStatusForRequirement(requirement, options) {
|
|
12808
|
+
const snapshot = options.tracker.getReadiness();
|
|
12809
|
+
if (requirement === "workspace-fs") {
|
|
12810
|
+
return statusFromCapability(requirement, snapshot.capabilities.workspace, ErrorCode.enum.WORKSPACE_NOT_READY);
|
|
12811
|
+
}
|
|
12812
|
+
if (requirement === "sandbox-exec") {
|
|
12813
|
+
return snapshot.sandboxReady ? { key: requirement, ready: true, state: "ready" } : {
|
|
12814
|
+
key: requirement,
|
|
12815
|
+
ready: false,
|
|
12816
|
+
state: "preparing",
|
|
12817
|
+
errorCode: ErrorCode.enum.SANDBOX_NOT_READY,
|
|
12818
|
+
retryable: true
|
|
12819
|
+
};
|
|
12820
|
+
}
|
|
12821
|
+
if (isRuntimeReadinessRequirement(requirement)) {
|
|
12822
|
+
const status = statusFromCapability(
|
|
12823
|
+
requirement,
|
|
12824
|
+
snapshot.capabilities.runtimeDependencies,
|
|
12825
|
+
ErrorCode.enum.AGENT_RUNTIME_NOT_READY
|
|
12826
|
+
);
|
|
12827
|
+
if (status.ready || !options.checkReadiness) return status;
|
|
12828
|
+
return enrichRuntimeStatus(
|
|
12829
|
+
status,
|
|
12830
|
+
options.checkReadiness(requirement, READINESS_PROBE_TOOL)
|
|
12831
|
+
);
|
|
12832
|
+
}
|
|
12833
|
+
return { key: requirement, ready: false };
|
|
12834
|
+
}
|
|
12835
|
+
function enrichRuntimeStatus(status, readiness) {
|
|
12836
|
+
if (readiness === true || typeof readiness === "object" && readiness !== null && readiness.ready === true) {
|
|
12837
|
+
return status;
|
|
12838
|
+
}
|
|
12839
|
+
if (readiness === false) {
|
|
12840
|
+
return { ...status, retryable: status.retryable ?? true };
|
|
12841
|
+
}
|
|
12842
|
+
return {
|
|
12843
|
+
...status,
|
|
12844
|
+
...readiness.errorCode ? { errorCode: readiness.errorCode } : {},
|
|
12845
|
+
...readiness.causeCode ? { causeCode: readiness.causeCode } : {},
|
|
12846
|
+
...readiness.message ? { message: readiness.message } : {},
|
|
12847
|
+
...readiness.workspaceId ? { workspaceId: readiness.workspaceId } : {},
|
|
12848
|
+
retryable: readiness.retryable ?? status.retryable ?? true
|
|
12849
|
+
};
|
|
12850
|
+
}
|
|
12851
|
+
function statusFromCapability(key, detail, fallbackErrorCode) {
|
|
12852
|
+
const ready = detail.state === "ready";
|
|
12853
|
+
const errorCode = detail.errorCode ?? (detail.state === "failed" && isRuntimeReadinessRequirement(key) ? ErrorCode.enum.RUNTIME_PROVISIONING_FAILED : fallbackErrorCode);
|
|
12854
|
+
return {
|
|
12855
|
+
key,
|
|
12856
|
+
ready,
|
|
12857
|
+
state: detail.state,
|
|
12858
|
+
...!ready ? { errorCode } : {},
|
|
12859
|
+
...detail.causeCode ? { causeCode: detail.causeCode } : {},
|
|
12860
|
+
...detail.message ? { message: detail.message } : {},
|
|
12861
|
+
...detail.retryable !== void 0 ? { retryable: detail.retryable } : {}
|
|
12862
|
+
};
|
|
12863
|
+
}
|
|
12864
|
+
function isRuntimeReadinessRequirement(requirement) {
|
|
12865
|
+
return requirement === "runtime-dependencies" || requirement.startsWith("runtime:");
|
|
12866
|
+
}
|
|
12867
|
+
|
|
12405
12868
|
// src/server/createAgentApp.ts
|
|
12406
12869
|
var DEFAULT_VERSION = "0.1.0-dev";
|
|
12407
12870
|
var DEFAULT_SESSION_ID = "default";
|
|
@@ -12553,9 +13016,16 @@ async function createWorkspaceAgentAppProfile(opts, sessionId, resolvedMode, app
|
|
|
12553
13016
|
sessionRoot: opts.sessionRoot,
|
|
12554
13017
|
sessionDir: opts.sessionDir ?? input.sessionDir
|
|
12555
13018
|
}));
|
|
13019
|
+
const readyTracker = createRuntimeReadyStatusTracker(modeAdapter, {
|
|
13020
|
+
harnessReady: true
|
|
13021
|
+
});
|
|
12556
13022
|
const coreAgent = createAgentRuntimeBridge2({
|
|
12557
13023
|
runtime: modeAdapter,
|
|
12558
13024
|
tools,
|
|
13025
|
+
readiness: createAgentReadinessFromTracker({
|
|
13026
|
+
requirements: collectToolReadinessRequirements(tools),
|
|
13027
|
+
tracker: readyTracker
|
|
13028
|
+
}),
|
|
12559
13029
|
harnessFactory,
|
|
12560
13030
|
systemPromptAppend: opts.systemPromptAppend,
|
|
12561
13031
|
systemPromptDynamic: opts.systemPromptDynamic,
|
|
@@ -12573,9 +13043,6 @@ async function createWorkspaceAgentAppProfile(opts, sessionId, resolvedMode, app
|
|
|
12573
13043
|
opts.onWorkspaceAgentDispatcher?.(createStaticWorkspaceAgentDispatcherResolver(coreAgent.agent, sessionId));
|
|
12574
13044
|
const harness = agentRuntime.harness;
|
|
12575
13045
|
harnessRef = harness;
|
|
12576
|
-
const readyTracker = createRuntimeReadyStatusTracker(modeAdapter, {
|
|
12577
|
-
harnessReady: true
|
|
12578
|
-
});
|
|
12579
13046
|
const filesystemBindingsForRequest = opts.getFilesystemBindings ? (request) => {
|
|
12580
13047
|
const user = request.user;
|
|
12581
13048
|
return opts.getFilesystemBindings?.({
|
|
@@ -12588,6 +13055,8 @@ async function createWorkspaceAgentAppProfile(opts, sessionId, resolvedMode, app
|
|
|
12588
13055
|
requestId: request.id
|
|
12589
13056
|
});
|
|
12590
13057
|
} : void 0;
|
|
13058
|
+
const gitStorageRoot = getOptionalRuntimeBundleStorageRoot(runtimeBundle);
|
|
13059
|
+
const gitWorkspace = gitStorageRoot === void 0 ? runtimeBundle.workspace : createNodeWorkspace(gitStorageRoot);
|
|
12591
13060
|
return {
|
|
12592
13061
|
runtimeMode: resolvedMode,
|
|
12593
13062
|
capabilities: { tools: toolNames(tools) },
|
|
@@ -12611,12 +13080,12 @@ async function createWorkspaceAgentAppProfile(opts, sessionId, resolvedMode, app
|
|
|
12611
13080
|
// File search shares the same bound implementation as the model tool.
|
|
12612
13081
|
search: { fileSearch: runtimeBundle.fileSearch },
|
|
12613
13082
|
// Git metadata resolves against host storage, not a sandbox-internal cwd.
|
|
12614
|
-
git: {
|
|
13083
|
+
git: { workspace: gitWorkspace }
|
|
12615
13084
|
},
|
|
12616
13085
|
chat: { service: agentRuntime.service },
|
|
12617
13086
|
systemPrompt: { harness },
|
|
12618
13087
|
skills: {
|
|
12619
|
-
workspaceRoot,
|
|
13088
|
+
workspace: createNodeWorkspace(workspaceRoot),
|
|
12620
13089
|
additionalSkillPaths: runtimePi.additionalSkillPaths,
|
|
12621
13090
|
piPackages: runtimePi.packages,
|
|
12622
13091
|
noSkills: runtimePi.noSkills,
|
|
@@ -13194,7 +13663,7 @@ function createRuntimeProvisioningFailedError(workspaceId, cause) {
|
|
|
13194
13663
|
}
|
|
13195
13664
|
);
|
|
13196
13665
|
}
|
|
13197
|
-
function
|
|
13666
|
+
function isRuntimeReadinessRequirement2(requirement) {
|
|
13198
13667
|
return requirement === "runtime-dependencies" || requirement.startsWith("runtime:");
|
|
13199
13668
|
}
|
|
13200
13669
|
function causeCodeFrom(error) {
|
|
@@ -13203,7 +13672,7 @@ function causeCodeFrom(error) {
|
|
|
13203
13672
|
}
|
|
13204
13673
|
function createRuntimeReadinessCheck(workspaceId, getRuntimeDependencies) {
|
|
13205
13674
|
return (requirement) => {
|
|
13206
|
-
if (!
|
|
13675
|
+
if (!isRuntimeReadinessRequirement2(requirement)) return true;
|
|
13207
13676
|
const runtimeDependencies = getRuntimeDependencies();
|
|
13208
13677
|
if (runtimeDependencies.state === "ready" || runtimeDependencies.state === "not-started") return true;
|
|
13209
13678
|
return {
|
|
@@ -13532,6 +14001,11 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13532
14001
|
const coreAgent = createAgentRuntimeBridge2({
|
|
13533
14002
|
runtime: modeAdapter,
|
|
13534
14003
|
tools,
|
|
14004
|
+
readiness: createAgentReadinessFromTracker({
|
|
14005
|
+
requirements: collectToolReadinessRequirements(tools),
|
|
14006
|
+
tracker: readyTracker,
|
|
14007
|
+
checkReadiness
|
|
14008
|
+
}),
|
|
13535
14009
|
harnessFactory,
|
|
13536
14010
|
systemPromptAppend: opts.systemPromptAppend,
|
|
13537
14011
|
systemPromptDynamic,
|
|
@@ -13752,6 +14226,9 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13752
14226
|
}
|
|
13753
14227
|
opts.onWorkspaceAgentDispatcher?.({
|
|
13754
14228
|
async resolve(ctx, options) {
|
|
14229
|
+
return (await this.resolveWithWorkspace(ctx, options)).dispatcher;
|
|
14230
|
+
},
|
|
14231
|
+
async resolveWithWorkspace(ctx, options) {
|
|
13755
14232
|
const boundCtx = normalizeWorkspaceAgentDispatcherContext(ctx);
|
|
13756
14233
|
assertWorkspaceAgentDispatcherRequestContext(boundCtx, options?.request);
|
|
13757
14234
|
bindingLifecycle.assertAdmission(boundCtx.workspaceId, options?.request);
|
|
@@ -13763,11 +14240,17 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13763
14240
|
401
|
|
13764
14241
|
);
|
|
13765
14242
|
}
|
|
13766
|
-
return
|
|
14243
|
+
return {
|
|
14244
|
+
dispatcher: createLeasedWorkspaceAgentDispatcher(staticBinding, boundCtx, options?.request),
|
|
14245
|
+
workspace: staticBinding.runtimeBundle.workspace
|
|
14246
|
+
};
|
|
13767
14247
|
}
|
|
13768
14248
|
const binding = await getOrCreateRuntimeBinding(boundCtx.workspaceId, options?.request, { trustedCtx: boundCtx });
|
|
13769
14249
|
bindingLifecycle.assertAdmission(boundCtx.workspaceId, options?.request);
|
|
13770
|
-
return
|
|
14250
|
+
return {
|
|
14251
|
+
dispatcher: createLeasedWorkspaceAgentDispatcher(binding, boundCtx, options?.request),
|
|
14252
|
+
workspace: binding.runtimeBundle.workspace
|
|
14253
|
+
};
|
|
13771
14254
|
}
|
|
13772
14255
|
});
|
|
13773
14256
|
function getSkillsScopeForRequest(request) {
|
|
@@ -13867,7 +14350,11 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13867
14350
|
getFileSearch: async (request) => (await getBindingForRequest(request)).runtimeBundle.fileSearch
|
|
13868
14351
|
});
|
|
13869
14352
|
await app.register(gitRoutes, {
|
|
13870
|
-
|
|
14353
|
+
getWorkspace: async (request) => {
|
|
14354
|
+
const runtimeBundle = (await getBindingForRequest(request)).runtimeBundle;
|
|
14355
|
+
const storageRoot = getOptionalRuntimeBundleStorageRoot(runtimeBundle);
|
|
14356
|
+
return storageRoot === void 0 ? runtimeBundle.workspace : createNodeWorkspace(storageRoot);
|
|
14357
|
+
}
|
|
13871
14358
|
});
|
|
13872
14359
|
await app.register(piChatRoutes, {
|
|
13873
14360
|
getService: async (request) => {
|
|
@@ -13883,7 +14370,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13883
14370
|
filterModels: opts.filterModels
|
|
13884
14371
|
});
|
|
13885
14372
|
await app.register(skillsRoutes, {
|
|
13886
|
-
workspaceRoot,
|
|
14373
|
+
workspace: staticBinding ? createNodeWorkspace(workspaceRoot) : void 0,
|
|
13887
14374
|
additionalSkillPaths: [
|
|
13888
14375
|
...staticBinding?.runtimeProvisioning?.skillPaths ?? [],
|
|
13889
14376
|
...opts.pi?.additionalSkillPaths ?? []
|
|
@@ -13892,7 +14379,7 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
13892
14379
|
// Undefined is fine: skillsRoutes resolves it through the canonical
|
|
13893
14380
|
// harness policy (withPiHarnessDefaults), same as the factory above.
|
|
13894
14381
|
noSkills: opts.pi?.noSkills,
|
|
13895
|
-
|
|
14382
|
+
getWorkspace: staticBinding ? void 0 : async (request) => createNodeWorkspace((await getSkillsScopeForRequest(request)).root),
|
|
13896
14383
|
getAdditionalSkillPaths: staticBinding && !hasRuntimeProvisioningInput ? void 0 : async (request) => {
|
|
13897
14384
|
const scope = await getSkillsScopeForRequest(request);
|
|
13898
14385
|
if (!hasRuntimeProvisioningInput) return scope.pi.additionalSkillPaths;
|
|
@@ -14024,6 +14511,8 @@ export {
|
|
|
14024
14511
|
createAgent,
|
|
14025
14512
|
AgentDirectoryCompilerError,
|
|
14026
14513
|
compileAgentDirectory,
|
|
14514
|
+
createResolvedAgentDigest,
|
|
14515
|
+
resolveAgentDeployment,
|
|
14027
14516
|
MANAGED_AGENT_MCP_ORIGIN_SURFACE,
|
|
14028
14517
|
MANAGED_AGENT_MCP_DELIVERY_RULE,
|
|
14029
14518
|
ManagedAgentMcpError,
|