opencode-tbot 0.1.5 → 0.1.6
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/plugin.js +70 -14
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ A Telegram plugin for driving [OpenCode](https://opencode.ai) from chat.
|
|
|
22
22
|
Run:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
|
|
25
|
+
npm install opencode-tbot@latest
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
The installer registers the plugin globally and writes the default runtime config.
|
package/README.zh-CN.md
CHANGED
package/dist/plugin.js
CHANGED
|
@@ -214,6 +214,15 @@ function buildOpenCodeSdkConfig(options) {
|
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
216
|
var EMPTY_RESPONSE_TEXT = "OpenCode returned empty response.";
|
|
217
|
+
var PROMPT_MESSAGE_POLL_DELAYS_MS = [
|
|
218
|
+
0,
|
|
219
|
+
150,
|
|
220
|
+
300,
|
|
221
|
+
600,
|
|
222
|
+
1200,
|
|
223
|
+
2e3,
|
|
224
|
+
3200
|
|
225
|
+
];
|
|
217
226
|
var STRUCTURED_REPLY_SCHEMA = {
|
|
218
227
|
type: "json_schema",
|
|
219
228
|
retryCount: 2,
|
|
@@ -327,7 +336,7 @@ var OpenCodeClient = class {
|
|
|
327
336
|
url: file.url
|
|
328
337
|
}))];
|
|
329
338
|
if (parts.length === 0) throw new Error("Prompt requires text or file attachments.");
|
|
330
|
-
const
|
|
339
|
+
const initialData = unwrapSdkData(await this.client.session.prompt({
|
|
331
340
|
sessionID: input.sessionId,
|
|
332
341
|
...input.agent ? { agent: input.agent } : {},
|
|
333
342
|
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
@@ -335,19 +344,36 @@ var OpenCodeClient = class {
|
|
|
335
344
|
...input.variant ? { variant: input.variant } : {},
|
|
336
345
|
parts
|
|
337
346
|
}, SDK_OPTIONS));
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
347
|
+
return buildPromptSessionResult(await this.resolvePromptResponse(input, initialData), {
|
|
348
|
+
emptyResponseText: EMPTY_RESPONSE_TEXT,
|
|
349
|
+
finishedAt: Date.now(),
|
|
350
|
+
startedAt,
|
|
351
|
+
structured: input.structured ?? false
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
async resolvePromptResponse(input, data) {
|
|
355
|
+
if (!shouldPollPromptMessage(data, input.structured ?? false)) return data;
|
|
356
|
+
const messageId = data.info?.id;
|
|
357
|
+
if (!messageId) return data;
|
|
358
|
+
for (const delayMs of PROMPT_MESSAGE_POLL_DELAYS_MS) {
|
|
359
|
+
if (delayMs > 0) await delay(delayMs);
|
|
360
|
+
const next = await this.fetchPromptMessage(input.sessionId, messageId);
|
|
361
|
+
if (!next) continue;
|
|
362
|
+
data = next;
|
|
363
|
+
if (!shouldPollPromptMessage(data, input.structured ?? false)) return data;
|
|
364
|
+
}
|
|
365
|
+
return data;
|
|
366
|
+
}
|
|
367
|
+
async fetchPromptMessage(sessionId, messageId) {
|
|
368
|
+
if (typeof this.client.session.message !== "function") return null;
|
|
369
|
+
try {
|
|
370
|
+
return unwrapSdkData(await this.client.session.message({
|
|
371
|
+
sessionID: sessionId,
|
|
372
|
+
messageID: messageId
|
|
373
|
+
}, SDK_OPTIONS));
|
|
374
|
+
} catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
351
377
|
}
|
|
352
378
|
async loadModels() {
|
|
353
379
|
const [configResponse, providersResponse] = await Promise.all([this.client.config.get(void 0, SDK_OPTIONS), this.client.config.providers(void 0, SDK_OPTIONS)]);
|
|
@@ -450,6 +476,36 @@ function extractTextFromParts(parts) {
|
|
|
450
476
|
if (!Array.isArray(parts)) return "";
|
|
451
477
|
return parts.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
|
|
452
478
|
}
|
|
479
|
+
function buildPromptSessionResult(data, options) {
|
|
480
|
+
const assistantInfo = toAssistantMessage(data.info);
|
|
481
|
+
const bodyMd = options.structured ? extractStructuredMarkdown(assistantInfo?.structured) : null;
|
|
482
|
+
const responseParts = Array.isArray(data.parts) ? data.parts : [];
|
|
483
|
+
const fallbackText = extractTextFromParts(responseParts) || bodyMd || options.emptyResponseText;
|
|
484
|
+
return {
|
|
485
|
+
assistantError: assistantInfo?.error ?? null,
|
|
486
|
+
bodyMd,
|
|
487
|
+
fallbackText,
|
|
488
|
+
info: assistantInfo,
|
|
489
|
+
metrics: extractPromptMetrics(assistantInfo, options.startedAt, options.finishedAt),
|
|
490
|
+
parts: responseParts,
|
|
491
|
+
structured: assistantInfo?.structured ?? null
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function shouldPollPromptMessage(data, structured) {
|
|
495
|
+
const assistantInfo = toAssistantMessage(data.info);
|
|
496
|
+
const bodyMd = structured ? extractStructuredMarkdown(assistantInfo?.structured) : null;
|
|
497
|
+
const hasText = extractTextFromParts(Array.isArray(data.parts) ? data.parts : []).length > 0;
|
|
498
|
+
const hasAssistantError = !!assistantInfo?.error;
|
|
499
|
+
const isCompleted = typeof assistantInfo?.time?.completed === "number" && Number.isFinite(assistantInfo.time.completed);
|
|
500
|
+
return !hasText && !bodyMd && !hasAssistantError && !isCompleted;
|
|
501
|
+
}
|
|
502
|
+
function toAssistantMessage(message) {
|
|
503
|
+
if (!message || typeof message !== "object") return null;
|
|
504
|
+
return !("role" in message) || message.role === "assistant" ? message : null;
|
|
505
|
+
}
|
|
506
|
+
function delay(ms) {
|
|
507
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
508
|
+
}
|
|
453
509
|
function extractStructuredMarkdown(structured) {
|
|
454
510
|
const parsed = StructuredReplySchema.safeParse(structured);
|
|
455
511
|
if (!parsed.success) return null;
|