@hachej/boring-agent 0.1.93 → 0.1.94
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-CJ2BW2W2.js → chunk-EOMY2HDT.js} +1 -0
- package/dist/{chunk-4TKUT7IL.js → chunk-N4AATPH7.js} +255 -73
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +1 -1
- package/dist/{errors-C38f6pol.d.ts → errors-G6T6S7PQ.d.ts} +2 -0
- package/dist/front/index.d.ts +68 -8
- package/dist/front/index.js +594 -593
- package/dist/front/styles.css +179 -109
- package/dist/{lease-BqeCLGPL.d.ts → lease-CusB-uLg.d.ts} +3 -1
- package/dist/{piChatSessionService-BrPqKrpY.d.ts → piChatSessionService-C0KbcGw9.d.ts} +7 -1
- package/dist/server/agent-host/testing/gatewayConformance.d.ts +3 -3
- package/dist/server/agent-host/testing/gatewayConformance.js +77 -0
- package/dist/server/index.d.ts +44 -5
- package/dist/server/index.js +2 -2
- package/dist/server/worker/index.js +2 -2
- package/dist/shared/index.d.ts +4 -4
- package/dist/{types-uQozUhGt.d.ts → types-C-Eroi__.d.ts} +2 -2
- package/docs/AGENT_GATEWAY_V0.md +152 -0
- package/package.json +4 -4
|
@@ -42,6 +42,7 @@ var AGENT_EFFECT_METHODS = {
|
|
|
42
42
|
};
|
|
43
43
|
function withAgentEffectAdmission(service, admit) {
|
|
44
44
|
return {
|
|
45
|
+
...service.ensurePiSessionBound ? { ensurePiSessionBound: (ctx, sessionId) => service.ensurePiSessionBound(ctx, sessionId) } : {},
|
|
45
46
|
...service.listSessions ? { listSessions: (ctx, options) => service.listSessions(ctx, options) } : {},
|
|
46
47
|
async createSession(ctx, init) {
|
|
47
48
|
await admit(ctx);
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
AgentEffectAdmissionError,
|
|
12
12
|
createAgentRuntimeBridge,
|
|
13
13
|
isObservedSynchronousServiceError
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-EOMY2HDT.js";
|
|
15
15
|
import {
|
|
16
16
|
AgentDefinitionValidationError,
|
|
17
17
|
AgentDeploymentValidationError,
|
|
@@ -4605,6 +4605,18 @@ var HarnessPiChatService = class {
|
|
|
4605
4605
|
const seq = envelope?.chunk?.seq;
|
|
4606
4606
|
return typeof seq === "number" && Number.isInteger(seq) && seq >= 0 ? seq : tailIndex + 1;
|
|
4607
4607
|
}
|
|
4608
|
+
/**
|
|
4609
|
+
* Validate the persisted session identity and instantiate its lazily-created
|
|
4610
|
+
* Pi adapter under the same full cache key. This is intentionally a narrow
|
|
4611
|
+
* trusted-host seam rather than another browser route.
|
|
4612
|
+
*/
|
|
4613
|
+
async ensurePiSessionBound(ctx, sessionId) {
|
|
4614
|
+
this.lifecycle.assertOpen();
|
|
4615
|
+
await this.assertCanAccessSession(ctx, sessionId);
|
|
4616
|
+
const adapter = await this.getAdapter(ctx, sessionId, "", { authorize: false });
|
|
4617
|
+
await this.ensureChannel(ctx, sessionId, adapter);
|
|
4618
|
+
this.lifecycle.assertOpen();
|
|
4619
|
+
}
|
|
4608
4620
|
async assertCanAccessSession(ctx, sessionId) {
|
|
4609
4621
|
try {
|
|
4610
4622
|
await this.sessionStore.load(toSessionCtx(ctx), sessionId);
|
|
@@ -7311,7 +7323,16 @@ var EmbeddedAgentGateway = class {
|
|
|
7311
7323
|
});
|
|
7312
7324
|
this.runtime.activity.set(claim.workspaceScopeId, ref, "running");
|
|
7313
7325
|
return { ...receipt, disposition: "prompt" };
|
|
7314
|
-
},
|
|
7326
|
+
}, {
|
|
7327
|
+
duplicateReceipt: true,
|
|
7328
|
+
guard: async () => await this.promptAdmission(
|
|
7329
|
+
scope,
|
|
7330
|
+
claim,
|
|
7331
|
+
ref,
|
|
7332
|
+
command.requestId,
|
|
7333
|
+
command.requireIdle === true
|
|
7334
|
+
)
|
|
7335
|
+
});
|
|
7315
7336
|
}
|
|
7316
7337
|
return await this.sessionEffect(ref, claim, "session.followup", command.requestId, command, async () => {
|
|
7317
7338
|
const receipt = await service.followUp(context(claim, command.requestId), ref.sessionId, {
|
|
@@ -7321,7 +7342,7 @@ var EmbeddedAgentGateway = class {
|
|
|
7321
7342
|
clientSeq: command.clientSeq
|
|
7322
7343
|
});
|
|
7323
7344
|
return { ...receipt, disposition: "followup" };
|
|
7324
|
-
}, true);
|
|
7345
|
+
}, { duplicateReceipt: true });
|
|
7325
7346
|
}
|
|
7326
7347
|
async renameSession(input) {
|
|
7327
7348
|
const claim = await this.verify(input.scope);
|
|
@@ -7395,16 +7416,18 @@ var EmbeddedAgentGateway = class {
|
|
|
7395
7416
|
if (!summary) throw new AgentGatewayError(AgentGatewayErrorCode.AGENT_SESSION_NOT_FOUND, "session was not found");
|
|
7396
7417
|
return summary;
|
|
7397
7418
|
}
|
|
7398
|
-
sessionEffect(ref, claim, operation, requestId, payload, action,
|
|
7419
|
+
sessionEffect(ref, claim, operation, requestId, payload, action, options = {}) {
|
|
7399
7420
|
return this.effect(
|
|
7400
7421
|
claim,
|
|
7401
7422
|
operation,
|
|
7402
7423
|
sessionTarget(ref),
|
|
7403
7424
|
requestId,
|
|
7404
7425
|
payload,
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7426
|
+
action,
|
|
7427
|
+
{
|
|
7428
|
+
...options,
|
|
7429
|
+
serialize: (effect) => this.withWriter(claim.workspaceScopeId, ref, effect)
|
|
7430
|
+
}
|
|
7408
7431
|
);
|
|
7409
7432
|
}
|
|
7410
7433
|
/** Internal legacy-alias seam; never exposed through the public Gateway contract. */
|
|
@@ -7419,8 +7442,7 @@ var EmbeddedAgentGateway = class {
|
|
|
7419
7442
|
input.requestId,
|
|
7420
7443
|
input.payload,
|
|
7421
7444
|
input.action,
|
|
7422
|
-
|
|
7423
|
-
true
|
|
7445
|
+
{ legacyAlias: true }
|
|
7424
7446
|
);
|
|
7425
7447
|
}
|
|
7426
7448
|
if (input.target.kind !== "session") throw new TypeError(`${input.operation} requires a session target`);
|
|
@@ -7431,12 +7453,20 @@ var EmbeddedAgentGateway = class {
|
|
|
7431
7453
|
input.requestId,
|
|
7432
7454
|
input.payload,
|
|
7433
7455
|
input.action,
|
|
7434
|
-
|
|
7435
|
-
|
|
7456
|
+
{
|
|
7457
|
+
legacyAlias: true,
|
|
7458
|
+
guard: input.retryableGuard
|
|
7459
|
+
}
|
|
7436
7460
|
);
|
|
7437
7461
|
}
|
|
7438
|
-
async effect(claim, operation, target, requestId, payload, action,
|
|
7462
|
+
async effect(claim, operation, target, requestId, payload, action, options = {}) {
|
|
7439
7463
|
this.assertOpen();
|
|
7464
|
+
const {
|
|
7465
|
+
duplicateReceipt = false,
|
|
7466
|
+
legacyAlias = false,
|
|
7467
|
+
serialize,
|
|
7468
|
+
guard
|
|
7469
|
+
} = options;
|
|
7440
7470
|
const key = {
|
|
7441
7471
|
workspaceScopeId: claim.workspaceScopeId,
|
|
7442
7472
|
authSubjectId: claim.authSubjectId,
|
|
@@ -7452,8 +7482,9 @@ var EmbeddedAgentGateway = class {
|
|
|
7452
7482
|
const id = requestKeyString(key);
|
|
7453
7483
|
const existing = this.effects.get(id);
|
|
7454
7484
|
if (existing) return this.replayReceipt(await existing, duplicateReceipt);
|
|
7455
|
-
const
|
|
7485
|
+
const execute = async () => {
|
|
7456
7486
|
const current = await this.runtime.ledger.read(key);
|
|
7487
|
+
let admissionReceipt;
|
|
7457
7488
|
if (current?.state === "pending-admission") {
|
|
7458
7489
|
const admission = await this.runtime.effectAdmission.admit({ key, digest: digest2, scope: claim, operation, target });
|
|
7459
7490
|
if (admission.type === "retryable") throw gatewayError(admission.error);
|
|
@@ -7461,71 +7492,87 @@ var EmbeddedAgentGateway = class {
|
|
|
7461
7492
|
await this.runtime.ledger.reject(key, { kind: "gateway", error: admission.error });
|
|
7462
7493
|
throw gatewayError(admission.error);
|
|
7463
7494
|
}
|
|
7464
|
-
|
|
7465
|
-
}
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7495
|
+
admissionReceipt = admission.admissionReceipt;
|
|
7496
|
+
}
|
|
7497
|
+
const runEffect = async () => {
|
|
7498
|
+
const locked = await this.runtime.ledger.read(key);
|
|
7499
|
+
if (locked?.state === "pending-admission") {
|
|
7500
|
+
if (admissionReceipt === void 0) {
|
|
7501
|
+
throw new AgentGatewayError(
|
|
7502
|
+
AgentGatewayErrorCode.AGENT_REQUEST_OUTCOME_UNKNOWN,
|
|
7503
|
+
"request admission receipt was unavailable"
|
|
7504
|
+
);
|
|
7505
|
+
}
|
|
7506
|
+
const retryableGuardError = await guard?.();
|
|
7507
|
+
if (retryableGuardError) throw gatewayError(retryableGuardError);
|
|
7508
|
+
await this.runtime.ledger.acceptAdmission(key, admissionReceipt);
|
|
7509
|
+
}
|
|
7510
|
+
await this.runtime.ledger.beginEffect(key);
|
|
7511
|
+
let actionResult;
|
|
7512
|
+
try {
|
|
7513
|
+
actionResult = action();
|
|
7514
|
+
} catch (error) {
|
|
7515
|
+
if (legacyAlias) {
|
|
7516
|
+
if (error instanceof AgentEffectAdmissionError) {
|
|
7517
|
+
const details = projectJson(error.details);
|
|
7518
|
+
const failure2 = {
|
|
7519
|
+
kind: "legacy-admission",
|
|
7520
|
+
code: error.code,
|
|
7521
|
+
statusCode: 500,
|
|
7522
|
+
message: error.message,
|
|
7523
|
+
...details === void 0 ? {} : { details }
|
|
7524
|
+
};
|
|
7525
|
+
await this.runtime.ledger.reject(key, failure2);
|
|
7526
|
+
throw this.failure(failure2, true);
|
|
7527
|
+
}
|
|
7528
|
+
const failure = legacyServiceFailure(error);
|
|
7529
|
+
await this.runtime.ledger.reject(key, failure);
|
|
7530
|
+
throw this.failure(failure, true);
|
|
7531
|
+
}
|
|
7532
|
+
const unknown = new AgentGatewayError(
|
|
7533
|
+
AgentGatewayErrorCode.AGENT_REQUEST_OUTCOME_UNKNOWN,
|
|
7534
|
+
"effect outcome could not be safely replayed"
|
|
7535
|
+
);
|
|
7536
|
+
await this.runtime.ledger.markOutcomeUnknown(key, unknown.toJSON()).catch(() => {
|
|
7537
|
+
});
|
|
7538
|
+
throw error;
|
|
7539
|
+
}
|
|
7540
|
+
try {
|
|
7541
|
+
const receipt = await actionResult;
|
|
7542
|
+
this.runtime.assertOpen();
|
|
7543
|
+
await this.runtime.ledger.complete(key, receipt);
|
|
7544
|
+
return receipt;
|
|
7545
|
+
} catch (error) {
|
|
7546
|
+
if (legacyAlias && error instanceof AgentEffectAdmissionError) {
|
|
7473
7547
|
const details = projectJson(error.details);
|
|
7474
|
-
const
|
|
7548
|
+
const failure = {
|
|
7475
7549
|
kind: "legacy-admission",
|
|
7476
7550
|
code: error.code,
|
|
7477
7551
|
statusCode: 500,
|
|
7478
7552
|
message: error.message,
|
|
7479
7553
|
...details === void 0 ? {} : { details }
|
|
7480
7554
|
};
|
|
7481
|
-
await this.runtime.ledger.reject(key,
|
|
7482
|
-
throw this.failure(
|
|
7555
|
+
await this.runtime.ledger.reject(key, failure);
|
|
7556
|
+
throw this.failure(failure, true);
|
|
7483
7557
|
}
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
const receipt = await actionResult;
|
|
7498
|
-
this.runtime.assertOpen();
|
|
7499
|
-
await this.runtime.ledger.complete(key, receipt);
|
|
7500
|
-
return receipt;
|
|
7501
|
-
} catch (error) {
|
|
7502
|
-
if (legacyAlias && error instanceof AgentEffectAdmissionError) {
|
|
7503
|
-
const details = projectJson(error.details);
|
|
7504
|
-
const failure = {
|
|
7505
|
-
kind: "legacy-admission",
|
|
7506
|
-
code: error.code,
|
|
7507
|
-
statusCode: 500,
|
|
7508
|
-
message: error.message,
|
|
7509
|
-
...details === void 0 ? {} : { details }
|
|
7510
|
-
};
|
|
7511
|
-
await this.runtime.ledger.reject(key, failure);
|
|
7512
|
-
throw this.failure(failure, true);
|
|
7513
|
-
}
|
|
7514
|
-
if (legacyAlias && (isObservedSynchronousServiceError(error) || isKnownLegacyServiceFailure(error))) {
|
|
7515
|
-
const failure = legacyServiceFailure(error);
|
|
7516
|
-
await this.runtime.ledger.reject(key, failure);
|
|
7517
|
-
throw this.failure(failure, true);
|
|
7558
|
+
if (legacyAlias && (isObservedSynchronousServiceError(error) || isKnownLegacyServiceFailure(error))) {
|
|
7559
|
+
const failure = legacyServiceFailure(error);
|
|
7560
|
+
await this.runtime.ledger.reject(key, failure);
|
|
7561
|
+
throw this.failure(failure, true);
|
|
7562
|
+
}
|
|
7563
|
+
const unknown = new AgentGatewayError(
|
|
7564
|
+
AgentGatewayErrorCode.AGENT_REQUEST_OUTCOME_UNKNOWN,
|
|
7565
|
+
"effect outcome could not be safely replayed"
|
|
7566
|
+
);
|
|
7567
|
+
await this.runtime.ledger.markOutcomeUnknown(key, unknown.toJSON()).catch(() => {
|
|
7568
|
+
});
|
|
7569
|
+
if (legacyAlias) throw unknown;
|
|
7570
|
+
throw error;
|
|
7518
7571
|
}
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
await this.runtime.ledger.markOutcomeUnknown(key, unknown.toJSON()).catch(() => {
|
|
7524
|
-
});
|
|
7525
|
-
if (legacyAlias) throw unknown;
|
|
7526
|
-
throw error;
|
|
7527
|
-
}
|
|
7528
|
-
})(), key);
|
|
7572
|
+
};
|
|
7573
|
+
return serialize ? serialize(runEffect) : runEffect();
|
|
7574
|
+
};
|
|
7575
|
+
const running = this.runtime.trackEffect(execute(), key);
|
|
7529
7576
|
this.effects.set(id, running);
|
|
7530
7577
|
try {
|
|
7531
7578
|
return await running;
|
|
@@ -7558,6 +7605,20 @@ var EmbeddedAgentGateway = class {
|
|
|
7558
7605
|
"effect admission was rejected"
|
|
7559
7606
|
);
|
|
7560
7607
|
}
|
|
7608
|
+
async promptAdmission(scope, claim, ref, requestId, requireIdle) {
|
|
7609
|
+
const binding = await this.bindingForSession(scope, claim, ref);
|
|
7610
|
+
const snapshot = await binding.composition.service.readState(
|
|
7611
|
+
context(claim, requestId, binding.scope.identity),
|
|
7612
|
+
ref.sessionId
|
|
7613
|
+
);
|
|
7614
|
+
const admissible = requireIdle ? snapshot.status === "idle" : snapshot.status === "idle" || snapshot.status === "error";
|
|
7615
|
+
if (admissible) return void 0;
|
|
7616
|
+
return new AgentGatewayError(
|
|
7617
|
+
AgentGatewayErrorCode.AGENT_COMMAND_INVALID_STATE,
|
|
7618
|
+
requireIdle ? "session is not idle" : "prompt is invalid in current state",
|
|
7619
|
+
{ status: snapshot.status }
|
|
7620
|
+
).toJSON();
|
|
7621
|
+
}
|
|
7561
7622
|
async withWriter(workspaceScopeId, ref, action) {
|
|
7562
7623
|
const key = sessionKey(workspaceScopeId, ref);
|
|
7563
7624
|
const previous = this.writerTails.get(key) ?? Promise.resolve();
|
|
@@ -8167,6 +8228,7 @@ var PromptBodySchema = z4.object({
|
|
|
8167
8228
|
clientNonce: NonEmptyString.max(128),
|
|
8168
8229
|
content: NonEmptyString.max(1e6),
|
|
8169
8230
|
displayContent: NonEmptyString.max(1e6).optional(),
|
|
8231
|
+
requireIdle: z4.literal(true).optional(),
|
|
8170
8232
|
model: ChatModelSelectionSchema.optional(),
|
|
8171
8233
|
thinkingLevel: z4.enum(["off", "low", "medium", "high"]).optional(),
|
|
8172
8234
|
attachments: z4.array(ChatAttachmentPayloadSchema).max(20).optional()
|
|
@@ -8486,7 +8548,8 @@ function createLegacyPiChatCompatibilityService(input) {
|
|
|
8486
8548
|
target: options.target,
|
|
8487
8549
|
requestId: options.requestId,
|
|
8488
8550
|
payload: jsonProjection(options.payload),
|
|
8489
|
-
action: options.action
|
|
8551
|
+
action: options.action,
|
|
8552
|
+
...options.retryableGuard ? { retryableGuard: options.retryableGuard } : {}
|
|
8490
8553
|
});
|
|
8491
8554
|
return {
|
|
8492
8555
|
...input.service.listSessions ? { listSessions: (ctx, options) => input.service.listSessions(ctx, options) } : {},
|
|
@@ -8517,6 +8580,17 @@ function createLegacyPiChatCompatibilityService(input) {
|
|
|
8517
8580
|
target: sessionTarget2(input.agentTypeId, sessionId),
|
|
8518
8581
|
requestId: requestIdForPayload(ctx, payload.clientNonce),
|
|
8519
8582
|
payload,
|
|
8583
|
+
...payload.requireIdle ? {
|
|
8584
|
+
retryableGuard: async () => {
|
|
8585
|
+
const snapshot = await input.service.readState(ctx, sessionId);
|
|
8586
|
+
if (snapshot.status === "idle") return void 0;
|
|
8587
|
+
return new AgentGatewayError(
|
|
8588
|
+
AgentGatewayErrorCode.AGENT_COMMAND_INVALID_STATE,
|
|
8589
|
+
"session is not idle",
|
|
8590
|
+
{ status: snapshot.status }
|
|
8591
|
+
).toJSON();
|
|
8592
|
+
}
|
|
8593
|
+
} : {},
|
|
8520
8594
|
action: () => input.service.prompt(ctx, sessionId, payload)
|
|
8521
8595
|
}),
|
|
8522
8596
|
followUp: (ctx, sessionId, payload) => effect({
|
|
@@ -9732,7 +9806,7 @@ async function dispatchGatewayInput(binding, input) {
|
|
|
9732
9806
|
scope: binding.scope,
|
|
9733
9807
|
agentTypeId: binding.agentTypeId,
|
|
9734
9808
|
requestId,
|
|
9735
|
-
title: contentToText(input.content ?? input.message).slice(0, 80) || void 0
|
|
9809
|
+
title: input.title?.trim() || contentToText(input.content ?? input.message).slice(0, 80) || void 0
|
|
9736
9810
|
});
|
|
9737
9811
|
const connection = await binding.gateway.connectSession({
|
|
9738
9812
|
scope: binding.scope,
|
|
@@ -10897,6 +10971,75 @@ async function mountOrderedAgentHostLegacyRoutes(input) {
|
|
|
10897
10971
|
);
|
|
10898
10972
|
}
|
|
10899
10973
|
|
|
10974
|
+
// src/server/trustedPiSessionBinding.ts
|
|
10975
|
+
async function bindTrustedPiSession(input) {
|
|
10976
|
+
const sessionContext = trustedPiSessionContext(input.ctx, input.request, input.requested);
|
|
10977
|
+
await input.withServices(async ({ binding }) => {
|
|
10978
|
+
if (!binding.ensurePiSessionBound) {
|
|
10979
|
+
throw createWorkspaceAgentDispatcherError(
|
|
10980
|
+
ErrorCode.enum.INTERNAL_ERROR,
|
|
10981
|
+
"Pi session binding is unavailable",
|
|
10982
|
+
500
|
|
10983
|
+
);
|
|
10984
|
+
}
|
|
10985
|
+
return await binding.ensurePiSessionBound(sessionContext, input.sessionId);
|
|
10986
|
+
});
|
|
10987
|
+
return {
|
|
10988
|
+
visibleUserMessageTarget: {
|
|
10989
|
+
async isIdle() {
|
|
10990
|
+
return await input.withServices(async ({ binding }) => {
|
|
10991
|
+
const snapshot = await binding.readState(sessionContext, input.sessionId);
|
|
10992
|
+
return snapshot.status === "idle";
|
|
10993
|
+
});
|
|
10994
|
+
},
|
|
10995
|
+
async sendIfIdle(sendInput) {
|
|
10996
|
+
const requestId = sendInput.requestId.trim();
|
|
10997
|
+
if (!requestId) throw new TypeError("requestId must be a non-empty string");
|
|
10998
|
+
try {
|
|
10999
|
+
const receipt = await input.withServices(async ({ prompt }) => await prompt.prompt(
|
|
11000
|
+
sessionContext,
|
|
11001
|
+
input.sessionId,
|
|
11002
|
+
{
|
|
11003
|
+
message: sendInput.message,
|
|
11004
|
+
displayMessage: sendInput.displayMessage ?? sendInput.message,
|
|
11005
|
+
clientNonce: requestId,
|
|
11006
|
+
requireIdle: true
|
|
11007
|
+
}
|
|
11008
|
+
));
|
|
11009
|
+
return {
|
|
11010
|
+
status: "accepted",
|
|
11011
|
+
cursor: receipt.cursor,
|
|
11012
|
+
...receipt.duplicate ? { duplicate: true } : {}
|
|
11013
|
+
};
|
|
11014
|
+
} catch (error) {
|
|
11015
|
+
if (error instanceof AgentGatewayError && error.code === AgentGatewayErrorCode.AGENT_COMMAND_INVALID_STATE) {
|
|
11016
|
+
return { status: "busy" };
|
|
11017
|
+
}
|
|
11018
|
+
if (isGoneSessionError(error)) return { status: "gone" };
|
|
11019
|
+
throw error;
|
|
11020
|
+
}
|
|
11021
|
+
}
|
|
11022
|
+
}
|
|
11023
|
+
};
|
|
11024
|
+
}
|
|
11025
|
+
function isGoneSessionError(error) {
|
|
11026
|
+
const code = error?.code;
|
|
11027
|
+
return code === AgentGatewayErrorCode.AGENT_SESSION_NOT_FOUND || code === AgentGatewayErrorCode.AGENT_SCOPE_DENIED || code === AgentGatewayErrorCode.AGENT_SESSION_RUNTIME_SCOPE_MISMATCH || code === ErrorCode.enum.SESSION_NOT_FOUND || code === ErrorCode.enum.UNAUTHORIZED;
|
|
11028
|
+
}
|
|
11029
|
+
function trustedPiSessionContext(ctx, request, requested) {
|
|
11030
|
+
if (requested?.workspaceId && requested.workspaceId !== ctx.workspaceId) {
|
|
11031
|
+
throw createWorkspaceAgentDispatcherError(ErrorCode.enum.UNAUTHORIZED, "Pi session workspace context mismatch", 401);
|
|
11032
|
+
}
|
|
11033
|
+
if (requested?.userId && requested.userId !== ctx.userId) {
|
|
11034
|
+
throw createWorkspaceAgentDispatcherError(ErrorCode.enum.UNAUTHORIZED, "Pi session user context mismatch", 401);
|
|
11035
|
+
}
|
|
11036
|
+
return {
|
|
11037
|
+
workspaceId: requested?.workspaceId ?? ctx.workspaceId,
|
|
11038
|
+
authSubject: requested?.userId ?? ctx.userId,
|
|
11039
|
+
requestId: request?.id ?? `trusted:${ctx.workspaceId}:${ctx.userId}`
|
|
11040
|
+
};
|
|
11041
|
+
}
|
|
11042
|
+
|
|
10900
11043
|
// src/server/agentHostLegacyRouteRuntime.ts
|
|
10901
11044
|
var DEFAULT_WORKSPACE_ID6 = "default";
|
|
10902
11045
|
var STANDARD_AGENT_TOOL_NAMES = ["bash", "read", "write", "edit", "find", "grep", "ls"];
|
|
@@ -11391,6 +11534,11 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11391
11534
|
tools,
|
|
11392
11535
|
readyTracker,
|
|
11393
11536
|
piChatService: composition.service,
|
|
11537
|
+
trustedPiChatService: agentHost.createPiChatService({
|
|
11538
|
+
service: composition.service,
|
|
11539
|
+
scope: authorizedScope,
|
|
11540
|
+
agentTypeId: defaultAgentTypeId
|
|
11541
|
+
}),
|
|
11394
11542
|
authorizedScope,
|
|
11395
11543
|
hostScope
|
|
11396
11544
|
};
|
|
@@ -11526,6 +11674,7 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11526
11674
|
throw error;
|
|
11527
11675
|
}
|
|
11528
11676
|
return {
|
|
11677
|
+
binding,
|
|
11529
11678
|
dispatcher: createBoundWorkspaceAgentDispatcher({
|
|
11530
11679
|
gateway: agentHost.gateway,
|
|
11531
11680
|
scope: binding.authorizedScope,
|
|
@@ -11538,6 +11687,25 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11538
11687
|
binding = await getOrCreateRuntimeBinding(boundCtx.workspaceId, void 0, { trustedCtx: boundCtx });
|
|
11539
11688
|
}
|
|
11540
11689
|
}
|
|
11690
|
+
async function ensureTrustedPiSessionBound(initialBinding, boundCtx, boundSessionId, request, requestedSessionCtx) {
|
|
11691
|
+
return await bindTrustedPiSession({
|
|
11692
|
+
ctx: boundCtx,
|
|
11693
|
+
request,
|
|
11694
|
+
sessionId: boundSessionId,
|
|
11695
|
+
requested: requestedSessionCtx,
|
|
11696
|
+
withServices: async (effect) => {
|
|
11697
|
+
const operation = await acquireDispatcherOperation(initialBinding, boundCtx, request);
|
|
11698
|
+
try {
|
|
11699
|
+
return await effect({
|
|
11700
|
+
binding: operation.binding.piChatService,
|
|
11701
|
+
prompt: operation.binding.trustedPiChatService
|
|
11702
|
+
});
|
|
11703
|
+
} finally {
|
|
11704
|
+
operation.release();
|
|
11705
|
+
}
|
|
11706
|
+
}
|
|
11707
|
+
});
|
|
11708
|
+
}
|
|
11541
11709
|
function createLeasedWorkspaceAgentDispatcher(initialBinding, boundCtx, request) {
|
|
11542
11710
|
return {
|
|
11543
11711
|
async dispatch(input) {
|
|
@@ -11616,14 +11784,28 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11616
11784
|
}
|
|
11617
11785
|
return {
|
|
11618
11786
|
dispatcher: createLeasedWorkspaceAgentDispatcher(staticBinding, boundCtx, options?.request),
|
|
11619
|
-
workspace: staticBinding.runtimeBundle.workspace
|
|
11787
|
+
workspace: staticBinding.runtimeBundle.workspace,
|
|
11788
|
+
bindPiSession: async (boundSessionId, requestedSessionCtx) => await ensureTrustedPiSessionBound(
|
|
11789
|
+
staticBinding,
|
|
11790
|
+
boundCtx,
|
|
11791
|
+
boundSessionId,
|
|
11792
|
+
options?.request,
|
|
11793
|
+
requestedSessionCtx
|
|
11794
|
+
)
|
|
11620
11795
|
};
|
|
11621
11796
|
}
|
|
11622
11797
|
const binding = await getOrCreateRuntimeBinding(boundCtx.workspaceId, options?.request, { trustedCtx: boundCtx });
|
|
11623
11798
|
bindingLifecycle.assertAdmission(boundCtx.workspaceId, options?.request);
|
|
11624
11799
|
return {
|
|
11625
11800
|
dispatcher: createLeasedWorkspaceAgentDispatcher(binding, boundCtx, options?.request),
|
|
11626
|
-
workspace: binding.runtimeBundle.workspace
|
|
11801
|
+
workspace: binding.runtimeBundle.workspace,
|
|
11802
|
+
bindPiSession: async (boundSessionId, requestedSessionCtx) => await ensureTrustedPiSessionBound(
|
|
11803
|
+
binding,
|
|
11804
|
+
boundCtx,
|
|
11805
|
+
boundSessionId,
|
|
11806
|
+
options?.request,
|
|
11807
|
+
requestedSessionCtx
|
|
11808
|
+
)
|
|
11627
11809
|
};
|
|
11628
11810
|
}
|
|
11629
11811
|
});
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { A as AgentHarness, a as AgentReadiness, b as Agent } from '../harness-Cc48o6uS.js';
|
|
2
2
|
export { c as AGENT_NOT_IMPLEMENTED_UNTIL_T1, d as AgentActor, e as AgentCoreHarness, f as AgentCoreHarnessFactory, g as AgentCorePromptInput, h as AgentCoreSessionAdapter, i as AgentCoreSessionSnapshot, j as AgentEvent, k as AgentMessageContent, l as AgentMessagePart, m as AgentNotImplementedError, n as AgentReadinessStatus, o as AgentResolveInputResponse, p as AgentSendInput, q as AgentStartReceipt, r as AgentStreamOptions } from '../harness-Cc48o6uS.js';
|
|
3
3
|
import { S as SessionStore } from '../piChatEvent-BsMp3MSo.js';
|
|
4
|
-
import { A as AgentCoreSessionService, a as AgentEffectAdmission } from '../piChatSessionService-
|
|
5
|
-
export { b as AGENT_EFFECT_METHODS, c as AgentEffectAdmissionError, P as PiChatEventStreamResult, d as PiChatEventStreamSubscription, e as PiChatEventSubscriber, f as PiChatReplayRangeError, g as PiChatSessionService, h as PiSessionCreateInit, i as PiSessionRequestContext, w as withAgentEffectAdmission } from '../piChatSessionService-
|
|
4
|
+
import { A as AgentCoreSessionService, a as AgentEffectAdmission } from '../piChatSessionService-C0KbcGw9.js';
|
|
5
|
+
export { b as AGENT_EFFECT_METHODS, c as AgentEffectAdmissionError, P as PiChatEventStreamResult, d as PiChatEventStreamSubscription, e as PiChatEventSubscriber, f as PiChatReplayRangeError, g as PiChatSessionService, h as PiSessionCreateInit, i as PiSessionRequestContext, w as withAgentEffectAdmission } from '../piChatSessionService-C0KbcGw9.js';
|
|
6
6
|
import '@mariozechner/pi-coding-agent';
|
|
7
7
|
import 'zod';
|
|
8
8
|
|
package/dist/core/index.js
CHANGED
|
@@ -101,6 +101,8 @@ interface AgentPromptCommand {
|
|
|
101
101
|
readonly clientNonce: string;
|
|
102
102
|
readonly content: string;
|
|
103
103
|
readonly displayContent?: string;
|
|
104
|
+
/** Require an actually idle Pi session; busy is a retryable admission result. */
|
|
105
|
+
readonly requireIdle?: true;
|
|
104
106
|
readonly model?: ChatModelSelection;
|
|
105
107
|
readonly thinkingLevel?: ThinkingLevel;
|
|
106
108
|
readonly attachments?: readonly ChatAttachmentPayload[];
|
package/dist/front/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { T as ToolUiMetadata, B as BoringChatPart, a as BoringChatMessage, P as PiChatStatus, Q as QueuedUserMessage, C as ChatError, b as PiChatEvent, c as PromptPayload, d as PromptReceipt, F as FollowUpPayload, e as FollowUpReceipt, f as QueueClearPayload, g as QueueClearReceipt, I as InterruptPayload, h as CommandReceipt, i as StopPayload, j as StopReceipt, k as SessionSummary } from '../piChatEvent-BsMp3MSo.js';
|
|
1
2
|
import * as react from 'react';
|
|
2
3
|
import { ComponentProps, HTMLAttributes, FormEvent, ReactNode, ComponentType } from 'react';
|
|
3
4
|
import { FileUIPart, ChatStatus, UIMessage } from 'ai';
|
|
4
|
-
import { T as ToolUiMetadata, B as BoringChatPart, a as BoringChatMessage, P as PiChatStatus, Q as QueuedUserMessage, C as ChatError, b as PiChatEvent, c as PromptPayload, d as PromptReceipt, F as FollowUpPayload, e as FollowUpReceipt, f as QueueClearPayload, g as QueueClearReceipt, I as InterruptPayload, h as CommandReceipt, i as StopPayload, j as StopReceipt, k as SessionSummary } from '../piChatEvent-BsMp3MSo.js';
|
|
5
5
|
import { InputGroupAddon, InputGroupButton, InputGroupTextarea, Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from '@hachej/boring-ui-kit';
|
|
6
6
|
import { Streamdown } from 'streamdown';
|
|
7
7
|
import { StickToBottom } from 'use-stick-to-bottom';
|
|
@@ -176,6 +176,11 @@ interface SlashCommand {
|
|
|
176
176
|
source?: 'local' | 'extension' | 'prompt' | 'skill';
|
|
177
177
|
/** Originating plugin/package name (when known), shown as a tag. */
|
|
178
178
|
sourcePlugin?: string;
|
|
179
|
+
/**
|
|
180
|
+
* Narrow browser-local escape hatch for independent controls that must remain
|
|
181
|
+
* usable while Pi is running. The predicate must admit only exact safe subcommands.
|
|
182
|
+
*/
|
|
183
|
+
allowWhileBusy?: (args: string) => boolean;
|
|
179
184
|
handler: SlashCommandHandler;
|
|
180
185
|
}
|
|
181
186
|
interface SlashCommandContext {
|
|
@@ -210,7 +215,7 @@ declare function createCommandRegistry(initial?: SlashCommand[]): CommandRegistr
|
|
|
210
215
|
|
|
211
216
|
declare const builtinCommands: SlashCommand[];
|
|
212
217
|
|
|
213
|
-
type ToolState = 'input-streaming' | 'input-available' | 'approval-requested' | 'approval-responded' | 'output-available' | 'output-error' | 'output-denied' | 'aborted';
|
|
218
|
+
type ToolState$1 = 'input-streaming' | 'input-available' | 'approval-requested' | 'approval-responded' | 'output-available' | 'output-error' | 'output-denied' | 'aborted';
|
|
214
219
|
|
|
215
220
|
type BoringToolCallPart = Extract<BoringChatPart, {
|
|
216
221
|
type: 'tool-call';
|
|
@@ -220,25 +225,25 @@ interface ToolRendererResolution {
|
|
|
220
225
|
source: 'rendererId' | 'toolName' | 'fallback';
|
|
221
226
|
requestedRendererId?: string;
|
|
222
227
|
}
|
|
223
|
-
interface ToolPart {
|
|
228
|
+
interface ToolPart$1 {
|
|
224
229
|
/** Neutral render-model type. Legacy `tool-<name>` values are accepted at the renderer boundary. */
|
|
225
230
|
type: 'tool-call' | `tool-${string}` | 'dynamic-tool';
|
|
226
231
|
toolName: string;
|
|
227
232
|
/** Stable tool call id; for Pi-native BoringChatPart this is BoringChatPart.id. */
|
|
228
233
|
toolCallId: string;
|
|
229
|
-
state: ToolState;
|
|
234
|
+
state: ToolState$1;
|
|
230
235
|
input?: unknown;
|
|
231
236
|
output?: unknown;
|
|
232
237
|
errorText?: string;
|
|
233
238
|
ui?: ToolUiMetadata;
|
|
234
239
|
rendererResolution?: ToolRendererResolution;
|
|
235
240
|
}
|
|
236
|
-
type ToolRenderablePart = ToolPart | BoringToolCallPart | unknown;
|
|
237
|
-
type ToolRenderer = (part: ToolPart) => ReactNode;
|
|
241
|
+
type ToolRenderablePart = ToolPart$1 | BoringToolCallPart | unknown;
|
|
242
|
+
type ToolRenderer = (part: ToolPart$1) => ReactNode;
|
|
238
243
|
type ToolRendererOverrides = Partial<Record<string, ToolRenderer>>;
|
|
239
244
|
declare const defaultToolRenderers: Record<string, ToolRenderer>;
|
|
240
245
|
declare function mergeToolRenderers(overrides?: ToolRendererOverrides): Record<string, ToolRenderer>;
|
|
241
|
-
declare function resolveToolRenderer(toolNameOrPart: string | ToolPart, overrides?: ToolRendererOverrides): ToolRenderer;
|
|
246
|
+
declare function resolveToolRenderer(toolNameOrPart: string | ToolPart$1, overrides?: ToolRendererOverrides): ToolRenderer;
|
|
242
247
|
|
|
243
248
|
type ChatPanelRuntimeDependenciesWarmupStatus = {
|
|
244
249
|
state: 'preparing' | 'ready' | 'failed';
|
|
@@ -770,6 +775,37 @@ interface AgentCommandOptions {
|
|
|
770
775
|
}
|
|
771
776
|
declare function getAgentCommands(options?: AgentCommandOptions): AgentCommandContribution[];
|
|
772
777
|
|
|
778
|
+
type ComposerDraftUpdate = (currentDraft: string) => string;
|
|
779
|
+
interface ComposerActionContributionProps {
|
|
780
|
+
updateDraft(update: ComposerDraftUpdate, options?: {
|
|
781
|
+
focus?: boolean;
|
|
782
|
+
}): void;
|
|
783
|
+
}
|
|
784
|
+
interface ComposerContribution {
|
|
785
|
+
id: string;
|
|
786
|
+
Top?: ComponentType;
|
|
787
|
+
Action?: ComponentType<ComposerActionContributionProps>;
|
|
788
|
+
commands?: readonly SlashCommand[];
|
|
789
|
+
}
|
|
790
|
+
declare function ComposerContributionProvider({ contribution, children, }: {
|
|
791
|
+
contribution: ComposerContribution;
|
|
792
|
+
children: ReactNode;
|
|
793
|
+
}): react.JSX.Element;
|
|
794
|
+
|
|
795
|
+
interface ChatMessageContributionProps {
|
|
796
|
+
message: BoringChatMessage;
|
|
797
|
+
}
|
|
798
|
+
interface ChatMessageContribution {
|
|
799
|
+
id: string;
|
|
800
|
+
/** Pure, hook-free claim predicate. */
|
|
801
|
+
matches(message: BoringChatMessage): boolean;
|
|
802
|
+
Component: ComponentType<ChatMessageContributionProps>;
|
|
803
|
+
}
|
|
804
|
+
declare function ChatMessageContributionProvider({ contribution, children, }: {
|
|
805
|
+
contribution: ChatMessageContribution;
|
|
806
|
+
children: ReactNode;
|
|
807
|
+
}): react.JSX.Element;
|
|
808
|
+
|
|
773
809
|
declare function mergeShadcnToolRenderers(overrides?: ToolRendererOverrides): Record<string, ToolRenderer>;
|
|
774
810
|
|
|
775
811
|
type GroupedToolEntry = {
|
|
@@ -832,6 +868,30 @@ type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
832
868
|
};
|
|
833
869
|
declare const CodeBlock: ({ code, language, showLineNumbers, className, children, ...props }: CodeBlockProps) => react.JSX.Element;
|
|
834
870
|
|
|
871
|
+
type ToolProps = ComponentProps<typeof Collapsible>;
|
|
872
|
+
declare const Tool: ({ className, ...props }: ToolProps) => react.JSX.Element;
|
|
873
|
+
type ToolState = "input-streaming" | "input-available" | "approval-requested" | "approval-responded" | "output-available" | "output-denied" | "output-error" | "aborted";
|
|
874
|
+
type ToolPart = {
|
|
875
|
+
type: `tool-${string}` | "dynamic-tool" | "tool-call";
|
|
876
|
+
state: ToolState;
|
|
877
|
+
toolName?: string;
|
|
878
|
+
input?: unknown;
|
|
879
|
+
output?: unknown;
|
|
880
|
+
errorText?: string;
|
|
881
|
+
};
|
|
882
|
+
type ToolHeaderProps = {
|
|
883
|
+
title?: ReactNode;
|
|
884
|
+
className?: string;
|
|
885
|
+
icon?: ReactNode;
|
|
886
|
+
type: ToolPart["type"];
|
|
887
|
+
state: ToolState;
|
|
888
|
+
toolName?: string;
|
|
889
|
+
statusLabel?: string;
|
|
890
|
+
};
|
|
891
|
+
declare const ToolHeader: ({ className, title, type, state, icon, toolName, statusLabel, ...props }: ToolHeaderProps) => react.JSX.Element;
|
|
892
|
+
type ToolContentProps = ComponentProps<typeof CollapsibleContent>;
|
|
893
|
+
declare const ToolContent: ({ className, ...props }: ToolContentProps) => react.JSX.Element;
|
|
894
|
+
|
|
835
895
|
declare function cn(...inputs: ClassValue[]): string;
|
|
836
896
|
|
|
837
|
-
export { type AgentCommandContribution, type AgentCommandOptions, type AgentPluginReloadResult, ArtifactOpenProvider, type AvailableModel, ChatEmptyState, type ChatEmptyStateProps, PiChatPanel as ChatPanel, type PiChatPanelProps as ChatPanelProps, type ChatSuggestion, CodeBlock, type CommandRegistry, type ComposerBlocker, type ComposerBlockerAction, Conversation, ConversationContent, ConversationScrollButton, DebugDrawer, type GroupedToolEntry, Message, MessageAction, MessageActions, MessageContent, MessageResponse, ModelPickerMenu, ModelSelect, ModelSelectTrigger, type ModelSelection, type OpenArtifactHandler, type ParsedCommand, PiChatPanel, type PiChatPanelProps, SessionBrowser as PiSessionBrowser, type PiSessionCreateInit, SessionList as PiSessionList, type PiSessionSearchItem, type PiSessionSearchOptions, type PiSessionSearchSortMode, PromptInput, PromptInputFooter, PromptInputSubmit, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, type SessionListProps, type SlashCommand, type SlashCommandContext, type ThinkingLevel, ThinkingSelect, ToolCallGroup, type ToolPart, type ToolRenderer, type ToolRendererOverrides, type UploadFileOptions, type UploadFileResult, type UsePiSessionsOptions, type UsePiSessionsResult, activeSessionStorageKey, builtinCommands, clearActiveSessionId, cn, createCommandRegistry, defaultChatSuggestions, defaultToolRenderers, getAgentCommands, matchPiSessionSearch, mergeShadcnToolRenderers, mergeToolRenderers, parsePiSessionSearchQuery, parseSlashCommand, readActiveSessionId, resolveToolRenderer, searchPiSessions, uploadFile, useOpenArtifact, usePiSessions, writeActiveSessionId };
|
|
897
|
+
export { type AgentCommandContribution, type AgentCommandOptions, type AgentPluginReloadResult, ArtifactOpenProvider, type AvailableModel, BoringChatMessage, ChatEmptyState, type ChatEmptyStateProps, type ChatMessageContribution, type ChatMessageContributionProps, ChatMessageContributionProvider, PiChatPanel as ChatPanel, type PiChatPanelProps as ChatPanelProps, type ChatSuggestion, CodeBlock, type CommandRegistry, type ComposerActionContributionProps, type ComposerBlocker, type ComposerBlockerAction, type ComposerContribution, ComposerContributionProvider, type ComposerDraftUpdate, Conversation, ConversationContent, ConversationScrollButton, DebugDrawer, type GroupedToolEntry, Message, MessageAction, MessageActions, MessageContent, MessageResponse, ModelPickerMenu, ModelSelect, ModelSelectTrigger, type ModelSelection, type OpenArtifactHandler, type ParsedCommand, PiChatPanel, type PiChatPanelProps, SessionBrowser as PiSessionBrowser, type PiSessionCreateInit, SessionList as PiSessionList, type PiSessionSearchItem, type PiSessionSearchOptions, type PiSessionSearchSortMode, PromptInput, PromptInputFooter, PromptInputSubmit, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, type SessionListProps, type SlashCommand, type SlashCommandContext, type ThinkingLevel, ThinkingSelect, Tool, ToolCallGroup, ToolContent, ToolHeader, type ToolPart$1 as ToolPart, type ToolRenderer, type ToolRendererOverrides, type UploadFileOptions, type UploadFileResult, type UsePiSessionsOptions, type UsePiSessionsResult, activeSessionStorageKey, builtinCommands, clearActiveSessionId, cn, createCommandRegistry, defaultChatSuggestions, defaultToolRenderers, getAgentCommands, matchPiSessionSearch, mergeShadcnToolRenderers, mergeToolRenderers, parsePiSessionSearchQuery, parseSlashCommand, readActiveSessionId, resolveToolRenderer, searchPiSessions, uploadFile, useOpenArtifact, usePiSessions, writeActiveSessionId };
|