agentbox-sdk 0.1.303 → 0.1.305

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.
@@ -1,5 +1,5 @@
1
- import { o as AgentProviderName, h as AgentOptions, t as AgentRunConfig, s as AgentRun, r as AgentResult, a2 as RawAgentEvent, b as AgentAttachRequest, y as AttachedRun } from '../types-Ozo1rHKs.js';
2
- export { a as AgentApprovalMode, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a4 as RepoSkillConfig, aa as TextPart, ae as UserContent, af as UserContentPart } from '../types-Ozo1rHKs.js';
1
+ import { o as AgentProviderName, h as AgentOptions, t as AgentRunConfig, s as AgentRun, r as AgentResult, a2 as RawAgentEvent, b as AgentAttachRequest, y as AttachedRun } from '../types-DiZSjZma.js';
2
+ export { a as AgentApprovalMode, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a4 as RepoSkillConfig, aa as TextPart, ae as UserContent, af as UserContentPart } from '../types-DiZSjZma.js';
3
3
  import { S as Sandbox } from '../Sandbox-K6VNqKeo.js';
4
4
  export { AgentProvider } from '../enums.js';
5
5
  import 'e2b';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Agent
3
- } from "../chunk-GBM7LKZF.js";
4
- import "../chunk-NWAXQ7UD.js";
3
+ } from "../chunk-KRSY52XS.js";
4
+ import "../chunk-ZDSHOGJ4.js";
5
5
  import {
6
6
  AGENT_RESERVED_PORTS,
7
7
  collectAllAgentReservedPorts
@@ -2,7 +2,7 @@ import {
2
2
  createNormalizedEvent,
3
3
  normalizeRawAgentEvent,
4
4
  toAISDKStream
5
- } from "./chunk-NWAXQ7UD.js";
5
+ } from "./chunk-ZDSHOGJ4.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({ text, costData: extractCodexCostData(rawPayloads) });
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;
@@ -3766,11 +3724,13 @@ var OPEN_CODE_REASONING_LEVELS = ["low", "medium", "high", "xhigh"];
3766
3724
  function openCodeAgentSlug(reasoning) {
3767
3725
  return reasoning ? `agentbox-${reasoning}` : "agentbox";
3768
3726
  }
