opencode-tbot 0.1.10 → 0.1.11

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/plugin.js CHANGED
@@ -212,16 +212,15 @@ function buildOpenCodeSdkConfig(options) {
212
212
  };
213
213
  }
214
214
  var EMPTY_RESPONSE_TEXT = "OpenCode returned empty response.";
215
- var PROMPT_MESSAGE_POLL_DELAYS_MS = [
215
+ var PROMPT_MESSAGE_POLL_INITIAL_DELAYS_MS = [
216
216
  0,
217
217
  100,
218
218
  250,
219
219
  500,
220
- 1e3,
221
- 2e3,
222
- 4e3,
223
- 8e3
220
+ 1e3
224
221
  ];
222
+ var PROMPT_MESSAGE_POLL_INTERVAL_MS = 2e3;
223
+ var PROMPT_MESSAGE_POLL_TIMEOUT_MS = 6e4;
225
224
  var PROMPT_MESSAGE_POLL_LIMIT = 20;
226
225
  var STRUCTURED_REPLY_SCHEMA = {
227
226
  type: "json_schema",
@@ -376,68 +375,56 @@ var OpenCodeClient = class {
376
375
  if (parts.length === 0) throw new Error("Prompt requires text or file attachments.");
377
376
  const knownMessageIds = await this.captureKnownMessageIds(input.sessionId);
378
377
  const initialData = await this.sendPromptRequest(input, parts);
379
- return buildPromptSessionResult(await this.resolvePromptResponse(input, initialData, knownMessageIds), {
378
+ return buildPromptSessionResult(await this.resolvePromptResponse(input, initialData, knownMessageIds, startedAt), {
380
379
  emptyResponseText: EMPTY_RESPONSE_TEXT,
381
380
  finishedAt: Date.now(),
382
381
  startedAt,
383
382
  structured: input.structured ?? false
384
383
  });
385
384
  }
386
- async resolvePromptResponse(input, data, knownMessageIds) {
385
+ async resolvePromptResponse(input, data, knownMessageIds, startedAt) {
387
386
  const structured = input.structured ?? false;
388
387
  if (!shouldPollPromptMessage(data, structured)) return data;
389
388
  const messageId = extractMessageId(data.info);
390
- let expectedParentId = toAssistantMessage(data.info)?.parentID ?? null;
391
- let bestCandidate = data;
392
- let hasWaited = false;
393
- for (const delayMs of PROMPT_MESSAGE_POLL_DELAYS_MS) {
389
+ const candidateOptions = {
390
+ initialMessageId: messageId,
391
+ initialParentId: toAssistantMessage(data.info)?.parentID ?? null,
392
+ knownMessageIds,
393
+ requestStartedAt: resolvePromptCandidateStartTime(startedAt, data),
394
+ structured
395
+ };
396
+ let bestCandidate = selectPromptResponseCandidate([data], candidateOptions) ?? data;
397
+ const deadlineAt = Date.now() + PROMPT_MESSAGE_POLL_TIMEOUT_MS;
398
+ let idleStatusSeen = false;
399
+ let attempt = 0;
400
+ while (true) {
401
+ const delayMs = getPromptMessagePollDelayMs(attempt);
402
+ attempt += 1;
394
403
  if (delayMs > 0) {
395
- await delay(delayMs);
396
- hasWaited = true;
404
+ const remainingMs = deadlineAt - Date.now();
405
+ if (remainingMs <= 0) break;
406
+ await delay(Math.min(delayMs, remainingMs));
397
407
  }
398
408
  if (messageId) {
399
409
  const next = await this.fetchPromptMessage(input.sessionId, messageId);
400
410
  if (next) {
401
- bestCandidate = selectPromptResponseCandidate([bestCandidate, next], {
402
- initialMessageId: messageId,
403
- initialParentId: expectedParentId,
404
- knownMessageIds,
405
- structured
406
- }) ?? bestCandidate;
407
- expectedParentId = toAssistantMessage(next.info)?.parentID ?? expectedParentId;
408
- if (!shouldPollPromptMessage(next, structured)) return next;
411
+ bestCandidate = selectPromptResponseCandidate([bestCandidate, next], candidateOptions) ?? bestCandidate;
412
+ if (!shouldPollPromptMessage(next, structured)) return bestCandidate;
409
413
  }
410
414
  }
411
- const latest = await this.findLatestPromptResponse(input.sessionId, {
412
- initialMessageId: messageId,
413
- initialParentId: expectedParentId,
414
- knownMessageIds,
415
- structured
416
- });
415
+ const latest = await this.findLatestPromptResponse(input.sessionId, candidateOptions);
417
416
  if (latest) {
418
- bestCandidate = selectPromptResponseCandidate([bestCandidate, latest], {
419
- initialMessageId: messageId,
420
- initialParentId: expectedParentId,
421
- knownMessageIds,
422
- structured
423
- }) ?? bestCandidate;
424
- expectedParentId = toAssistantMessage(latest.info)?.parentID ?? expectedParentId;
425
- if (!shouldPollPromptMessage(latest, structured)) return latest;
417
+ bestCandidate = selectPromptResponseCandidate([bestCandidate, latest], candidateOptions) ?? bestCandidate;
418
+ if (!shouldPollPromptMessage(bestCandidate, structured)) return bestCandidate;
426
419
  }
427
- if ((await this.fetchPromptSessionStatus(input.sessionId))?.type === "idle" && hasWaited) break;
420
+ if ((await this.fetchPromptSessionStatus(input.sessionId))?.type === "idle") {
421
+ if (idleStatusSeen) break;
422
+ idleStatusSeen = true;
423
+ }
424
+ if (Date.now() >= deadlineAt) break;
428
425
  }
429
- const latest = await this.findLatestPromptResponse(input.sessionId, {
430
- initialMessageId: messageId,
431
- initialParentId: expectedParentId,
432
- knownMessageIds,
433
- structured
434
- });
435
- return selectPromptResponseCandidate([bestCandidate, latest], {
436
- initialMessageId: messageId,
437
- initialParentId: expectedParentId,
438
- knownMessageIds,
439
- structured
440
- }) ?? bestCandidate;
426
+ const latest = await this.findLatestPromptResponse(input.sessionId, candidateOptions);
427
+ return selectPromptResponseCandidate([bestCandidate, latest], candidateOptions) ?? bestCandidate;
441
428
  }
442
429
  async fetchPromptMessage(sessionId, messageId) {
443
430
  try {
@@ -709,6 +696,9 @@ function extractMessageId(message) {
709
696
  function delay(ms) {
710
697
  return new Promise((resolve) => setTimeout(resolve, ms));
711
698
  }
699
+ function getPromptMessagePollDelayMs(attempt) {
700
+ return PROMPT_MESSAGE_POLL_INITIAL_DELAYS_MS[attempt] ?? PROMPT_MESSAGE_POLL_INTERVAL_MS;
701
+ }
712
702
  function extractStructuredMarkdown(structured) {
713
703
  const parsed = StructuredReplySchema.safeParse(structured);
714
704
  if (!parsed.success) return null;
@@ -789,19 +779,34 @@ function selectPromptResponseCandidate(candidates, options) {
789
779
  function comparePromptResponseCandidates(left, right, options) {
790
780
  const leftRank = getPromptResponseCandidateRank(left, options);
791
781
  const rightRank = getPromptResponseCandidateRank(right, options);
792
- return Number(rightRank.isUsable) - Number(leftRank.isUsable) || Number(rightRank.isInitial) - Number(leftRank.isInitial) || Number(rightRank.sharesParent) - Number(leftRank.sharesParent) || Number(rightRank.isNew) - Number(leftRank.isNew) || rightRank.createdAt - leftRank.createdAt;
782
+ return Number(rightRank.isUsable) - Number(leftRank.isUsable) || Number(rightRank.isInitial) - Number(leftRank.isInitial) || Number(rightRank.sharesParent) - Number(leftRank.sharesParent) || Number(rightRank.isNewSinceRequestStart) - Number(leftRank.isNewSinceRequestStart) || rightRank.createdAt - leftRank.createdAt;
793
783
  }
794
784
  function getPromptResponseCandidateRank(message, options) {
795
785
  const assistant = toAssistantMessage(message.info);
796
786
  const id = assistant?.id ?? null;
787
+ const createdAt = typeof assistant?.time?.created === "number" && Number.isFinite(assistant.time.created) ? assistant.time.created : 0;
797
788
  return {
798
- createdAt: typeof assistant?.time?.created === "number" && Number.isFinite(assistant.time.created) ? assistant.time.created : 0,
789
+ createdAt,
799
790
  isInitial: !!id && id === options.initialMessageId,
800
- isNew: !!id && !options.knownMessageIds.has(id),
791
+ isNewSinceRequestStart: isPromptResponseNewSinceRequestStart(id, createdAt, options.knownMessageIds, options.requestStartedAt),
801
792
  isUsable: !shouldPollPromptMessage(message, options.structured),
802
793
  sharesParent: !!assistant?.parentID && assistant.parentID === options.initialParentId
803
794
  };
804
795
  }
796
+ function resolvePromptCandidateStartTime(startedAt, initialMessage) {
797
+ const initialCreatedAt = coerceFiniteNumber(toAssistantMessage(initialMessage.info)?.time?.created);
798
+ if (initialCreatedAt === null) return startedAt;
799
+ return areComparablePromptTimestamps(startedAt, initialCreatedAt) ? startedAt : initialCreatedAt;
800
+ }
801
+ function isPromptResponseNewSinceRequestStart(messageId, createdAt, knownMessageIds, requestStartedAt) {
802
+ if (!messageId || knownMessageIds.has(messageId)) return false;
803
+ if (requestStartedAt === null) return true;
804
+ return createdAt >= requestStartedAt;
805
+ }
806
+ function areComparablePromptTimestamps(left, right) {
807
+ const epochThresholdMs = 0xe8d4a51000;
808
+ return left >= epochThresholdMs && right >= epochThresholdMs;
809
+ }
805
810
  function isPlainRecord(value) {
806
811
  return value !== null && typeof value === "object" && !Array.isArray(value);
807
812
  }