@hachej/boring-agent 0.1.93 → 0.1.95
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-4TKUT7IL.js → chunk-2EMAKBVR.js} +272 -75
- package/dist/{chunk-CJ2BW2W2.js → chunk-EOMY2HDT.js} +1 -0
- 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 +71 -9
- package/dist/front/index.js +931 -881
- package/dist/front/styles.css +261 -172
- 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 +45 -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
|
@@ -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,
|
|
@@ -4077,12 +4077,22 @@ var HarnessPiChatService = class {
|
|
|
4077
4077
|
}
|
|
4078
4078
|
async readStateBeforeDispose(ctx, sessionId) {
|
|
4079
4079
|
const sessionKey2 = this.sessionKey(ctx, sessionId);
|
|
4080
|
-
|
|
4080
|
+
let channel = this.channels.get(sessionKey2);
|
|
4081
4081
|
if (!channel && !this.harnessMayHaveLiveSession(ctx, sessionId)) {
|
|
4082
4082
|
const persisted = await this.readPersistedState(ctx, sessionId);
|
|
4083
|
-
|
|
4083
|
+
channel = this.channels.get(sessionKey2);
|
|
4084
|
+
if (persisted && !channel && !this.harnessMayHaveLiveSession(ctx, sessionId)) return persisted;
|
|
4084
4085
|
}
|
|
4085
4086
|
const adapter = await this.getAdapter(ctx, sessionId, "");
|
|
4087
|
+
if (this.canRefreshFromPersistedState(sessionKey2, adapter)) {
|
|
4088
|
+
const persisted = await this.readPersistedState(ctx, sessionId);
|
|
4089
|
+
if (persisted && this.canRefreshFromPersistedState(sessionKey2, adapter)) {
|
|
4090
|
+
return this.enrichSyntheticPromptFailures(
|
|
4091
|
+
sessionKey2,
|
|
4092
|
+
this.messageMetadata.enrichSnapshot(sessionKey2, persisted)
|
|
4093
|
+
);
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4086
4096
|
const snapshot = this.messageMetadata.enrichSnapshot(sessionKey2, buildPiChatSnapshot(adapter, {
|
|
4087
4097
|
seq: channel?.buffer.latestSeq ?? 0,
|
|
4088
4098
|
sessionId,
|
|
@@ -4091,6 +4101,11 @@ var HarnessPiChatService = class {
|
|
|
4091
4101
|
}));
|
|
4092
4102
|
return this.enrichSyntheticPromptFailures(sessionKey2, snapshot);
|
|
4093
4103
|
}
|
|
4104
|
+
canRefreshFromPersistedState(sessionKey2, adapter) {
|
|
4105
|
+
if (this.activePromptRuns.has(sessionKey2)) return false;
|
|
4106
|
+
const snapshot = adapter.readSnapshot();
|
|
4107
|
+
return !snapshot.isStreaming && !snapshot.isRetrying && snapshot.pendingMessageCount === 0 && snapshot.steeringMessages.length === 0 && snapshot.followUpMessages.length === 0;
|
|
4108
|
+
}
|
|
4094
4109
|
harnessMayHaveLiveSession(ctx, sessionId) {
|
|
4095
4110
|
return typeof this.harness.hasPiSession === "function" ? this.harness.hasPiSession(sessionId, toSessionCtx(ctx)) : true;
|
|
4096
4111
|
}
|
|
@@ -4605,6 +4620,18 @@ var HarnessPiChatService = class {
|
|
|
4605
4620
|
const seq = envelope?.chunk?.seq;
|
|
4606
4621
|
return typeof seq === "number" && Number.isInteger(seq) && seq >= 0 ? seq : tailIndex + 1;
|
|
4607
4622
|
}
|
|
4623
|
+
/**
|
|
4624
|
+
* Validate the persisted session identity and instantiate its lazily-created
|
|
4625
|
+
* Pi adapter under the same full cache key. This is intentionally a narrow
|
|
4626
|
+
* trusted-host seam rather than another browser route.
|
|
4627
|
+
*/
|
|
4628
|
+
async ensurePiSessionBound(ctx, sessionId) {
|
|
4629
|
+
this.lifecycle.assertOpen();
|
|
4630
|
+
await this.assertCanAccessSession(ctx, sessionId);
|
|
4631
|
+
const adapter = await this.getAdapter(ctx, sessionId, "", { authorize: false });
|
|
4632
|
+
await this.ensureChannel(ctx, sessionId, adapter);
|
|
4633
|
+
this.lifecycle.assertOpen();
|
|
4634
|
+
}
|
|
4608
4635
|
async assertCanAccessSession(ctx, sessionId) {
|
|
4609
4636
|
try {
|
|
4610
4637
|
await this.sessionStore.load(toSessionCtx(ctx), sessionId);
|
|
@@ -7311,7 +7338,16 @@ var EmbeddedAgentGateway = class {
|
|
|
7311
7338
|
});
|
|
7312
7339
|
this.runtime.activity.set(claim.workspaceScopeId, ref, "running");
|
|
7313
7340
|
return { ...receipt, disposition: "prompt" };
|
|
7314
|
-
},
|
|
7341
|
+
}, {
|
|
7342
|
+
duplicateReceipt: true,
|
|
7343
|
+
guard: async () => await this.promptAdmission(
|
|
7344
|
+
scope,
|
|
7345
|
+
claim,
|
|
7346
|
+
ref,
|
|
7347
|
+
command.requestId,
|
|
7348
|
+
command.requireIdle === true
|
|
7349
|
+
)
|
|
7350
|
+
});
|
|
7315
7351
|
}
|
|
7316
7352
|
return await this.sessionEffect(ref, claim, "session.followup", command.requestId, command, async () => {
|
|
7317
7353
|
const receipt = await service.followUp(context(claim, command.requestId), ref.sessionId, {
|
|
@@ -7321,7 +7357,7 @@ var EmbeddedAgentGateway = class {
|
|
|
7321
7357
|
clientSeq: command.clientSeq
|
|
7322
7358
|
});
|
|
7323
7359
|
return { ...receipt, disposition: "followup" };
|
|
7324
|
-
}, true);
|
|
7360
|
+
}, { duplicateReceipt: true });
|
|
7325
7361
|
}
|
|
7326
7362
|
async renameSession(input) {
|
|
7327
7363
|
const claim = await this.verify(input.scope);
|
|
@@ -7395,16 +7431,18 @@ var EmbeddedAgentGateway = class {
|
|
|
7395
7431
|
if (!summary) throw new AgentGatewayError(AgentGatewayErrorCode.AGENT_SESSION_NOT_FOUND, "session was not found");
|
|
7396
7432
|
return summary;
|
|
7397
7433
|
}
|
|
7398
|
-
sessionEffect(ref, claim, operation, requestId, payload, action,
|
|
7434
|
+
sessionEffect(ref, claim, operation, requestId, payload, action, options = {}) {
|
|
7399
7435
|
return this.effect(
|
|
7400
7436
|
claim,
|
|
7401
7437
|
operation,
|
|
7402
7438
|
sessionTarget(ref),
|
|
7403
7439
|
requestId,
|
|
7404
7440
|
payload,
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7441
|
+
action,
|
|
7442
|
+
{
|
|
7443
|
+
...options,
|
|
7444
|
+
serialize: (effect) => this.withWriter(claim.workspaceScopeId, ref, effect)
|
|
7445
|
+
}
|
|
7408
7446
|
);
|
|
7409
7447
|
}
|
|
7410
7448
|
/** Internal legacy-alias seam; never exposed through the public Gateway contract. */
|
|
@@ -7419,8 +7457,7 @@ var EmbeddedAgentGateway = class {
|
|
|
7419
7457
|
input.requestId,
|
|
7420
7458
|
input.payload,
|
|
7421
7459
|
input.action,
|
|
7422
|
-
|
|
7423
|
-
true
|
|
7460
|
+
{ legacyAlias: true }
|
|
7424
7461
|
);
|
|
7425
7462
|
}
|
|
7426
7463
|
if (input.target.kind !== "session") throw new TypeError(`${input.operation} requires a session target`);
|
|
@@ -7431,12 +7468,20 @@ var EmbeddedAgentGateway = class {
|
|
|
7431
7468
|
input.requestId,
|
|
7432
7469
|
input.payload,
|
|
7433
7470
|
input.action,
|
|
7434
|
-
|
|
7435
|
-
|
|
7471
|
+
{
|
|
7472
|
+
legacyAlias: true,
|
|
7473
|
+
guard: input.retryableGuard
|
|
7474
|
+
}
|
|
7436
7475
|
);
|
|
7437
7476
|
}
|
|
7438
|
-
async effect(claim, operation, target, requestId, payload, action,
|
|
7477
|
+
async effect(claim, operation, target, requestId, payload, action, options = {}) {
|
|
7439
7478
|
this.assertOpen();
|
|
7479
|
+
const {
|
|
7480
|
+
duplicateReceipt = false,
|
|
7481
|
+
legacyAlias = false,
|
|
7482
|
+
serialize,
|
|
7483
|
+
guard
|
|
7484
|
+
} = options;
|
|
7440
7485
|
const key = {
|
|
7441
7486
|
workspaceScopeId: claim.workspaceScopeId,
|
|
7442
7487
|
authSubjectId: claim.authSubjectId,
|
|
@@ -7452,8 +7497,9 @@ var EmbeddedAgentGateway = class {
|
|
|
7452
7497
|
const id = requestKeyString(key);
|
|
7453
7498
|
const existing = this.effects.get(id);
|
|
7454
7499
|
if (existing) return this.replayReceipt(await existing, duplicateReceipt);
|
|
7455
|
-
const
|
|
7500
|
+
const execute = async () => {
|
|
7456
7501
|
const current = await this.runtime.ledger.read(key);
|
|
7502
|
+
let admissionReceipt;
|
|
7457
7503
|
if (current?.state === "pending-admission") {
|
|
7458
7504
|
const admission = await this.runtime.effectAdmission.admit({ key, digest: digest2, scope: claim, operation, target });
|
|
7459
7505
|
if (admission.type === "retryable") throw gatewayError(admission.error);
|
|
@@ -7461,71 +7507,87 @@ var EmbeddedAgentGateway = class {
|
|
|
7461
7507
|
await this.runtime.ledger.reject(key, { kind: "gateway", error: admission.error });
|
|
7462
7508
|
throw gatewayError(admission.error);
|
|
7463
7509
|
}
|
|
7464
|
-
|
|
7465
|
-
}
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7510
|
+
admissionReceipt = admission.admissionReceipt;
|
|
7511
|
+
}
|
|
7512
|
+
const runEffect = async () => {
|
|
7513
|
+
const locked = await this.runtime.ledger.read(key);
|
|
7514
|
+
if (locked?.state === "pending-admission") {
|
|
7515
|
+
if (admissionReceipt === void 0) {
|
|
7516
|
+
throw new AgentGatewayError(
|
|
7517
|
+
AgentGatewayErrorCode.AGENT_REQUEST_OUTCOME_UNKNOWN,
|
|
7518
|
+
"request admission receipt was unavailable"
|
|
7519
|
+
);
|
|
7520
|
+
}
|
|
7521
|
+
const retryableGuardError = await guard?.();
|
|
7522
|
+
if (retryableGuardError) throw gatewayError(retryableGuardError);
|
|
7523
|
+
await this.runtime.ledger.acceptAdmission(key, admissionReceipt);
|
|
7524
|
+
}
|
|
7525
|
+
await this.runtime.ledger.beginEffect(key);
|
|
7526
|
+
let actionResult;
|
|
7527
|
+
try {
|
|
7528
|
+
actionResult = action();
|
|
7529
|
+
} catch (error) {
|
|
7530
|
+
if (legacyAlias) {
|
|
7531
|
+
if (error instanceof AgentEffectAdmissionError) {
|
|
7532
|
+
const details = projectJson(error.details);
|
|
7533
|
+
const failure2 = {
|
|
7534
|
+
kind: "legacy-admission",
|
|
7535
|
+
code: error.code,
|
|
7536
|
+
statusCode: 500,
|
|
7537
|
+
message: error.message,
|
|
7538
|
+
...details === void 0 ? {} : { details }
|
|
7539
|
+
};
|
|
7540
|
+
await this.runtime.ledger.reject(key, failure2);
|
|
7541
|
+
throw this.failure(failure2, true);
|
|
7542
|
+
}
|
|
7543
|
+
const failure = legacyServiceFailure(error);
|
|
7544
|
+
await this.runtime.ledger.reject(key, failure);
|
|
7545
|
+
throw this.failure(failure, true);
|
|
7546
|
+
}
|
|
7547
|
+
const unknown = new AgentGatewayError(
|
|
7548
|
+
AgentGatewayErrorCode.AGENT_REQUEST_OUTCOME_UNKNOWN,
|
|
7549
|
+
"effect outcome could not be safely replayed"
|
|
7550
|
+
);
|
|
7551
|
+
await this.runtime.ledger.markOutcomeUnknown(key, unknown.toJSON()).catch(() => {
|
|
7552
|
+
});
|
|
7553
|
+
throw error;
|
|
7554
|
+
}
|
|
7555
|
+
try {
|
|
7556
|
+
const receipt = await actionResult;
|
|
7557
|
+
this.runtime.assertOpen();
|
|
7558
|
+
await this.runtime.ledger.complete(key, receipt);
|
|
7559
|
+
return receipt;
|
|
7560
|
+
} catch (error) {
|
|
7561
|
+
if (legacyAlias && error instanceof AgentEffectAdmissionError) {
|
|
7473
7562
|
const details = projectJson(error.details);
|
|
7474
|
-
const
|
|
7563
|
+
const failure = {
|
|
7475
7564
|
kind: "legacy-admission",
|
|
7476
7565
|
code: error.code,
|
|
7477
7566
|
statusCode: 500,
|
|
7478
7567
|
message: error.message,
|
|
7479
7568
|
...details === void 0 ? {} : { details }
|
|
7480
7569
|
};
|
|
7481
|
-
await this.runtime.ledger.reject(key,
|
|
7482
|
-
throw this.failure(
|
|
7570
|
+
await this.runtime.ledger.reject(key, failure);
|
|
7571
|
+
throw this.failure(failure, true);
|
|
7483
7572
|
}
|
|
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);
|
|
7573
|
+
if (legacyAlias && (isObservedSynchronousServiceError(error) || isKnownLegacyServiceFailure(error))) {
|
|
7574
|
+
const failure = legacyServiceFailure(error);
|
|
7575
|
+
await this.runtime.ledger.reject(key, failure);
|
|
7576
|
+
throw this.failure(failure, true);
|
|
7577
|
+
}
|
|
7578
|
+
const unknown = new AgentGatewayError(
|
|
7579
|
+
AgentGatewayErrorCode.AGENT_REQUEST_OUTCOME_UNKNOWN,
|
|
7580
|
+
"effect outcome could not be safely replayed"
|
|
7581
|
+
);
|
|
7582
|
+
await this.runtime.ledger.markOutcomeUnknown(key, unknown.toJSON()).catch(() => {
|
|
7583
|
+
});
|
|
7584
|
+
if (legacyAlias) throw unknown;
|
|
7585
|
+
throw error;
|
|
7518
7586
|
}
|
|
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);
|
|
7587
|
+
};
|
|
7588
|
+
return serialize ? serialize(runEffect) : runEffect();
|
|
7589
|
+
};
|
|
7590
|
+
const running = this.runtime.trackEffect(execute(), key);
|
|
7529
7591
|
this.effects.set(id, running);
|
|
7530
7592
|
try {
|
|
7531
7593
|
return await running;
|
|
@@ -7558,6 +7620,20 @@ var EmbeddedAgentGateway = class {
|
|
|
7558
7620
|
"effect admission was rejected"
|
|
7559
7621
|
);
|
|
7560
7622
|
}
|
|
7623
|
+
async promptAdmission(scope, claim, ref, requestId, requireIdle) {
|
|
7624
|
+
const binding = await this.bindingForSession(scope, claim, ref);
|
|
7625
|
+
const snapshot = await binding.composition.service.readState(
|
|
7626
|
+
context(claim, requestId, binding.scope.identity),
|
|
7627
|
+
ref.sessionId
|
|
7628
|
+
);
|
|
7629
|
+
const admissible = requireIdle ? snapshot.status === "idle" : snapshot.status === "idle" || snapshot.status === "error";
|
|
7630
|
+
if (admissible) return void 0;
|
|
7631
|
+
return new AgentGatewayError(
|
|
7632
|
+
AgentGatewayErrorCode.AGENT_COMMAND_INVALID_STATE,
|
|
7633
|
+
requireIdle ? "session is not idle" : "prompt is invalid in current state",
|
|
7634
|
+
{ status: snapshot.status }
|
|
7635
|
+
).toJSON();
|
|
7636
|
+
}
|
|
7561
7637
|
async withWriter(workspaceScopeId, ref, action) {
|
|
7562
7638
|
const key = sessionKey(workspaceScopeId, ref);
|
|
7563
7639
|
const previous = this.writerTails.get(key) ?? Promise.resolve();
|
|
@@ -8167,6 +8243,7 @@ var PromptBodySchema = z4.object({
|
|
|
8167
8243
|
clientNonce: NonEmptyString.max(128),
|
|
8168
8244
|
content: NonEmptyString.max(1e6),
|
|
8169
8245
|
displayContent: NonEmptyString.max(1e6).optional(),
|
|
8246
|
+
requireIdle: z4.literal(true).optional(),
|
|
8170
8247
|
model: ChatModelSelectionSchema.optional(),
|
|
8171
8248
|
thinkingLevel: z4.enum(["off", "low", "medium", "high"]).optional(),
|
|
8172
8249
|
attachments: z4.array(ChatAttachmentPayloadSchema).max(20).optional()
|
|
@@ -8486,7 +8563,8 @@ function createLegacyPiChatCompatibilityService(input) {
|
|
|
8486
8563
|
target: options.target,
|
|
8487
8564
|
requestId: options.requestId,
|
|
8488
8565
|
payload: jsonProjection(options.payload),
|
|
8489
|
-
action: options.action
|
|
8566
|
+
action: options.action,
|
|
8567
|
+
...options.retryableGuard ? { retryableGuard: options.retryableGuard } : {}
|
|
8490
8568
|
});
|
|
8491
8569
|
return {
|
|
8492
8570
|
...input.service.listSessions ? { listSessions: (ctx, options) => input.service.listSessions(ctx, options) } : {},
|
|
@@ -8517,6 +8595,17 @@ function createLegacyPiChatCompatibilityService(input) {
|
|
|
8517
8595
|
target: sessionTarget2(input.agentTypeId, sessionId),
|
|
8518
8596
|
requestId: requestIdForPayload(ctx, payload.clientNonce),
|
|
8519
8597
|
payload,
|
|
8598
|
+
...payload.requireIdle ? {
|
|
8599
|
+
retryableGuard: async () => {
|
|
8600
|
+
const snapshot = await input.service.readState(ctx, sessionId);
|
|
8601
|
+
if (snapshot.status === "idle") return void 0;
|
|
8602
|
+
return new AgentGatewayError(
|
|
8603
|
+
AgentGatewayErrorCode.AGENT_COMMAND_INVALID_STATE,
|
|
8604
|
+
"session is not idle",
|
|
8605
|
+
{ status: snapshot.status }
|
|
8606
|
+
).toJSON();
|
|
8607
|
+
}
|
|
8608
|
+
} : {},
|
|
8520
8609
|
action: () => input.service.prompt(ctx, sessionId, payload)
|
|
8521
8610
|
}),
|
|
8522
8611
|
followUp: (ctx, sessionId, payload) => effect({
|
|
@@ -9732,7 +9821,7 @@ async function dispatchGatewayInput(binding, input) {
|
|
|
9732
9821
|
scope: binding.scope,
|
|
9733
9822
|
agentTypeId: binding.agentTypeId,
|
|
9734
9823
|
requestId,
|
|
9735
|
-
title: contentToText(input.content ?? input.message).slice(0, 80) || void 0
|
|
9824
|
+
title: input.title?.trim() || contentToText(input.content ?? input.message).slice(0, 80) || void 0
|
|
9736
9825
|
});
|
|
9737
9826
|
const connection = await binding.gateway.connectSession({
|
|
9738
9827
|
scope: binding.scope,
|
|
@@ -10897,6 +10986,75 @@ async function mountOrderedAgentHostLegacyRoutes(input) {
|
|
|
10897
10986
|
);
|
|
10898
10987
|
}
|
|
10899
10988
|
|
|
10989
|
+
// src/server/trustedPiSessionBinding.ts
|
|
10990
|
+
async function bindTrustedPiSession(input) {
|
|
10991
|
+
const sessionContext = trustedPiSessionContext(input.ctx, input.request, input.requested);
|
|
10992
|
+
await input.withServices(async ({ binding }) => {
|
|
10993
|
+
if (!binding.ensurePiSessionBound) {
|
|
10994
|
+
throw createWorkspaceAgentDispatcherError(
|
|
10995
|
+
ErrorCode.enum.INTERNAL_ERROR,
|
|
10996
|
+
"Pi session binding is unavailable",
|
|
10997
|
+
500
|
|
10998
|
+
);
|
|
10999
|
+
}
|
|
11000
|
+
return await binding.ensurePiSessionBound(sessionContext, input.sessionId);
|
|
11001
|
+
});
|
|
11002
|
+
return {
|
|
11003
|
+
visibleUserMessageTarget: {
|
|
11004
|
+
async isIdle() {
|
|
11005
|
+
return await input.withServices(async ({ binding }) => {
|
|
11006
|
+
const snapshot = await binding.readState(sessionContext, input.sessionId);
|
|
11007
|
+
return snapshot.status === "idle";
|
|
11008
|
+
});
|
|
11009
|
+
},
|
|
11010
|
+
async sendIfIdle(sendInput) {
|
|
11011
|
+
const requestId = sendInput.requestId.trim();
|
|
11012
|
+
if (!requestId) throw new TypeError("requestId must be a non-empty string");
|
|
11013
|
+
try {
|
|
11014
|
+
const receipt = await input.withServices(async ({ prompt }) => await prompt.prompt(
|
|
11015
|
+
sessionContext,
|
|
11016
|
+
input.sessionId,
|
|
11017
|
+
{
|
|
11018
|
+
message: sendInput.message,
|
|
11019
|
+
displayMessage: sendInput.displayMessage ?? sendInput.message,
|
|
11020
|
+
clientNonce: requestId,
|
|
11021
|
+
requireIdle: true
|
|
11022
|
+
}
|
|
11023
|
+
));
|
|
11024
|
+
return {
|
|
11025
|
+
status: "accepted",
|
|
11026
|
+
cursor: receipt.cursor,
|
|
11027
|
+
...receipt.duplicate ? { duplicate: true } : {}
|
|
11028
|
+
};
|
|
11029
|
+
} catch (error) {
|
|
11030
|
+
if (error instanceof AgentGatewayError && error.code === AgentGatewayErrorCode.AGENT_COMMAND_INVALID_STATE) {
|
|
11031
|
+
return { status: "busy" };
|
|
11032
|
+
}
|
|
11033
|
+
if (isGoneSessionError(error)) return { status: "gone" };
|
|
11034
|
+
throw error;
|
|
11035
|
+
}
|
|
11036
|
+
}
|
|
11037
|
+
}
|
|
11038
|
+
};
|
|
11039
|
+
}
|
|
11040
|
+
function isGoneSessionError(error) {
|
|
11041
|
+
const code = error?.code;
|
|
11042
|
+
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;
|
|
11043
|
+
}
|
|
11044
|
+
function trustedPiSessionContext(ctx, request, requested) {
|
|
11045
|
+
if (requested?.workspaceId && requested.workspaceId !== ctx.workspaceId) {
|
|
11046
|
+
throw createWorkspaceAgentDispatcherError(ErrorCode.enum.UNAUTHORIZED, "Pi session workspace context mismatch", 401);
|
|
11047
|
+
}
|
|
11048
|
+
if (requested?.userId && requested.userId !== ctx.userId) {
|
|
11049
|
+
throw createWorkspaceAgentDispatcherError(ErrorCode.enum.UNAUTHORIZED, "Pi session user context mismatch", 401);
|
|
11050
|
+
}
|
|
11051
|
+
return {
|
|
11052
|
+
workspaceId: requested?.workspaceId ?? ctx.workspaceId,
|
|
11053
|
+
authSubject: requested?.userId ?? ctx.userId,
|
|
11054
|
+
requestId: request?.id ?? `trusted:${ctx.workspaceId}:${ctx.userId}`
|
|
11055
|
+
};
|
|
11056
|
+
}
|
|
11057
|
+
|
|
10900
11058
|
// src/server/agentHostLegacyRouteRuntime.ts
|
|
10901
11059
|
var DEFAULT_WORKSPACE_ID6 = "default";
|
|
10902
11060
|
var STANDARD_AGENT_TOOL_NAMES = ["bash", "read", "write", "edit", "find", "grep", "ls"];
|
|
@@ -11391,6 +11549,11 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11391
11549
|
tools,
|
|
11392
11550
|
readyTracker,
|
|
11393
11551
|
piChatService: composition.service,
|
|
11552
|
+
trustedPiChatService: agentHost.createPiChatService({
|
|
11553
|
+
service: composition.service,
|
|
11554
|
+
scope: authorizedScope,
|
|
11555
|
+
agentTypeId: defaultAgentTypeId
|
|
11556
|
+
}),
|
|
11394
11557
|
authorizedScope,
|
|
11395
11558
|
hostScope
|
|
11396
11559
|
};
|
|
@@ -11526,6 +11689,7 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11526
11689
|
throw error;
|
|
11527
11690
|
}
|
|
11528
11691
|
return {
|
|
11692
|
+
binding,
|
|
11529
11693
|
dispatcher: createBoundWorkspaceAgentDispatcher({
|
|
11530
11694
|
gateway: agentHost.gateway,
|
|
11531
11695
|
scope: binding.authorizedScope,
|
|
@@ -11538,6 +11702,25 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11538
11702
|
binding = await getOrCreateRuntimeBinding(boundCtx.workspaceId, void 0, { trustedCtx: boundCtx });
|
|
11539
11703
|
}
|
|
11540
11704
|
}
|
|
11705
|
+
async function ensureTrustedPiSessionBound(initialBinding, boundCtx, boundSessionId, request, requestedSessionCtx) {
|
|
11706
|
+
return await bindTrustedPiSession({
|
|
11707
|
+
ctx: boundCtx,
|
|
11708
|
+
request,
|
|
11709
|
+
sessionId: boundSessionId,
|
|
11710
|
+
requested: requestedSessionCtx,
|
|
11711
|
+
withServices: async (effect) => {
|
|
11712
|
+
const operation = await acquireDispatcherOperation(initialBinding, boundCtx, request);
|
|
11713
|
+
try {
|
|
11714
|
+
return await effect({
|
|
11715
|
+
binding: operation.binding.piChatService,
|
|
11716
|
+
prompt: operation.binding.trustedPiChatService
|
|
11717
|
+
});
|
|
11718
|
+
} finally {
|
|
11719
|
+
operation.release();
|
|
11720
|
+
}
|
|
11721
|
+
}
|
|
11722
|
+
});
|
|
11723
|
+
}
|
|
11541
11724
|
function createLeasedWorkspaceAgentDispatcher(initialBinding, boundCtx, request) {
|
|
11542
11725
|
return {
|
|
11543
11726
|
async dispatch(input) {
|
|
@@ -11616,14 +11799,28 @@ async function mountAgentHostLegacyRouteRuntime(app, opts, mountInput, scopePoli
|
|
|
11616
11799
|
}
|
|
11617
11800
|
return {
|
|
11618
11801
|
dispatcher: createLeasedWorkspaceAgentDispatcher(staticBinding, boundCtx, options?.request),
|
|
11619
|
-
workspace: staticBinding.runtimeBundle.workspace
|
|
11802
|
+
workspace: staticBinding.runtimeBundle.workspace,
|
|
11803
|
+
bindPiSession: async (boundSessionId, requestedSessionCtx) => await ensureTrustedPiSessionBound(
|
|
11804
|
+
staticBinding,
|
|
11805
|
+
boundCtx,
|
|
11806
|
+
boundSessionId,
|
|
11807
|
+
options?.request,
|
|
11808
|
+
requestedSessionCtx
|
|
11809
|
+
)
|
|
11620
11810
|
};
|
|
11621
11811
|
}
|
|
11622
11812
|
const binding = await getOrCreateRuntimeBinding(boundCtx.workspaceId, options?.request, { trustedCtx: boundCtx });
|
|
11623
11813
|
bindingLifecycle.assertAdmission(boundCtx.workspaceId, options?.request);
|
|
11624
11814
|
return {
|
|
11625
11815
|
dispatcher: createLeasedWorkspaceAgentDispatcher(binding, boundCtx, options?.request),
|
|
11626
|
-
workspace: binding.runtimeBundle.workspace
|
|
11816
|
+
workspace: binding.runtimeBundle.workspace,
|
|
11817
|
+
bindPiSession: async (boundSessionId, requestedSessionCtx) => await ensureTrustedPiSessionBound(
|
|
11818
|
+
binding,
|
|
11819
|
+
boundCtx,
|
|
11820
|
+
boundSessionId,
|
|
11821
|
+
options?.request,
|
|
11822
|
+
requestedSessionCtx
|
|
11823
|
+
)
|
|
11627
11824
|
};
|
|
11628
11825
|
}
|
|
11629
11826
|
});
|
|
@@ -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);
|
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[];
|