3727
+ var FALLBACK_OPEN_CODE_AGENT_PROMPT = "You are an AI coding assistant. Follow the user's instructions.";
3769
3728
  function buildOpenCodeConfig(options, interactiveApproval) {
3770
3729
  const mcpConfig = buildOpenCodeMcpConfig(options.mcps);
3771
3730
  const commandsConfig = buildOpenCodeCommandsConfig(options.commands);
3772
3731
  const baseAgent = {
3773
3732
  mode: "primary",
3733
+ prompt: options.systemPrompt || FALLBACK_OPEN_CODE_AGENT_PROMPT,
3774
3734
  permission: buildOpenCodePermissionConfig(interactiveApproval),
3775
3735
  tools: {
3776
3736
  write: true,
@@ -4029,25 +3989,14 @@ var OpenCodeAgentAdapter = class {
4029
3989
  "validateProviderUserInput",
4030
3990
  () => validateProviderUserInput(request.provider, request.run.input)
4031
3991
  );
4032
- let pendingMessages = 0;
4033
- let finalText = "";
4034
3992
  let streamedTextFromSse = "";
4035
- const settledMessageIds = /* @__PURE__ */ new Set();
3993
+ const assistantTextByMessageId = /* @__PURE__ */ new Map();
3994
+ const announcedAssistantCompletions = /* @__PURE__ */ new Set();
4036
3995
  let dispatchError;
4037
3996
  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
3997
  let sendToSession;
4048
3998
  const queuedParts = [];
4049
3999
  sink.onMessage(async (content) => {
4050
- pendingMessages++;
4051
4000
  try {
4052
4001
  const parts = await validateProviderUserInput(
4053
4002
  request.provider,
@@ -4060,11 +4009,10 @@ var OpenCodeAgentAdapter = class {
4060
4009
  queuedParts.push(mapped);
4061
4010
  }
4062
4011
  } catch (error) {
4063
- pendingMessages--;
4064
4012
  if (!dispatchError) {
4065
4013
  dispatchError = error;
4066
4014
  }
4067
- checkDone();
4015
+ resolveSessionTerminal();
4068
4016
  throw error;
4069
4017
  }
4070
4018
  });
@@ -4083,10 +4031,15 @@ var OpenCodeAgentAdapter = class {
4083
4031
  const rawPayloads = [];
4084
4032
  const sseAbort = new AbortController();
4085
4033
  let sseTask;
4086
- const dispatchAbort = new AbortController();
4087
4034
  let capturedSessionId;
4088
4035
  let sessionErrorFromSse;
4089
4036
  let sessionAbortedFromSse = false;
4037
+ let sessionIdleFromSse = false;
4038
+ let resolveSessionTerminal;
4039
+ const sessionTerminal = new Promise((resolve) => {
4040
+ resolveSessionTerminal = resolve;
4041
+ });
4042
+ let lastSseActivityAt = Date.now();
4090
4043
  let userAbortRequested = false;
4091
4044
  sink.setAbort(async () => {
4092
4045
  userAbortRequested = true;
@@ -4114,7 +4067,7 @@ var OpenCodeAgentAdapter = class {
4114
4067
  } catch {
4115
4068
  }
4116
4069
  }
4117
- dispatchAbort.abort();
4070
+ resolveSessionTerminal();
4118
4071
  });
4119
4072
  try {
4120
4073
  const interactiveApproval = isInteractiveApproval(request.options);
@@ -4155,10 +4108,14 @@ var OpenCodeAgentAdapter = class {
4155
4108
  const foreignMessageIds = /* @__PURE__ */ new Set();
4156
4109
  sseTask = (async () => {
4157
4110
  try {
4158
- for await (const event of streamSse(`${runtime.baseUrl}/event`, {
4159
- headers: runtime.previewHeaders,
4160
- signal: sseAbort.signal
4161
- })) {
4111
+ for await (const event of streamSseResilient(
4112
+ `${runtime.baseUrl}/event`,
4113
+ {
4114
+ headers: runtime.previewHeaders,
4115
+ signal: sseAbort.signal
4116
+ }
4117
+ )) {
4118
+ lastSseActivityAt = Date.now();
4162
4119
  if (!firstSseEventLogged) {
4163
4120
  firstSseEventLogged = true;
4164
4121
  debugOpencode(
@@ -4201,6 +4158,22 @@ var OpenCodeAgentAdapter = class {
4201
4158
  { messageId: info.id }
4202
4159
  )
4203
4160
  );
4161
+ } else if (info.role === "assistant" && !announcedAssistantCompletions.has(info.id)) {
4162
+ const time2 = info.time;
4163
+ if (typeof time2?.completed === "number") {
4164
+ announcedAssistantCompletions.add(info.id);
4165
+ sink.emitEvent(
4166
+ createNormalizedEvent(
4167
+ "message.completed",
4168
+ {
4169
+ provider: request.provider,
4170
+ runId: request.runId,
4171
+ raw
4172
+ },
4173
+ { text: assistantTextByMessageId.get(info.id) ?? "" }
4174
+ )
4175
+ );
4176
+ }
4204
4177
  }
4205
4178
  }
4206
4179
  }
@@ -4233,7 +4206,7 @@ var OpenCodeAgentAdapter = class {
4233
4206
  continue;
4234
4207
  }
4235
4208
  const payloadRecord = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
4236
- if ((payloadRecord?.type === "session.idle" || payloadRecord?.type === "session.error") && !dispatchAbort.signal.aborted) {
4209
+ if (payloadRecord?.type === "session.idle" || payloadRecord?.type === "session.error") {
4237
4210
  const properties = payloadRecord.properties;
4238
4211
  const eventSessionId = typeof properties?.sessionID === "string" ? properties.sessionID : void 0;
4239
4212
  if (!eventSessionId || eventSessionId === sessionId) {
@@ -4245,13 +4218,28 @@ var OpenCodeAgentAdapter = class {
4245
4218
  const errMsg = typeof errData?.data?.message === "string" ? errData.data.message : typeof errData?.message === "string" ? errData.message : "OpenCode session error";
4246
4219
  sessionErrorFromSse = new Error(errMsg);
4247
4220
  }
4221
+ } else {
4222
+ sessionIdleFromSse = true;
4248
4223
  }
4249
4224
  debugOpencode(
4250
- "\u2605 %s for session=%s \u2014 aborting in-flight dispatch",
4225
+ "\u2605 %s for session=%s",
4251
4226
  payloadRecord.type,
4252
4227
  sessionId
4253
4228
  );
4254
- dispatchAbort.abort();
4229
+ resolveSessionTerminal();
4230
+ }
4231
+ }
4232
+ if (payloadRecord?.type === "session.status") {
4233
+ const properties = payloadRecord.properties;
4234
+ const status = properties?.status;
4235
+ const eventSessionId = typeof properties?.sessionID === "string" ? properties.sessionID : void 0;
4236
+ if ((!eventSessionId || eventSessionId === sessionId) && status?.type === "idle") {
4237
+ sessionIdleFromSse = true;
4238
+ debugOpencode(
4239
+ "\u2605 session.status{idle} for session=%s",
4240
+ sessionId
4241
+ );
4242
+ resolveSessionTerminal();
4255
4243
  }
4256
4244
  }
4257
4245
  if (payloadRecord?.type === "message.part.delta") {
@@ -4262,12 +4250,15 @@ var OpenCodeAgentAdapter = class {
4262
4250
  if (isForeignSession) {
4263
4251
  continue;
4264
4252
  }
4265
- if (eventMessageId !== void 0 && settledMessageIds.has(eventMessageId)) {
4266
- continue;
4267
- }
4268
4253
  const delta = typeof properties?.delta === "string" ? properties.delta : "";
4269
4254
  if (delta && properties?.field === "text") {
4270
4255
  streamedTextFromSse += delta;
4256
+ if (eventMessageId) {
4257
+ assistantTextByMessageId.set(
4258
+ eventMessageId,
4259
+ (assistantTextByMessageId.get(eventMessageId) ?? "") + delta
4260
+ );
4261
+ }
4271
4262
  sink.emitEvent(
4272
4263
  createNormalizedEvent(
4273
4264
  "text.delta",
@@ -4320,131 +4311,138 @@ var OpenCodeAgentAdapter = class {
4320
4311
  })
4321
4312
  );
4322
4313
  const agentSlug = openCodeAgentSlug(request.run.reasoning);
4323
- const dispatchMessage = async (parts) => {
4324
- const sseTextLengthBeforeDispatch = streamedTextFromSse.length;
4325
- try {
4326
- const response = await fetchJson(
4327
- `${runtime.baseUrl}/session/${sessionId}/message`,
4328
- {
4329
- method: "POST",
4330
- signal: dispatchAbort.signal,
4331
- headers: {
4332
- "content-type": "application/json",
4333
- ...runtime.previewHeaders
4334
- },
4335
- body: JSON.stringify({
4336
- ...request.run.model ? { model: toOpenCodeModel(request.run.model) } : {},
4337
- // Per-message system prompt keeps systemPrompt out of
4338
- // the on-disk agent config so changing it doesn't
4339
- // invalidate setupId. Sent on every dispatch (the field
4340
- // is per-message, not session-sticky).
4341
- ...request.run.systemPrompt ? { system: request.run.systemPrompt } : {},
4342
- agent: agentSlug,
4343
- parts
4344
- })
4314
+ const dispatchPrompt = async (parts) => {
4315
+ const body = JSON.stringify({
4316
+ ...request.run.model ? { model: toOpenCodeModel(request.run.model) } : {},
4317
+ // Per-message system prompt override. opencode appends this
4318
+ // *after* `agent.prompt` and the runtime appendix
4319
+ // (env/AGENTS.md/skills) when composing the final system
4320
+ // string — see `buildOpenCodeConfig` for the full ordering.
4321
+ // For Anthropic models specifically, this trailing-position
4322
+ // content tends to be ignored; callers that need the prompt
4323
+ // to actually steer Sonnet/Opus should pass it via
4324
+ // `OpenCodeAgentOptions.systemPrompt` so it's baked into
4325
+ // `agent.prompt` (the leading position) at setup time
4326
+ // instead. This per-message field stays as a per-run
4327
+ // override path that's effective for codex/GPT/Gemini.
4328
+ ...request.run.systemPrompt ? { system: request.run.systemPrompt } : {},
4329
+ agent: agentSlug,
4330
+ parts
4331
+ });
4332
+ const url = `${runtime.baseUrl}/session/${sessionId}/prompt_async`;
4333
+ const attempt = async () => {
4334
+ return fetch(url, {
4335
+ method: "POST",
4336
+ headers: {
4337
+ "content-type": "application/json",
4338
+ ...runtime.previewHeaders
4339
+ },
4340
+ body
4341
+ });
4342
+ };
4343
+ let lastError;
4344
+ for (let i = 0; i < 2; i++) {
4345
+ try {
4346
+ const response = await attempt();
4347
+ if (response.ok || response.status === 204) {
4348
+ return;
4345
4349
  }
4346
- );
4347
- const rawResponse = toRawEvent3(
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
- )
4350
+ lastError = new Error(
4351
+ `POST ${url} returned ${response.status}`
4371
4352
  );
4353
+ } catch (error) {
4354
+ lastError = error;
4372
4355
  }
4373
- const text = extractText(response);
4374
- if (text) {
4375
- finalText = text;
4376
- const sseTextForThisDispatch = streamedTextFromSse.slice(
4377
- sseTextLengthBeforeDispatch
4356
+ if (i === 0) {
4357
+ debugOpencode(
4358
+ "prompt_async dispatch attempt %d failed (%s); retrying once",
4359
+ i + 1,
4360
+ lastError?.message ?? String(lastError)
4378
4361
  );
4379
- let missing;
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
- }
4362
+ await sleep(500);
4404
4363
  }
4405
- } catch (error) {
4406
- if (!dispatchError) {
4407
- dispatchError = error;
4408
- }
4409
- } finally {
4410
- pendingMessages--;
4411
- checkDone();
4412
4364
  }
4365
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
4413
4366
  };
4414
4367
  sendToSession = (parts) => {
4415
- void dispatchMessage(parts);
4368
+ void (async () => {
4369
+ try {
4370
+ await dispatchPrompt(parts);
4371
+ } catch (error) {
4372
+ if (!dispatchError) {
4373
+ dispatchError = error;
4374
+ }
4375
+ resolveSessionTerminal();
4376
+ }
4377
+ })();
4416
4378
  };
4417
4379
  for (const queued of queuedParts.splice(0)) {
4418
4380
  sendToSession(queued);
4419
4381
  }
4420
- pendingMessages++;
4421
- void dispatchMessage(mapToOpenCodeParts(inputParts));
4422
- await allDone;
4382
+ try {
4383
+ await dispatchPrompt(mapToOpenCodeParts(inputParts));
4384
+ } catch (error) {
4385
+ if (!dispatchError) {
4386
+ dispatchError = error;
4387
+ }
4388
+ resolveSessionTerminal();
4389
+ }
4390
+ const SSE_SILENCE_THRESHOLD_MS = 18e4;
4391
+ const SSE_POLL_INTERVAL_MS = 5e3;
4392
+ lastSseActivityAt = Date.now();
4393
+ let sseSilent = false;
4394
+ while (!sessionIdleFromSse && !sessionErrorFromSse && !sessionAbortedFromSse && !userAbortRequested && !dispatchError) {
4395
+ const silence = Date.now() - lastSseActivityAt;
4396
+ if (silence > SSE_SILENCE_THRESHOLD_MS) {
4397
+ sseSilent = true;
4398
+ debugOpencode("SSE went silent (%dms) \u2014 giving up", silence);
4399
+ break;
4400
+ }
4401
+ await Promise.race([
4402
+ sessionTerminal,
4403
+ new Promise(
4404
+ (resolve) => setTimeout(resolve, SSE_POLL_INTERVAL_MS)
4405
+ )
4406
+ ]);
4407
+ }
4408
+ sseAbort.abort();
4409
+ await sseTask;
4423
4410
  if (userAbortRequested || sessionAbortedFromSse) {
4424
4411
  debugOpencode(
4425
4412
  "\u2605 run.cancelled (%dms since execute start)",
4426
4413
  Date.now() - executeStartedAt
4427
4414
  );
4428
- sseAbort.abort();
4429
- await sseTask;
4430
4415
  sink.cancel({
4431
4416
  text: streamedTextFromSse || void 0,
4432
4417
  costData: extractOpenCodeCostData(rawPayloads)
4433
4418
  });
4434
4419
  } else if (sessionErrorFromSse) {
4435
- sseAbort.abort();
4436
- await sseTask;
4437
4420
  sink.fail(sessionErrorFromSse);
4438
- } else if (dispatchError && !(dispatchAbort.signal.aborted && dispatchError?.name === "AbortError")) {
4439
- sseAbort.abort();
4440
- await sseTask;
4421
+ } else if (dispatchError) {
4441
4422
  sink.fail(dispatchError);
4442
- } else {
4423
+ } else if (sessionIdleFromSse) {
4443
4424
  debugOpencode(
4444
4425
  "\u2605 run.completed (%dms since execute start) chars=%d",
4445
4426
  Date.now() - executeStartedAt,
4446
- finalText.length
4427
+ streamedTextFromSse.length
4447
4428
  );
4429
+ let lastAssistantText = "";
4430
+ for (const [messageId, text] of assistantTextByMessageId) {
4431
+ lastAssistantText = text;
4432
+ if (!announcedAssistantCompletions.has(messageId)) {
4433
+ announcedAssistantCompletions.add(messageId);
4434
+ sink.emitEvent(
4435
+ createNormalizedEvent(
4436
+ "message.completed",
4437
+ {
4438
+ provider: request.provider,
4439
+ runId: request.runId
4440
+ },
4441
+ { text }
4442
+ )
4443
+ );
4444
+ }
4445
+ }
4448
4446
  sink.emitEvent(
4449
4447
  createNormalizedEvent(
4450
4448
  "run.completed",
@@ -4452,15 +4450,23 @@ var OpenCodeAgentAdapter = class {
4452
4450
  provider: request.provider,
4453
4451
  runId: request.runId
4454
4452
  },
4455
- { text: finalText }
4453
+ { text: lastAssistantText }
4456
4454
  )
4457
4455
  );
4458
- sseAbort.abort();
4459
- await sseTask;
4460
4456
  sink.complete({
4461
- text: finalText,
4457
+ text: lastAssistantText,
4462
4458
  costData: extractOpenCodeCostData(rawPayloads)
4463
4459
  });
4460
+ } else if (sseSilent) {
4461
+ sink.fail(
4462
+ new Error(
4463
+ "opencode SSE went silent before the session reached idle"
4464
+ )
4465
+ );
4466
+ } else {
4467
+ sink.fail(
4468
+ new Error("opencode run ended without a terminal signal")
4469
+ );
4464
4470
  }
4465
4471
  } finally {
4466
4472
  sseAbort.abort();
@@ -4506,10 +4512,10 @@ var OpenCodeAgentAdapter = class {
4506
4512
  }
4507
4513
  }
4508
4514
  /**
4509
- * Stateless message injection. POST a fresh user message to
4510
- * `/session/:id/message` with `agent` defaulting to the build agent
4511
- * opencode appends it to the running session and the originating
4512
- * instance picks up the new turn through its existing SSE stream.
4515
+ * Stateless message injection. Fire-and-forget POST to
4516
+ * `/session/:id/prompt_async` (returns 204) opencode appends the
4517
+ * message to the running session and the originating instance picks
4518
+ * up the new turn through its existing SSE stream.
4513
4519
  */
4514
4520
  async attachSendMessage(request, content) {
4515
4521
  if (!request.sessionId) {
@@ -4523,20 +4529,21 @@ var OpenCodeAgentAdapter = class {
4523
4529
  content
4524
4530
  );
4525
4531
  const parts = mapToOpenCodeParts(inputParts);
4526
- await fetchJson(
4527
- `${baseUrl}/session/${request.sessionId}/message`,
4528
- {
4529
- method: "POST",
4530
- headers: {
4531
- "content-type": "application/json",
4532
- ...request.sandbox.previewHeaders
4533
- },
4534
- body: JSON.stringify({
4535
- agent: openCodeAgentSlug(void 0),
4536
- parts
4537
- })
4538
- }
4539
- );
4532
+ const url = `${baseUrl}/session/${request.sessionId}/prompt_async`;
4533
+ const response = await fetch(url, {
4534
+ method: "POST",
4535
+ headers: {
4536
+ "content-type": "application/json",
4537
+ ...request.sandbox.previewHeaders
4538
+ },
4539
+ body: JSON.stringify({
4540
+ agent: openCodeAgentSlug(void 0),
4541
+ parts
4542
+ })
4543
+ });
4544
+ if (!response.ok && response.status !== 204) {
4545
+ throw new Error(`POST ${url} returned ${response.status}`);
4546
+ }
4540
4547
  }
4541
4548
  };
4542
4549
 
@@ -4619,6 +4626,7 @@ var AgentRunController = class {
4619
4626
  pendingPermissions = /* @__PURE__ */ new Map();
4620
4627
  messageHandler;
4621
4628
  text = "";
4629
+ observedMessageCompleted = false;
4622
4630
  costData = null;
4623
4631
  settled = false;
4624
4632
  finished;
@@ -4669,6 +4677,9 @@ var AgentRunController = class {
4669
4677
  this.text += event.delta;
4670
4678
  } else if ((event.type === "message.completed" || event.type === "run.completed") && event.text) {
4671
4679
  this.text = event.text;
4680
+ if (event.type === "message.completed") {
4681
+ this.observedMessageCompleted = true;
4682
+ }
4672
4683
  }
4673
4684
  this.eventQueue.push(event);
4674
4685
  }
@@ -4766,7 +4777,7 @@ var AgentRunController = class {
4766
4777
  "Agent run completed before pending permission requests resolved."
4767
4778
  )
4768
4779
  );
4769
- if (result?.text) {
4780
+ if (result?.text && !this.observedMessageCompleted) {
4770
4781
  this.text = result.text;
4771
4782
  }
4772
4783
  if (result && "costData" in result) {
@@ -4811,7 +4822,7 @@ var AgentRunController = class {
4811
4822
  "Agent run was cancelled before pending permission requests resolved."
4812
4823
  )
4813
4824
  );
4814
- if (result?.text) {
4825
+ if (result?.text && !this.observedMessageCompleted) {
4815
4826
  this.text = result.text;
4816
4827
  }
4817
4828
  if (result && "costData" in result) {
@@ -426,7 +426,9 @@ var ClaudeCodeLogAssembler = class {
426
426
  }
427
427
  const final = extractClaudeAssistantContent(message);
428
428
  this.textByMessageId.set(id, final.text);
429
- this.thinkingByMessageId.set(id, final.thinking);
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];
@@ -464,8 +466,8 @@ var ClaudeCodeLogAssembler = class {
464
466
  const text = this.textByMessageId.get(messageId) ?? "";
465
467
  const thinking = this.thinkingByMessageId.get(messageId) ?? "";
466
468
  const content = [];
467
- if (text) content.push({ type: "text", text });
468
469
  if (thinking) content.push({ type: "thinking", thinking });
470
+ if (text) content.push({ type: "text", text });
469
471
  for (const block of extraBlocks) content.push(clone(block));
470
472
  const next = {
471
473
  type: "message.updated",
@@ -1,4 +1,4 @@
1
- export { A as AISDKEvent, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, a0 as PermissionRequestedEvent, a1 as PermissionResolvedEvent, a2 as RawAgentEvent, a3 as ReasoningDeltaEvent, a5 as RunCancelledEvent, a6 as RunCompletedEvent, a7 as RunErrorEvent, a8 as RunStartedEvent, a9 as TextDeltaEvent, ab as ToolCallCompletedEvent, ac as ToolCallDeltaEvent, ad as ToolCallStartedEvent, ag as createNormalizedEvent, ah as normalizeRawAgentEvent, ai as toAISDKEvent, aj as toAISDKStream } from '../types-Ozo1rHKs.js';
1
+ export { A as AISDKEvent, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, a0 as PermissionRequestedEvent, a1 as PermissionResolvedEvent, a2 as RawAgentEvent, a3 as ReasoningDeltaEvent, a5 as RunCancelledEvent, a6 as RunCompletedEvent, a7 as RunErrorEvent, a8 as RunStartedEvent, a9 as TextDeltaEvent, ab as ToolCallCompletedEvent, ac as ToolCallDeltaEvent, ad as ToolCallStartedEvent, ag as createNormalizedEvent, ah as normalizeRawAgentEvent, ai as toAISDKEvent, aj as toAISDKStream } from '../types-DiZSjZma.js';
2
2
  import { AgentProvider } from '../enums.js';
3
3
  import '../Sandbox-K6VNqKeo.js';
4
4
  import 'e2b';
@@ -4,7 +4,7 @@ import {
4
4
  normalizeRawAgentEvent,
5
5
  toAISDKEvent,
6
6
  toAISDKStream
7
- } from "../chunk-NWAXQ7UD.js";
7
+ } from "../chunk-ZDSHOGJ4.js";
8
8
  import "../chunk-GOFJNFAD.js";
9
9
  export {
10
10
  ProviderLogAssembler,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AISDKEvent, a as AgentApprovalMode, b as AgentAttachRequest, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, h as AgentOptions, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, o as AgentProviderName, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, r as AgentResult, s as AgentRun, t as AgentRunConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AttachedRun, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a0 as PermissionRequestedEvent, a1 as PermissionResolvedEvent, a2 as RawAgentEvent, a3 as ReasoningDeltaEvent, a4 as RepoSkillConfig, a5 as RunCancelledEvent, a6 as RunCompletedEvent, a7 as RunErrorEvent, a8 as RunStartedEvent, a9 as TextDeltaEvent, aa as TextPart, ab as ToolCallCompletedEvent, ac as ToolCallDeltaEvent, ad as ToolCallStartedEvent, ae as UserContent, af as UserContentPart, ag as createNormalizedEvent, ah as normalizeRawAgentEvent, ai as toAISDKEvent, aj as toAISDKStream } from './types-Ozo1rHKs.js';
1
+ export { A as AISDKEvent, a as AgentApprovalMode, b as AgentAttachRequest, c as AgentCommandConfig, d as AgentCostData, e as AgentExecutionRequest, f as AgentLocalMcpConfig, g as AgentMcpConfig, h as AgentOptions, i as AgentOptionsBase, j as AgentOptionsMap, k as AgentPermissionDecision, l as AgentPermissionKind, m as AgentPermissionResponse, n as AgentProviderAdapter, o as AgentProviderName, p as AgentReasoningEffort, q as AgentRemoteMcpConfig, r as AgentResult, s as AgentRun, t as AgentRunConfig, u as AgentRunSink, v as AgentSetupRequest, w as AgentSkillConfig, x as AgentSubAgentConfig, y as AttachedRun, C as ClaudeCodeAgentOptions, z as ClaudeCodeHookConfig, B as ClaudeCodeHookEvent, D as ClaudeCodeHookHandler, E as ClaudeCodeHookMatcherGroup, F as ClaudeCodeHooksConfig, G as ClaudeCodeProviderOptions, H as CodexAgentOptions, I as CodexCommandHook, J as CodexHookEvent, K as CodexHookMatcherGroup, L as CodexHooksConfig, M as CodexProviderOptions, N as DataContent, O as EmbeddedSkillConfig, P as FilePart, Q as ImagePart, R as MessageCompletedEvent, S as MessageInjectedEvent, T as MessageStartedEvent, U as NormalizedAgentEvent, V as NormalizedAgentEventBase, W as NormalizedAgentEventType, X as OpenCodeAgentOptions, Y as OpenCodePluginConfig, Z as OpenCodePluginEvent, _ as OpenCodePluginHookConfig, $ as OpenCodeProviderOptions, a0 as PermissionRequestedEvent, a1 as PermissionResolvedEvent, a2 as RawAgentEvent, a3 as ReasoningDeltaEvent, a4 as RepoSkillConfig, a5 as RunCancelledEvent, a6 as RunCompletedEvent, a7 as RunErrorEvent, a8 as RunStartedEvent, a9 as TextDeltaEvent, aa as TextPart, ab as ToolCallCompletedEvent, ac as ToolCallDeltaEvent, ad as ToolCallStartedEvent, ae as UserContent, af as UserContentPart, ag as createNormalizedEvent, ah as normalizeRawAgentEvent, ai as toAISDKEvent, aj as toAISDKStream } from './types-DiZSjZma.js';
2
2
  export { AGENT_RESERVED_PORTS, Agent, collectAllAgentReservedPorts } from './agents/index.js';
3
3
  export { A as AsyncCommandHandle, C as CommandEvent, a as CommandOptions, b as CommandResult, D as DaytonaProviderOptions, c as DaytonaSandboxOptions, E as E2bProviderOptions, d as E2bSandboxOptions, G as GitCloneOptions, L as LocalDockerProviderOptions, e as LocalDockerSandboxOptions, M as ModalProviderOptions, f as ModalSandboxOptions, S as Sandbox, g as SandboxDescriptor, h as SandboxListOptions, i as SandboxOptions, j as SandboxOptionsBase, k as SandboxOptionsMap, l as SandboxProviderName, m as SandboxRaw, n as SandboxRawMap, o as SandboxResourceSpec, T as TarballEntry, V as VercelGitSource, p as VercelProviderOptions, q as VercelSandboxOptions } from './Sandbox-K6VNqKeo.js';
4
4
  export { SandboxAdapter, buildGitCloneCommand } from './sandboxes/index.js';
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  Agent
3
- } from "./chunk-GBM7LKZF.js";
3
+ } from "./chunk-KRSY52XS.js";
4
4
  import {
5
5
  ProviderLogAssembler,
6
6
  createNormalizedEvent,
7
7
  normalizeRawAgentEvent,
8
8
  toAISDKEvent,
9
9
  toAISDKStream
10
- } from "./chunk-NWAXQ7UD.js";
10
+ } from "./chunk-ZDSHOGJ4.js";
11
11
  import {
12
12
  Sandbox,
13
13
  SandboxAdapter,
@@ -385,6 +385,29 @@ interface CodexAgentOptions extends AgentOptionsBase {
385
385
  }
386
386
  interface OpenCodeAgentOptions extends AgentOptionsBase {
387
387
  provider?: OpenCodeProviderOptions;
388
+ /**
389
+ * Setup-time system prompt baked into the opencode agent's `prompt` field.
390
+ *
391
+ * When set, this REPLACES opencode's built-in provider prompt
392
+ * (`anthropic.txt` / `codex.txt` / `gemini.txt` / etc.) and is the most
393
+ * prominent system message the model sees. Use this when you need the
394
+ * prompt to actually steer Anthropic models — opencode appends
395
+ * {@link AgentRunConfig.systemPrompt} *after* its long provider prompt,
396
+ * which Sonnet/Opus tend to ignore in favor of the leading content.
397
+ *
398
+ * Trade-off: replacing the provider prompt drops opencode's hand-tuned
399
+ * Anthropic tool-usage hints. Models still receive tool definitions and
400
+ * the runtime appendix (MCPs/skills/sub-agents/commands) via the
401
+ * per-message `system` field, so tools remain functional — just less
402
+ * prominently announced.
403
+ *
404
+ * Setup-time field: changing it between runs invalidates the
405
+ * setup-manifest cache and triggers a re-upload of the agent config on
406
+ * the next `setup()` call. {@link AgentRunConfig.systemPrompt} continues
407
+ * to work as a per-message override (appended after `agent.prompt`),
408
+ * which is fine for codex/GPT models but weak for Anthropic.
409
+ */
410
+ systemPrompt?: string;
388
411
  }
389
412
  interface ClaudeCodeAgentOptions extends AgentOptionsBase {
390
413
  provider?: ClaudeCodeProviderOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentbox-sdk",
3
- "version": "0.1.303",
3
+ "version": "0.1.305",
4
4
  "description": "Swappable coding agents and sandbox providers for Bun and TypeScript.",
5
5
  "license": "MIT",
6
6
  "repository": {