agentbox-sdk 0.1.303 → 0.1.304
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/agents/index.js
CHANGED
|
@@ -426,7 +426,9 @@ var ClaudeCodeLogAssembler = class {
|
|
|
426
426
|
}
|
|
427
427
|
const final = extractClaudeAssistantContent(message);
|
|
428
428
|
this.textByMessageId.set(id, final.text);
|
|
429
|
-
|
|
429
|
+
if (final.thinking) {
|
|
430
|
+
this.thinkingByMessageId.set(id, final.thinking);
|
|
431
|
+
}
|
|
430
432
|
const snapshot = this.upsertMessage(id, final.extraBlocks);
|
|
431
433
|
this.currentMessageId = null;
|
|
432
434
|
return [snapshot];
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createNormalizedEvent,
|
|
3
3
|
normalizeRawAgentEvent,
|
|
4
4
|
toAISDKStream
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EK6GC6YA.js";
|
|
6
6
|
import {
|
|
7
7
|
AgentBoxError,
|
|
8
8
|
AsyncQueue,
|
|
@@ -2504,6 +2504,31 @@ async function* streamSse(url, init) {
|
|
|
2504
2504
|
})();
|
|
2505
2505
|
yield* queue;
|
|
2506
2506
|
}
|
|
2507
|
+
async function* streamSseResilient(url, init) {
|
|
2508
|
+
let lastEventId;
|
|
2509
|
+
let attempt = 0;
|
|
2510
|
+
const signal = init?.signal;
|
|
2511
|
+
while (true) {
|
|
2512
|
+
try {
|
|
2513
|
+
const headers = {
|
|
2514
|
+
...init?.headers ?? {},
|
|
2515
|
+
...lastEventId ? { "Last-Event-ID": lastEventId } : {}
|
|
2516
|
+
};
|
|
2517
|
+
for await (const ev of streamSse(url, { ...init, headers })) {
|
|
2518
|
+
attempt = 0;
|
|
2519
|
+
if (ev.id) lastEventId = ev.id;
|
|
2520
|
+
yield ev;
|
|
2521
|
+
}
|
|
2522
|
+
return;
|
|
2523
|
+
} catch (err) {
|
|
2524
|
+
if (signal?.aborted) throw err;
|
|
2525
|
+
const delay = Math.min(500 * Math.pow(2, attempt), 5e3);
|
|
2526
|
+
attempt++;
|
|
2527
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2528
|
+
if (signal?.aborted) throw err;
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2507
2532
|
async function connectJsonRpcWebSocket(url, options) {
|
|
2508
2533
|
const notifications = new AsyncQueue();
|
|
2509
2534
|
const socket = new WebSocket(url, { headers: options?.headers });
|
|
@@ -3540,7 +3565,7 @@ var CodexAgentAdapter = class {
|
|
|
3540
3565
|
Date.now() - executeStartedAt,
|
|
3541
3566
|
text?.length ?? 0
|
|
3542
3567
|
);
|
|
3543
|
-
sink.complete({
|
|
3568
|
+
sink.complete({ costData: extractCodexCostData(rawPayloads) });
|
|
3544
3569
|
}
|
|
3545
3570
|
}
|
|
3546
3571
|
} finally {
|
|
@@ -3638,73 +3663,6 @@ function toRawEvent3(runId, payload, type) {
|
|
|
3638
3663
|
payload
|
|
3639
3664
|
};
|
|
3640
3665
|
}
|
|
3641
|
-
function extractText(value) {
|
|
3642
|
-
if (!value) {
|
|
3643
|
-
return "";
|
|
3644
|
-
}
|
|
3645
|
-
if (typeof value === "string") {
|
|
3646
|
-
return value;
|
|
3647
|
-
}
|
|
3648
|
-
if (Array.isArray(value)) {
|
|
3649
|
-
return value.map(extractText).filter(Boolean).join("");
|
|
3650
|
-
}
|
|
3651
|
-
if (typeof value === "object") {
|
|
3652
|
-
const record = value;
|
|
3653
|
-
if (record.type === "text" && typeof record.text === "string") {
|
|
3654
|
-
return record.text;
|
|
3655
|
-
}
|
|
3656
|
-
if (record.type === "reasoning") {
|
|
3657
|
-
return "";
|
|
3658
|
-
}
|
|
3659
|
-
if (record.message) {
|
|
3660
|
-
return extractText(record.message);
|
|
3661
|
-
}
|
|
3662
|
-
if (record.content) {
|
|
3663
|
-
return extractText(record.content);
|
|
3664
|
-
}
|
|
3665
|
-
if (record.parts) {
|
|
3666
|
-
return extractText(record.parts);
|
|
3667
|
-
}
|
|
3668
|
-
if (record.text) {
|
|
3669
|
-
return extractText(record.text);
|
|
3670
|
-
}
|
|
3671
|
-
}
|
|
3672
|
-
return "";
|
|
3673
|
-
}
|
|
3674
|
-
function extractAssistantMessageId(response) {
|
|
3675
|
-
if (!response || typeof response !== "object") {
|
|
3676
|
-
return void 0;
|
|
3677
|
-
}
|
|
3678
|
-
const record = response;
|
|
3679
|
-
const info = record.info && typeof record.info === "object" ? record.info : record.message && typeof record.message === "object" ? record.message : void 0;
|
|
3680
|
-
const id = info?.id ?? record.id;
|
|
3681
|
-
return typeof id === "string" ? id : void 0;
|
|
3682
|
-
}
|
|
3683
|
-
function extractReasoning(value) {
|
|
3684
|
-
if (!value) {
|
|
3685
|
-
return "";
|
|
3686
|
-
}
|
|
3687
|
-
if (Array.isArray(value)) {
|
|
3688
|
-
return value.map(extractReasoning).filter(Boolean).join("");
|
|
3689
|
-
}
|
|
3690
|
-
if (typeof value === "object") {
|
|
3691
|
-
const record = value;
|
|
3692
|
-
if (record.type === "reasoning") {
|
|
3693
|
-
if (typeof record.text === "string") {
|
|
3694
|
-
return record.text;
|
|
3695
|
-
}
|
|
3696
|
-
if (typeof record.reasoning === "string") {
|
|
3697
|
-
return record.reasoning;
|
|
3698
|
-
}
|
|
3699
|
-
}
|
|
3700
|
-
return [
|
|
3701
|
-
extractReasoning(record.message),
|
|
3702
|
-
extractReasoning(record.content),
|
|
3703
|
-
extractReasoning(record.parts)
|
|
3704
|
-
].filter(Boolean).join("");
|
|
3705
|
-
}
|
|
3706
|
-
return "";
|
|
3707
|
-
}
|
|
3708
3666
|
function toOpenCodeModel(model) {
|
|
3709
3667
|
if (!model) {
|
|
3710
3668
|
return void 0;
|
|
@@ -3771,6 +3729,14 @@ function buildOpenCodeConfig(options, interactiveApproval) {
|
|
|
3771
3729
|
const commandsConfig = buildOpenCodeCommandsConfig(options.commands);
|
|
3772
3730
|
const baseAgent = {
|
|
3773
3731
|
mode: "primary",
|
|
3732
|
+
// Suppress opencode's default provider system prompt (e.g.
|
|
3733
|
+
// PROMPT_ANTHROPIC's "You are OpenCode...") so request.run.systemPrompt
|
|
3734
|
+
// is the dominant identity statement the model sees. opencode's
|
|
3735
|
+
// session/llm.ts uses agent.prompt instead of SystemPrompt.provider(model)
|
|
3736
|
+
// when this field is truthy — codex already takes that branch via a
|
|
3737
|
+
// separate options.instructions channel, so this brings anthropic et al.
|
|
3738
|
+
// in line. Constant value, so setupId stays stable.
|
|
3739
|
+
prompt: "You are an AI coding assistant. Follow the user's instructions.",
|
|
3774
3740
|
permission: buildOpenCodePermissionConfig(interactiveApproval),
|
|
3775
3741
|
tools: {
|
|
3776
3742
|
write: true,
|
|
@@ -4029,25 +3995,14 @@ var OpenCodeAgentAdapter = class {
|
|
|
4029
3995
|
"validateProviderUserInput",
|
|
4030
3996
|
() => validateProviderUserInput(request.provider, request.run.input)
|
|
4031
3997
|
);
|
|
4032
|
-
let pendingMessages = 0;
|
|
4033
|
-
let finalText = "";
|
|
4034
3998
|
let streamedTextFromSse = "";
|
|
4035
|
-
const
|
|
3999
|
+
const assistantTextByMessageId = /* @__PURE__ */ new Map();
|
|
4000
|
+
const announcedAssistantCompletions = /* @__PURE__ */ new Set();
|
|
4036
4001
|
let dispatchError;
|
|
4037
4002
|
let firstSseEventLogged = false;
|
|
4038
|
-
let resolveAllDone;
|
|
4039
|
-
const allDone = new Promise((resolve) => {
|
|
4040
|
-
resolveAllDone = resolve;
|
|
4041
|
-
});
|
|
4042
|
-
const checkDone = () => {
|
|
4043
|
-
if (pendingMessages === 0) {
|
|
4044
|
-
resolveAllDone();
|
|
4045
|
-
}
|
|
4046
|
-
};
|
|
4047
4003
|
let sendToSession;
|
|
4048
4004
|
const queuedParts = [];
|
|
4049
4005
|
sink.onMessage(async (content) => {
|
|
4050
|
-
pendingMessages++;
|
|
4051
4006
|
try {
|
|
4052
4007
|
const parts = await validateProviderUserInput(
|
|
4053
4008
|
request.provider,
|
|
@@ -4060,11 +4015,10 @@ var OpenCodeAgentAdapter = class {
|
|
|
4060
4015
|
queuedParts.push(mapped);
|
|
4061
4016
|
}
|
|
4062
4017
|
} catch (error) {
|
|
4063
|
-
pendingMessages--;
|
|
4064
4018
|
if (!dispatchError) {
|
|
4065
4019
|
dispatchError = error;
|
|
4066
4020
|
}
|
|
4067
|
-
|
|
4021
|
+
resolveSessionTerminal();
|
|
4068
4022
|
throw error;
|
|
4069
4023
|
}
|
|
4070
4024
|
});
|
|
@@ -4083,10 +4037,15 @@ var OpenCodeAgentAdapter = class {
|
|
|
4083
4037
|
const rawPayloads = [];
|
|
4084
4038
|
const sseAbort = new AbortController();
|
|
4085
4039
|
let sseTask;
|
|
4086
|
-
const dispatchAbort = new AbortController();
|
|
4087
4040
|
let capturedSessionId;
|
|
4088
4041
|
let sessionErrorFromSse;
|
|
4089
4042
|
let sessionAbortedFromSse = false;
|
|
4043
|
+
let sessionIdleFromSse = false;
|
|
4044
|
+
let resolveSessionTerminal;
|
|
4045
|
+
const sessionTerminal = new Promise((resolve) => {
|
|
4046
|
+
resolveSessionTerminal = resolve;
|
|
4047
|
+
});
|
|
4048
|
+
let lastSseActivityAt = Date.now();
|
|
4090
4049
|
let userAbortRequested = false;
|
|
4091
4050
|
sink.setAbort(async () => {
|
|
4092
4051
|
userAbortRequested = true;
|
|
@@ -4114,7 +4073,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
4114
4073
|
} catch {
|
|
4115
4074
|
}
|
|
4116
4075
|
}
|
|
4117
|
-
|
|
4076
|
+
resolveSessionTerminal();
|
|
4118
4077
|
});
|
|
4119
4078
|
try {
|
|
4120
4079
|
const interactiveApproval = isInteractiveApproval(request.options);
|
|
@@ -4155,10 +4114,14 @@ var OpenCodeAgentAdapter = class {
|
|
|
4155
4114
|
const foreignMessageIds = /* @__PURE__ */ new Set();
|
|
4156
4115
|
sseTask = (async () => {
|
|
4157
4116
|
try {
|
|
4158
|
-
for await (const event of
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4117
|
+
for await (const event of streamSseResilient(
|
|
4118
|
+
`${runtime.baseUrl}/event`,
|
|
4119
|
+
{
|
|
4120
|
+
headers: runtime.previewHeaders,
|
|
4121
|
+
signal: sseAbort.signal
|
|
4122
|
+
}
|
|
4123
|
+
)) {
|
|
4124
|
+
lastSseActivityAt = Date.now();
|
|
4162
4125
|
if (!firstSseEventLogged) {
|
|
4163
4126
|
firstSseEventLogged = true;
|
|
4164
4127
|
debugOpencode(
|
|
@@ -4201,6 +4164,22 @@ var OpenCodeAgentAdapter = class {
|
|
|
4201
4164
|
{ messageId: info.id }
|
|
4202
4165
|
)
|
|
4203
4166
|
);
|
|
4167
|
+
} else if (info.role === "assistant" && !announcedAssistantCompletions.has(info.id)) {
|
|
4168
|
+
const time2 = info.time;
|
|
4169
|
+
if (typeof time2?.completed === "number") {
|
|
4170
|
+
announcedAssistantCompletions.add(info.id);
|
|
4171
|
+
sink.emitEvent(
|
|
4172
|
+
createNormalizedEvent(
|
|
4173
|
+
"message.completed",
|
|
4174
|
+
{
|
|
4175
|
+
provider: request.provider,
|
|
4176
|
+
runId: request.runId,
|
|
4177
|
+
raw
|
|
4178
|
+
},
|
|
4179
|
+
{ text: assistantTextByMessageId.get(info.id) ?? "" }
|
|
4180
|
+
)
|
|
4181
|
+
);
|
|
4182
|
+
}
|
|
4204
4183
|
}
|
|
4205
4184
|
}
|
|
4206
4185
|
}
|
|
@@ -4233,7 +4212,7 @@ var OpenCodeAgentAdapter = class {
|
|
|
4233
4212
|
continue;
|
|
4234
4213
|
}
|
|
4235
4214
|
const payloadRecord = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
|
|
4236
|
-
if (
|
|
4215
|
+
if (payloadRecord?.type === "session.idle" || payloadRecord?.type === "session.error") {
|
|
4237
4216
|
const properties = payloadRecord.properties;
|
|
4238
4217
|
const eventSessionId = typeof properties?.sessionID === "string" ? properties.sessionID : void 0;
|
|
4239
4218
|
if (!eventSessionId || eventSessionId === sessionId) {
|
|
@@ -4245,13 +4224,28 @@ var OpenCodeAgentAdapter = class {
|
|
|
4245
4224
|
const errMsg = typeof errData?.data?.message === "string" ? errData.data.message : typeof errData?.message === "string" ? errData.message : "OpenCode session error";
|
|
4246
4225
|
sessionErrorFromSse = new Error(errMsg);
|
|
4247
4226
|
}
|
|
4227
|
+
} else {
|
|
4228
|
+
sessionIdleFromSse = true;
|
|
4248
4229
|
}
|
|
4249
4230
|
debugOpencode(
|
|
4250
|
-
"\u2605 %s for session=%s
|
|
4231
|
+
"\u2605 %s for session=%s",
|
|
4251
4232
|
payloadRecord.type,
|
|
4252
4233
|
sessionId
|
|
4253
4234
|
);
|
|
4254
|
-
|
|
4235
|
+
resolveSessionTerminal();
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
if (payloadRecord?.type === "session.status") {
|
|
4239
|
+
const properties = payloadRecord.properties;
|
|
4240
|
+
const status = properties?.status;
|
|
4241
|
+
const eventSessionId = typeof properties?.sessionID === "string" ? properties.sessionID : void 0;
|
|
4242
|
+
if ((!eventSessionId || eventSessionId === sessionId) && status?.type === "idle") {
|
|
4243
|
+
sessionIdleFromSse = true;
|
|
4244
|
+
debugOpencode(
|
|
4245
|
+
"\u2605 session.status{idle} for session=%s",
|
|
4246
|
+
sessionId
|
|
4247
|
+
);
|
|
4248
|
+
resolveSessionTerminal();
|
|
4255
4249
|
}
|
|
4256
4250
|
}
|
|
4257
4251
|
if (payloadRecord?.type === "message.part.delta") {
|
|
@@ -4262,12 +4256,15 @@ var OpenCodeAgentAdapter = class {
|
|
|
4262
4256
|
if (isForeignSession) {
|
|
4263
4257
|
continue;
|
|
4264
4258
|
}
|
|
4265
|
-
if (eventMessageId !== void 0 && settledMessageIds.has(eventMessageId)) {
|
|
4266
|
-
continue;
|
|
4267
|
-
}
|
|
4268
4259
|
const delta = typeof properties?.delta === "string" ? properties.delta : "";
|
|
4269
4260
|
if (delta && properties?.field === "text") {
|
|
4270
4261
|
streamedTextFromSse += delta;
|
|
4262
|
+
if (eventMessageId) {
|
|
4263
|
+
assistantTextByMessageId.set(
|
|
4264
|
+
eventMessageId,
|
|
4265
|
+
(assistantTextByMessageId.get(eventMessageId) ?? "") + delta
|
|
4266
|
+
);
|
|
4267
|
+
}
|
|
4271
4268
|
sink.emitEvent(
|
|
4272
4269
|
createNormalizedEvent(
|
|
4273
4270
|
"text.delta",
|
|
@@ -4320,131 +4317,131 @@ var OpenCodeAgentAdapter = class {
|
|
|
4320
4317
|
})
|
|
4321
4318
|
);
|
|
4322
4319
|
const agentSlug = openCodeAgentSlug(request.run.reasoning);
|
|
4323
|
-
const
|
|
4324
|
-
const
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4320
|
+
const dispatchPrompt = async (parts) => {
|
|
4321
|
+
const body = JSON.stringify({
|
|
4322
|
+
...request.run.model ? { model: toOpenCodeModel(request.run.model) } : {},
|
|
4323
|
+
// Per-message system prompt — keeps systemPrompt out of
|
|
4324
|
+
// the on-disk agent config so changing it doesn't
|
|
4325
|
+
// invalidate setupId. Sent on every dispatch (the field
|
|
4326
|
+
// is per-message, not session-sticky).
|
|
4327
|
+
...request.run.systemPrompt ? { system: request.run.systemPrompt } : {},
|
|
4328
|
+
agent: agentSlug,
|
|
4329
|
+
parts
|
|
4330
|
+
});
|
|
4331
|
+
const url = `${runtime.baseUrl}/session/${sessionId}/prompt_async`;
|
|
4332
|
+
const attempt = async () => {
|
|
4333
|
+
return fetch(url, {
|
|
4334
|
+
method: "POST",
|
|
4335
|
+
headers: {
|
|
4336
|
+
"content-type": "application/json",
|
|
4337
|
+
...runtime.previewHeaders
|
|
4338
|
+
},
|
|
4339
|
+
body
|
|
4340
|
+
});
|
|
4341
|
+
};
|
|
4342
|
+
let lastError;
|
|
4343
|
+
for (let i = 0; i < 2; i++) {
|
|
4344
|
+
try {
|
|
4345
|
+
const response = await attempt();
|
|
4346
|
+
if (response.ok || response.status === 204) {
|
|
4347
|
+
return;
|
|
4345
4348
|
}
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
request.runId,
|
|
4349
|
-
response,
|
|
4350
|
-
"message.response"
|
|
4351
|
-
);
|
|
4352
|
-
if (response && typeof response === "object" && !Array.isArray(response)) {
|
|
4353
|
-
rawPayloads.push(response);
|
|
4354
|
-
}
|
|
4355
|
-
sink.emitRaw(rawResponse);
|
|
4356
|
-
for (const event of normalizeRawAgentEvent(rawResponse)) {
|
|
4357
|
-
sink.emitEvent(event);
|
|
4358
|
-
}
|
|
4359
|
-
const reasoning = extractReasoning(response);
|
|
4360
|
-
if (reasoning) {
|
|
4361
|
-
sink.emitEvent(
|
|
4362
|
-
createNormalizedEvent(
|
|
4363
|
-
"reasoning.delta",
|
|
4364
|
-
{
|
|
4365
|
-
provider: request.provider,
|
|
4366
|
-
runId: request.runId,
|
|
4367
|
-
raw: rawResponse
|
|
4368
|
-
},
|
|
4369
|
-
{ delta: reasoning }
|
|
4370
|
-
)
|
|
4349
|
+
lastError = new Error(
|
|
4350
|
+
`POST ${url} returned ${response.status}`
|
|
4371
4351
|
);
|
|
4352
|
+
} catch (error) {
|
|
4353
|
+
lastError = error;
|
|
4372
4354
|
}
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4355
|
+
if (i === 0) {
|
|
4356
|
+
debugOpencode(
|
|
4357
|
+
"prompt_async dispatch attempt %d failed (%s); retrying once",
|
|
4358
|
+
i + 1,
|
|
4359
|
+
lastError?.message ?? String(lastError)
|
|
4378
4360
|
);
|
|
4379
|
-
|
|
4380
|
-
if (text.startsWith(sseTextForThisDispatch)) {
|
|
4381
|
-
missing = text.slice(sseTextForThisDispatch.length);
|
|
4382
|
-
} else if (sseTextForThisDispatch.length === 0) {
|
|
4383
|
-
missing = text;
|
|
4384
|
-
} else {
|
|
4385
|
-
missing = "";
|
|
4386
|
-
}
|
|
4387
|
-
if (missing.length > 0) {
|
|
4388
|
-
streamedTextFromSse += missing;
|
|
4389
|
-
sink.emitEvent(
|
|
4390
|
-
createNormalizedEvent(
|
|
4391
|
-
"text.delta",
|
|
4392
|
-
{
|
|
4393
|
-
provider: request.provider,
|
|
4394
|
-
runId: request.runId
|
|
4395
|
-
},
|
|
4396
|
-
{ delta: missing }
|
|
4397
|
-
)
|
|
4398
|
-
);
|
|
4399
|
-
}
|
|
4400
|
-
const assistantMessageId = extractAssistantMessageId(response);
|
|
4401
|
-
if (assistantMessageId) {
|
|
4402
|
-
settledMessageIds.add(assistantMessageId);
|
|
4403
|
-
}
|
|
4361
|
+
await sleep(500);
|
|
4404
4362
|
}
|
|
4405
|
-
} catch (error) {
|
|
4406
|
-
if (!dispatchError) {
|
|
4407
|
-
dispatchError = error;
|
|
4408
|
-
}
|
|
4409
|
-
} finally {
|
|
4410
|
-
pendingMessages--;
|
|
4411
|
-
checkDone();
|
|
4412
4363
|
}
|
|
4364
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
4413
4365
|
};
|
|
4414
4366
|
sendToSession = (parts) => {
|
|
4415
|
-
void
|
|
4367
|
+
void (async () => {
|
|
4368
|
+
try {
|
|
4369
|
+
await dispatchPrompt(parts);
|
|
4370
|
+
} catch (error) {
|
|
4371
|
+
if (!dispatchError) {
|
|
4372
|
+
dispatchError = error;
|
|
4373
|
+
}
|
|
4374
|
+
resolveSessionTerminal();
|
|
4375
|
+
}
|
|
4376
|
+
})();
|
|
4416
4377
|
};
|
|
4417
4378
|
for (const queued of queuedParts.splice(0)) {
|
|
4418
4379
|
sendToSession(queued);
|
|
4419
4380
|
}
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4381
|
+
try {
|
|
4382
|
+
await dispatchPrompt(mapToOpenCodeParts(inputParts));
|
|
4383
|
+
} catch (error) {
|
|
4384
|
+
if (!dispatchError) {
|
|
4385
|
+
dispatchError = error;
|
|
4386
|
+
}
|
|
4387
|
+
resolveSessionTerminal();
|
|
4388
|
+
}
|
|
4389
|
+
const SSE_SILENCE_THRESHOLD_MS = 18e4;
|
|
4390
|
+
const SSE_POLL_INTERVAL_MS = 5e3;
|
|
4391
|
+
lastSseActivityAt = Date.now();
|
|
4392
|
+
let sseSilent = false;
|
|
4393
|
+
while (!sessionIdleFromSse && !sessionErrorFromSse && !sessionAbortedFromSse && !userAbortRequested && !dispatchError) {
|
|
4394
|
+
const silence = Date.now() - lastSseActivityAt;
|
|
4395
|
+
if (silence > SSE_SILENCE_THRESHOLD_MS) {
|
|
4396
|
+
sseSilent = true;
|
|
4397
|
+
debugOpencode("SSE went silent (%dms) \u2014 giving up", silence);
|
|
4398
|
+
break;
|
|
4399
|
+
}
|
|
4400
|
+
await Promise.race([
|
|
4401
|
+
sessionTerminal,
|
|
4402
|
+
new Promise(
|
|
4403
|
+
(resolve) => setTimeout(resolve, SSE_POLL_INTERVAL_MS)
|
|
4404
|
+
)
|
|
4405
|
+
]);
|
|
4406
|
+
}
|
|
4407
|
+
sseAbort.abort();
|
|
4408
|
+
await sseTask;
|
|
4423
4409
|
if (userAbortRequested || sessionAbortedFromSse) {
|
|
4424
4410
|
debugOpencode(
|
|
4425
4411
|
"\u2605 run.cancelled (%dms since execute start)",
|
|
4426
4412
|
Date.now() - executeStartedAt
|
|
4427
4413
|
);
|
|
4428
|
-
sseAbort.abort();
|
|
4429
|
-
await sseTask;
|
|
4430
4414
|
sink.cancel({
|
|
4431
4415
|
text: streamedTextFromSse || void 0,
|
|
4432
4416
|
costData: extractOpenCodeCostData(rawPayloads)
|
|
4433
4417
|
});
|
|
4434
4418
|
} else if (sessionErrorFromSse) {
|
|
4435
|
-
sseAbort.abort();
|
|
4436
|
-
await sseTask;
|
|
4437
4419
|
sink.fail(sessionErrorFromSse);
|
|
4438
|
-
} else if (dispatchError
|
|
4439
|
-
sseAbort.abort();
|
|
4440
|
-
await sseTask;
|
|
4420
|
+
} else if (dispatchError) {
|
|
4441
4421
|
sink.fail(dispatchError);
|
|
4442
|
-
} else {
|
|
4422
|
+
} else if (sessionIdleFromSse) {
|
|
4443
4423
|
debugOpencode(
|
|
4444
4424
|
"\u2605 run.completed (%dms since execute start) chars=%d",
|
|
4445
4425
|
Date.now() - executeStartedAt,
|
|
4446
|
-
|
|
4426
|
+
streamedTextFromSse.length
|
|
4447
4427
|
);
|
|
4428
|
+
let lastAssistantText = "";
|
|
4429
|
+
for (const [messageId, text] of assistantTextByMessageId) {
|
|
4430
|
+
lastAssistantText = text;
|
|
4431
|
+
if (!announcedAssistantCompletions.has(messageId)) {
|
|
4432
|
+
announcedAssistantCompletions.add(messageId);
|
|
4433
|
+
sink.emitEvent(
|
|
4434
|
+
createNormalizedEvent(
|
|
4435
|
+
"message.completed",
|
|
4436
|
+
{
|
|
4437
|
+
provider: request.provider,
|
|
4438
|
+
runId: request.runId
|
|
4439
|
+
},
|
|
4440
|
+
{ text }
|
|
4441
|
+
)
|
|
4442
|
+
);
|
|
4443
|
+
}
|
|
4444
|
+
}
|
|
4448
4445
|
sink.emitEvent(
|
|
4449
4446
|
createNormalizedEvent(
|
|
4450
4447
|
"run.completed",
|
|
@@ -4452,15 +4449,23 @@ var OpenCodeAgentAdapter = class {
|
|
|
4452
4449
|
provider: request.provider,
|
|
4453
4450
|
runId: request.runId
|
|
4454
4451
|
},
|
|
4455
|
-
{ text:
|
|
4452
|
+
{ text: lastAssistantText }
|
|
4456
4453
|
)
|
|
4457
4454
|
);
|
|
4458
|
-
sseAbort.abort();
|
|
4459
|
-
await sseTask;
|
|
4460
4455
|
sink.complete({
|
|
4461
|
-
text:
|
|
4456
|
+
text: lastAssistantText,
|
|
4462
4457
|
costData: extractOpenCodeCostData(rawPayloads)
|
|
4463
4458
|
});
|
|
4459
|
+
} else if (sseSilent) {
|
|
4460
|
+
sink.fail(
|
|
4461
|
+
new Error(
|
|
4462
|
+
"opencode SSE went silent before the session reached idle"
|
|
4463
|
+
)
|
|
4464
|
+
);
|
|
4465
|
+
} else {
|
|
4466
|
+
sink.fail(
|
|
4467
|
+
new Error("opencode run ended without a terminal signal")
|
|
4468
|
+
);
|
|
4464
4469
|
}
|
|
4465
4470
|
} finally {
|
|
4466
4471
|
sseAbort.abort();
|
|
@@ -4506,10 +4511,10 @@ var OpenCodeAgentAdapter = class {
|
|
|
4506
4511
|
}
|
|
4507
4512
|
}
|
|
4508
4513
|
/**
|
|
4509
|
-
* Stateless message injection. POST
|
|
4510
|
-
* `/session/:id/
|
|
4511
|
-
*
|
|
4512
|
-
*
|
|
4514
|
+
* Stateless message injection. Fire-and-forget POST to
|
|
4515
|
+
* `/session/:id/prompt_async` (returns 204) — opencode appends the
|
|
4516
|
+
* message to the running session and the originating instance picks
|
|
4517
|
+
* up the new turn through its existing SSE stream.
|
|
4513
4518
|
*/
|
|
4514
4519
|
async attachSendMessage(request, content) {
|
|
4515
4520
|
if (!request.sessionId) {
|
|
@@ -4523,20 +4528,21 @@ var OpenCodeAgentAdapter = class {
|
|
|
4523
4528
|
content
|
|
4524
4529
|
);
|
|
4525
4530
|
const parts = mapToOpenCodeParts(inputParts);
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4531
|
+
const url = `${baseUrl}/session/${request.sessionId}/prompt_async`;
|
|
4532
|
+
const response = await fetch(url, {
|
|
4533
|
+
method: "POST",
|
|
4534
|
+
headers: {
|
|
4535
|
+
"content-type": "application/json",
|
|
4536
|
+
...request.sandbox.previewHeaders
|
|
4537
|
+
},
|
|
4538
|
+
body: JSON.stringify({
|
|
4539
|
+
agent: openCodeAgentSlug(void 0),
|
|
4540
|
+
parts
|
|
4541
|
+
})
|
|
4542
|
+
});
|
|
4543
|
+
if (!response.ok && response.status !== 204) {
|
|
4544
|
+
throw new Error(`POST ${url} returned ${response.status}`);
|
|
4545
|
+
}
|
|
4540
4546
|
}
|
|
4541
4547
|
};
|
|
4542
4548
|
|
|
@@ -4619,6 +4625,7 @@ var AgentRunController = class {
|
|
|
4619
4625
|
pendingPermissions = /* @__PURE__ */ new Map();
|
|
4620
4626
|
messageHandler;
|
|
4621
4627
|
text = "";
|
|
4628
|
+
observedMessageCompleted = false;
|
|
4622
4629
|
costData = null;
|
|
4623
4630
|
settled = false;
|
|
4624
4631
|
finished;
|
|
@@ -4669,6 +4676,9 @@ var AgentRunController = class {
|
|
|
4669
4676
|
this.text += event.delta;
|
|
4670
4677
|
} else if ((event.type === "message.completed" || event.type === "run.completed") && event.text) {
|
|
4671
4678
|
this.text = event.text;
|
|
4679
|
+
if (event.type === "message.completed") {
|
|
4680
|
+
this.observedMessageCompleted = true;
|
|
4681
|
+
}
|
|
4672
4682
|
}
|
|
4673
4683
|
this.eventQueue.push(event);
|
|
4674
4684
|
}
|
|
@@ -4766,7 +4776,7 @@ var AgentRunController = class {
|
|
|
4766
4776
|
"Agent run completed before pending permission requests resolved."
|
|
4767
4777
|
)
|
|
4768
4778
|
);
|
|
4769
|
-
if (result?.text) {
|
|
4779
|
+
if (result?.text && !this.observedMessageCompleted) {
|
|
4770
4780
|
this.text = result.text;
|
|
4771
4781
|
}
|
|
4772
4782
|
if (result && "costData" in result) {
|
|
@@ -4811,7 +4821,7 @@ var AgentRunController = class {
|
|
|
4811
4821
|
"Agent run was cancelled before pending permission requests resolved."
|
|
4812
4822
|
)
|
|
4813
4823
|
);
|
|
4814
|
-
if (result?.text) {
|
|
4824
|
+
if (result?.text && !this.observedMessageCompleted) {
|
|
4815
4825
|
this.text = result.text;
|
|
4816
4826
|
}
|
|
4817
4827
|
if (result && "costData" in result) {
|
package/dist/events/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Agent
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-T7C77LCW.js";
|
|
4
4
|
import {
|
|
5
5
|
ProviderLogAssembler,
|
|
6
6
|
createNormalizedEvent,
|
|
7
7
|
normalizeRawAgentEvent,
|
|
8
8
|
toAISDKEvent,
|
|
9
9
|
toAISDKStream
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EK6GC6YA.js";
|
|
11
11
|
import {
|
|
12
12
|
Sandbox,
|
|
13
13
|
SandboxAdapter,
|