@geminixiang/mikan 1.0.1 → 1.1.0
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/CHANGELOG.md +52 -0
- package/dist/adapters/discord/context.js +1 -1
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/messages.d.ts +1 -0
- package/dist/adapters/messages.d.ts.map +1 -1
- package/dist/adapters/messages.js +3 -0
- package/dist/adapters/messages.js.map +1 -1
- package/dist/adapters/progressive-renderer.d.ts.map +1 -1
- package/dist/adapters/progressive-renderer.js +132 -147
- package/dist/adapters/progressive-renderer.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +3 -0
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +88 -33
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
- package/dist/adapters/slack/response-lifecycle.js +1 -3
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/telegram/context.js +1 -1
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/types.d.ts +1 -2
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/file-guards.d.ts +2 -0
- package/dist/file-guards.d.ts.map +1 -1
- package/dist/file-guards.js +2 -1
- package/dist/file-guards.js.map +1 -1
- package/dist/harness/execution-env.d.ts.map +1 -1
- package/dist/harness/execution-env.js +82 -5
- package/dist/harness/execution-env.js.map +1 -1
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +21 -28
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/prompt.d.ts +3 -2
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +47 -6
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +5 -3
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session.d.ts +2 -0
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +49 -8
- package/dist/harness/session.js.map +1 -1
- package/dist/harness/tools/task.d.ts +4 -0
- package/dist/harness/tools/task.d.ts.map +1 -1
- package/dist/harness/tools/task.js +12 -0
- package/dist/harness/tools/task.js.map +1 -1
- package/dist/harness/types.d.ts +7 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +15 -0
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +1 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -1
- package/dist/runtime/session-lifecycle.js +17 -1
- package/dist/runtime/session-lifecycle.js.map +1 -1
- package/dist/runtime/types.d.ts +1 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/container.d.ts +2 -1
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +23 -4
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/provisioner.d.ts.map +1 -1
- package/dist/sandbox/provisioner.js +4 -0
- package/dist/sandbox/provisioner.js.map +1 -1
- package/dist/sessions/session-store.d.ts +4 -0
- package/dist/sessions/session-store.d.ts.map +1 -1
- package/dist/sessions/session-store.js +83 -4
- package/dist/sessions/session-store.js.map +1 -1
- package/dist/sessions/types.d.ts +1 -0
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/types.d.ts +7 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,58 @@ change in a minor release.
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [1.1.0] - 2026-10-08
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- A DM task survives a restart. A deploy no longer waits up to five minutes for running
|
|
19
|
+
tasks, and a task interrupted by a deploy or crash in the last 24 hours resumes in its
|
|
20
|
+
thread with a notice. A stopped task stays stopped.
|
|
21
|
+
- A finished task's answer is written to the DM conversation that started it, so a later
|
|
22
|
+
question in the DM can be answered from the result.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Pi packages are upgraded to 1.1.0. Retryable "server busy" provider errors are retried, the
|
|
27
|
+
first system prompt leads the model context so tool changes keep the prompt cache, and
|
|
28
|
+
each tool result records how long it ran. The container sandbox implements Pi's new file
|
|
29
|
+
reader in one `docker exec` per read, as before.
|
|
30
|
+
- Embedders: `ConversationResponder` no longer has `appendResponseDelta` or
|
|
31
|
+
`finishResponse`. `replaceResponse` always receives the whole main message, with
|
|
32
|
+
`{ final: true }` on the final write, and a responder sets `showsPartialAnswer` to receive
|
|
33
|
+
the answer while it is written. A responder that implemented the removed methods stops
|
|
34
|
+
receiving streamed text until it handles `replaceResponse` this way.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- A task run is no longer offered `task_status` and `start_task`, which made one of three
|
|
39
|
+
test tasks report its own status instead of doing the work.
|
|
40
|
+
- A reply's message no longer flickers between its text and the tool checklist. Text written
|
|
41
|
+
before a tool call stays under the checklist until the next answer replaces it, the
|
|
42
|
+
message is updated at most once a second, and the final answer is written once instead of
|
|
43
|
+
three times. A Slack thread reply that has to change earlier text stops streaming and is
|
|
44
|
+
edited in place instead of deleted and posted again.
|
|
45
|
+
- The `...` that marks a reply still being written is removed when the reply ends, also when
|
|
46
|
+
the final edit is first rejected.
|
|
47
|
+
- A signature the model wrote at the end of its last line is replaced, so a reply no longer
|
|
48
|
+
ends with two `Triggered by` lines.
|
|
49
|
+
- A reply no longer streams with its first words missing. The first text of an answer, and
|
|
50
|
+
sometimes its last, never reached the chat while it streamed, so the message jumped when
|
|
51
|
+
the final version replaced it, and a Slack thread reply was deleted and posted again.
|
|
52
|
+
|
|
53
|
+
## [1.0.2] - 2026-10-08
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- The system prompt lists the folders already in the office's `scratch/` and asks the agent
|
|
58
|
+
to reuse an existing clone, with `git fetch` or `git worktree add`, before cloning again.
|
|
59
|
+
A new thread previously could not tell a repository was already there and cloned another copy.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- A command left running in a container sandbox by a crashed or killed daemon is ended
|
|
64
|
+
when the daemon starts again, so a resumed or repeated run does not race the old copy.
|
|
65
|
+
|
|
14
66
|
## [1.0.1] - 2026-10-07
|
|
15
67
|
|
|
16
68
|
### Changed
|
|
@@ -47,7 +47,7 @@ export function createDiscordAdapters(event, bot) {
|
|
|
47
47
|
formatContinuation: formatDiscordContinuation,
|
|
48
48
|
errorPrefix: "*Error:* ",
|
|
49
49
|
workingIndicator: " ...",
|
|
50
|
-
|
|
50
|
+
showsPartialAnswer: true,
|
|
51
51
|
typing: {
|
|
52
52
|
send: () => bot.sendTyping(channelId),
|
|
53
53
|
intervalMs: 8000,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/adapters/discord/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,MAAM,UAAU,GAAG,qBAAqB,GAAG,GAAG,CAAC;AAE/C,MAAM,yBAAyB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,eAAe,OAAO,IAAI,CAAC;AAE1F,SAAS,yBAAyB,CAAC,EAAsB;IACvD,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,KAAmB,EACnB,GAAuB;IAEvB,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;IACpD,MAAM,SAAS,GAAG,cAAc,CAAC;IACjC,MAAM,cAAc,GAAG,yBAAyB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAChG,MAAM,aAAa,GAAG,yBAAyB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEjF,MAAM,OAAO,GAAG,yBAAyB,CAAC;QACxC,QAAQ,EAAE,SAAS;QACnB,cAAc;QACd,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,UAAU,EACR,KAAK,CAAC,UAAU;YAChB,qBAAqB,CAAC;gBACpB,cAAc;gBACd,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;gBACxC,SAAS,EAAE,KAAK,CAAC,EAAE;gBACnB,kBAAkB,EAAE,IAAI;gBACxB,QAAQ,EAAE,KAAK,CAAC,SAAS;aAC1B,CAAC;QACJ,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,MAAM,EAAE,KAAK,CAAC,IAAI;QAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS;KAC1B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAExC,SAAS,SAAS,CAAC,IAAY;QAC7B,IAAI,cAAc;YAAE,OAAO,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QAC7E,IAAI,aAAa;YAAE,OAAO,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC;QACxE,OAAO,GAAG,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,EAAE,SAAS,EAAE,GAAG,yBAAyB,CAAC;QAC9C,KAAK,EAAE,SAAS;QAChB,SAAS,EAAE,UAAU;QACrB,kBAAkB,EAAE,yBAAyB;QAC7C,WAAW,EAAE,WAAW;QACxB,gBAAgB,EAAE,MAAM;QACxB,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/adapters/discord/context.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ConversationContext } from \"../../types.js\";\nimport { createConversationMessage } from \"../../office/index.js\";\nimport { resolveChatSessionKey } from \"../../sessions/session-key.js\";\nimport { createProgressiveRenderer, formatMarkdownToolResult } from \"../progressive-renderer.js\";\nimport { DISCORD_V2_TEXT_LIMIT } from \"./components.js\";\nimport { formatDiscordMarkdown } from \"./format.js\";\nimport type { DiscordEvent, DiscordResponseBot } from \"./types.js\";\n\nconst MAX_LENGTH = DISCORD_V2_TEXT_LIMIT - 100;\n\nconst formatDiscordContinuation = (partNum: number): string => `*(continued ${partNum})*`;\n\nfunction isDiscordMessageReference(id: string | undefined): id is string {\n return typeof id === \"string\" && id !== \"\" && !id.startsWith(\"event:\");\n}\n\nexport function createDiscordAdapters(\n event: DiscordEvent,\n bot: DiscordResponseBot,\n): ConversationContext {\n const conversationId = event.address.conversationId;\n const channelId = conversationId;\n const threadTargetId = isDiscordMessageReference(event.thread_ts) ? event.thread_ts : undefined;\n const replyTargetId = isDiscordMessageReference(event.ts) ? event.ts : undefined;\n\n const message = createConversationMessage({\n platform: \"discord\",\n conversationId,\n address: event.address,\n id: event.ts,\n sessionKey:\n event.sessionKey ??\n resolveChatSessionKey({\n conversationId,\n conversationKind: event.conversationKind,\n messageId: event.ts,\n persistentTopLevel: true,\n threadTs: event.thread_ts,\n }),\n conversationKind: event.conversationKind,\n userId: event.user,\n userName: event.userName,\n text: event.text,\n attachments: event.attachments,\n threadTs: event.thread_ts,\n });\n\n const platform = bot.getMessagingInfo();\n\n function postFirst(text: string): Promise<string> {\n if (threadTargetId) return bot.postInThread(channelId, threadTargetId, text);\n if (replyTargetId) return bot.postReply(channelId, replyTargetId, text);\n return bot.postMessage(channelId, text);\n }\n\n const { responder } = createProgressiveRenderer({\n label: \"Discord\",\n maxLength: MAX_LENGTH,\n formatContinuation: formatDiscordContinuation,\n errorPrefix: \"*Error:* \",\n workingIndicator: \" ...\",\n showsPartialAnswer: true,\n typing: {\n send: () => bot.sendTyping(channelId),\n intervalMs: 8000,\n stopOnSend: true,\n },\n prepareSource: (text) => formatDiscordMarkdown(text),\n formatToolResult: formatMarkdownToolResult,\n responseErrorContext: (responseId) => ({\n platform: \"discord\",\n conversationId,\n channelId,\n messageId: message.id,\n sessionKey: message.sessionKey,\n responseMessageId: responseId,\n threadTs: threadTargetId,\n replyTargetId,\n conversationKind: message.conversationKind,\n }),\n post: postFirst,\n update: (id, text) => bot.updateMessageRaw(channelId, id, text),\n postExtra: async (text, responseId) => {\n if (threadTargetId) return bot.postInThread(channelId, threadTargetId, text);\n if (replyTargetId) return bot.postReply(channelId, replyTargetId, text);\n if (responseId !== null) return bot.postReply(channelId, responseId, text);\n return bot.postMessage(channelId, text);\n },\n delete: (id) => bot.deleteMessageRaw(channelId, id),\n logBotResponse: (text, id) =>\n bot.logBotResponse(channelId, text, id, undefined, {\n answer: { replyTo: message.id, sessionKey: message.sessionKey },\n }),\n uploadFile: (filePath, title) => bot.uploadFile(channelId, filePath, title),\n react: replyTargetId ? (emoji) => bot.addReaction(channelId, replyTargetId, emoji) : undefined,\n });\n\n return { address: message.address, message, responder, platform };\n}\n"]}
|
|
@@ -5,6 +5,7 @@ export declare function formatNothingRunning(source: PlatformSource): string;
|
|
|
5
5
|
export declare function formatStopping(source: PlatformSource): string;
|
|
6
6
|
export declare function formatStopped(source: PlatformSource): string;
|
|
7
7
|
export declare function formatRestarting(source: PlatformSource): string;
|
|
8
|
+
export declare function formatResumingTask(source: PlatformSource): string;
|
|
8
9
|
export declare function formatAlreadyWorking(source: PlatformSource, stopCommand: string, options?: {
|
|
9
10
|
scope?: "thread";
|
|
10
11
|
}): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,KAAK,cAAc,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAoB5D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAK/D;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC7B,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAErF"}
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,KAAK,cAAc,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAoB5D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEnE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAK/D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAKjE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC7B,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAErF"}
|
|
@@ -27,6 +27,9 @@ export function formatStopped(source) {
|
|
|
27
27
|
export function formatRestarting(source) {
|
|
28
28
|
return formatItalic(resolvePlatformName(source), "Restarting for an update; this reply was interrupted. Please send your message again.");
|
|
29
29
|
}
|
|
30
|
+
export function formatResumingTask(source) {
|
|
31
|
+
return formatItalic(resolvePlatformName(source), "Restarted for an update; continuing this task.");
|
|
32
|
+
}
|
|
30
33
|
export function formatAlreadyWorking(source, stopCommand, options) {
|
|
31
34
|
const platformName = resolvePlatformName(source);
|
|
32
35
|
const command = formatCode(platformName, stopCommand);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAIpC,SAAS,mBAAmB,CAAC,MAAsB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,kBAAkB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;IACxE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAClD,OAAO,YAAY,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB,EAAE,IAAY;IACtD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB,EAAE,IAAY;IACpD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAsB;IACrD,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,uFAAuF,CACxF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACvF,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,UAAkB;IAC3E,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,oBAAoB,UAAU,GAAG,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { MessagingBot, MessagingInfo } from \"../types.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = MessagingBot | MessagingInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getMessagingInfo\" in source) return source.getMessagingInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatRestarting(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Restarting for an update; this reply was interrupted. Please send your message again.\",\n );\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n\nexport function formatForceStopped(source: PlatformSource, actorLabel: string): string {\n return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/adapters/messages.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAIpC,SAAS,mBAAmB,CAAC,MAAsB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,kBAAkB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;IACxE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,YAAoB;IAClD,OAAO,YAAY,KAAK,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB,EAAE,IAAY;IACtD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB,EAAE,IAAY;IACpD,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAsB;IACzD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAsB;IACrD,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,uFAAuF,CACxF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB;IACvD,OAAO,YAAY,CACjB,mBAAmB,CAAC,MAAM,CAAC,EAC3B,gDAAgD,CACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAsB,EACtB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GACV,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACvF,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,UAAkB;IAC3E,OAAO,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,oBAAoB,UAAU,GAAG,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { MessagingBot, MessagingInfo } from \"../types.js\";\n\nexport const PRODUCT_NAME = \"mikan\";\n\ntype PlatformSource = MessagingBot | MessagingInfo | string;\n\nfunction resolvePlatformName(source: PlatformSource): string {\n if (typeof source === \"string\") return source;\n if (\"getMessagingInfo\" in source) return source.getMessagingInfo().name;\n return source.name;\n}\n\nfunction supportsHtmlFormatting(platformName: string): boolean {\n return platformName === \"telegram\";\n}\n\nfunction formatItalic(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? text : `_${text}_`;\n}\n\nfunction formatCode(platformName: string, text: string): string {\n return supportsHtmlFormatting(platformName) ? `<code>${text}</code>` : `\\`${text}\\``;\n}\n\nexport function formatNothingRunning(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Nothing running.\");\n}\n\nexport function formatStopping(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopping…\");\n}\n\nexport function formatStopped(source: PlatformSource): string {\n return formatItalic(resolvePlatformName(source), \"Stopped.\");\n}\n\nexport function formatRestarting(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Restarting for an update; this reply was interrupted. Please send your message again.\",\n );\n}\n\nexport function formatResumingTask(source: PlatformSource): string {\n return formatItalic(\n resolvePlatformName(source),\n \"Restarted for an update; continuing this task.\",\n );\n}\n\nexport function formatAlreadyWorking(\n source: PlatformSource,\n stopCommand: string,\n options?: { scope?: \"thread\" },\n): string {\n const platformName = resolvePlatformName(source);\n const command = formatCode(platformName, stopCommand);\n const prefix =\n options?.scope === \"thread\" ? \"Already working in this thread.\" : \"Already working.\";\n return formatItalic(platformName, `${prefix} Send ${command} to cancel.`);\n}\n\nexport function formatForceStopped(source: PlatformSource, actorLabel: string): string {\n return formatItalic(resolvePlatformName(source), `Force stopped by ${actorLabel}.`);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressive-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/progressive-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"progressive-renderer.d.ts","sourceRoot":"","sources":["../../src/adapters/progressive-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EAGtB,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAA8B,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAI1F,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CASvE;AAgeD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,2BAA2B,GAAG;IAChF,SAAS,EAAE,qBAAqB,CAAC;CAClC,CAEA"}
|
|
@@ -27,13 +27,13 @@ class ProgressiveRenderer {
|
|
|
27
27
|
streamActive: false,
|
|
28
28
|
streamUnavailable: false,
|
|
29
29
|
streamedSource: "",
|
|
30
|
-
pendingChars: 0,
|
|
31
|
-
lastFlushAt: 0,
|
|
32
|
-
resetDelta: false,
|
|
33
30
|
typingInterval: null,
|
|
34
31
|
typingFailureWarned: false,
|
|
35
32
|
extraIds: [],
|
|
36
33
|
continuationIds: [],
|
|
34
|
+
shown: null,
|
|
35
|
+
lastWriteAt: 0,
|
|
36
|
+
flushTimer: null,
|
|
37
37
|
};
|
|
38
38
|
this.sanitize = platform.sanitize ?? ((text) => text);
|
|
39
39
|
this.reportResponseError = platform.responseErrorContext
|
|
@@ -45,15 +45,10 @@ class ProgressiveRenderer {
|
|
|
45
45
|
createResponder() {
|
|
46
46
|
return {
|
|
47
47
|
respond: (text) => this.respond(text),
|
|
48
|
-
|
|
49
|
-
? (delta) => this.appendDelta(delta)
|
|
50
|
-
: undefined,
|
|
51
|
-
finishResponse: this.platform.supportsDeltas || this.platform.stream
|
|
52
|
-
? (finalText) => this.finishResponse(finalText)
|
|
53
|
-
: undefined,
|
|
48
|
+
showsPartialAnswer: Boolean(this.platform.showsPartialAnswer || this.platform.stream),
|
|
54
49
|
replaceResponse: (text, options) => this.replaceResponse(text, options),
|
|
55
50
|
replaceSubagentProgress: this.platform.formatSubagentProgress
|
|
56
|
-
? (progress, finalText) => this.replaceSubagentProgress(progress, finalText)
|
|
51
|
+
? (progress, finalText, options) => this.replaceSubagentProgress(progress, finalText, options)
|
|
57
52
|
: undefined,
|
|
58
53
|
respondDiagnostic: (text, options) => this.respondDiagnostic(text, options),
|
|
59
54
|
respondToolResult: (result) => this.respondToolResult(result),
|
|
@@ -116,19 +111,6 @@ class ProgressiveRenderer {
|
|
|
116
111
|
this.state.streamedSource = "";
|
|
117
112
|
await this.platform.stream.stop(streamId);
|
|
118
113
|
}
|
|
119
|
-
async abandonNativeStream() {
|
|
120
|
-
if (!this.platform.stream || this.state.responseId === null)
|
|
121
|
-
return;
|
|
122
|
-
const streamId = this.state.responseId;
|
|
123
|
-
this.state.streamActive = false;
|
|
124
|
-
this.state.streamedSource = "";
|
|
125
|
-
await this.platform.stream.stop(streamId).catch(() => undefined);
|
|
126
|
-
await this.platform.delete?.(streamId).catch((error) => {
|
|
127
|
-
log.logWarning("Could not delete an abandoned stream message", errorMessage(error));
|
|
128
|
-
});
|
|
129
|
-
if (this.state.responseId === streamId)
|
|
130
|
-
this.state.responseId = null;
|
|
131
|
-
}
|
|
132
114
|
async renderRaw(text, operation, options, canonicalText = text) {
|
|
133
115
|
try {
|
|
134
116
|
await this.postSplit(text);
|
|
@@ -150,77 +132,37 @@ class ProgressiveRenderer {
|
|
|
150
132
|
return fallback.text;
|
|
151
133
|
}
|
|
152
134
|
}
|
|
153
|
-
async
|
|
154
|
-
if (this.state.working && !text.trim())
|
|
155
|
-
return text;
|
|
156
|
-
const prepared = this.platform.prepareSource?.(text, this.state.working) ?? text;
|
|
157
|
-
const stream = this.platform.stream;
|
|
158
|
-
const display = this.provisional(prepared, this.state.working);
|
|
159
|
-
if (!stream || this.state.streamUnavailable) {
|
|
160
|
-
await this.renderRaw(display, "render", undefined, prepared);
|
|
161
|
-
return prepared;
|
|
162
|
-
}
|
|
163
|
-
if (this.state.responseId !== null && !this.state.streamActive) {
|
|
164
|
-
await this.renderRaw(display, "render", undefined, prepared);
|
|
165
|
-
return prepared;
|
|
166
|
-
}
|
|
167
|
-
if (this.state.responseId !== null &&
|
|
168
|
-
this.state.streamActive &&
|
|
169
|
-
!prepared.startsWith(this.state.streamedSource)) {
|
|
170
|
-
await this.abandonNativeStream();
|
|
171
|
-
await this.renderRaw(display, "render", undefined, prepared);
|
|
172
|
-
return prepared;
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
if (this.state.responseId !== null) {
|
|
176
|
-
const delta = prepared.slice(this.state.streamedSource.length);
|
|
177
|
-
if (delta && delta.length >= (stream.minDeltaChars ?? 0)) {
|
|
178
|
-
await stream.append(this.state.responseId, delta);
|
|
179
|
-
this.state.streamedSource = prepared;
|
|
180
|
-
}
|
|
181
|
-
return prepared;
|
|
182
|
-
}
|
|
183
|
-
this.state.responseId = await stream.start(prepared);
|
|
184
|
-
this.state.streamActive = true;
|
|
185
|
-
this.state.streamedSource = prepared;
|
|
186
|
-
return prepared;
|
|
187
|
-
}
|
|
188
|
-
catch (err) {
|
|
189
|
-
this.state.streamUnavailable = true;
|
|
190
|
-
log.logWarning("Native response streaming unavailable; falling back to message updates", errorMessage(err));
|
|
191
|
-
await this.abandonNativeStream();
|
|
192
|
-
await this.renderRaw(display, "render", undefined, prepared);
|
|
193
|
-
return prepared;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
async renderFinal(text) {
|
|
135
|
+
async renderFinal(text, options) {
|
|
197
136
|
const stream = this.platform.stream;
|
|
198
137
|
if (stream && this.state.streamActive && this.state.responseId !== null) {
|
|
199
|
-
|
|
138
|
+
const streamId = this.state.responseId;
|
|
139
|
+
const extendsStream = text.startsWith(this.state.streamedSource);
|
|
140
|
+
this.state.streamActive = false;
|
|
200
141
|
try {
|
|
201
|
-
if (
|
|
142
|
+
if (extendsStream) {
|
|
202
143
|
const delta = text.slice(this.state.streamedSource.length);
|
|
203
144
|
if (delta)
|
|
204
|
-
await stream.append(
|
|
205
|
-
await stream.stop(this.state.responseId);
|
|
206
|
-
streamed = true;
|
|
145
|
+
await stream.append(streamId, delta);
|
|
207
146
|
}
|
|
147
|
+
await stream.stop(streamId);
|
|
208
148
|
}
|
|
209
149
|
catch (err) {
|
|
210
150
|
this.state.streamUnavailable = true;
|
|
211
151
|
log.logWarning("Native response streaming unavailable; falling back to message updates", errorMessage(err));
|
|
152
|
+
await stream.stop(streamId).catch(() => undefined);
|
|
153
|
+
return this.renderRaw(text, "replace", options);
|
|
212
154
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (streamed) {
|
|
216
|
-
if (this.platform.needsCanonicalRender?.(text))
|
|
217
|
-
await this.renderRaw(text, "render");
|
|
218
|
-
return text;
|
|
155
|
+
finally {
|
|
156
|
+
this.state.streamedSource = "";
|
|
219
157
|
}
|
|
220
|
-
|
|
158
|
+
if (extendsStream && !this.platform.needsCanonicalRender?.(text))
|
|
159
|
+
return text;
|
|
160
|
+
return this.renderRaw(text, "replace", options);
|
|
221
161
|
}
|
|
162
|
+
if (text === this.state.shown)
|
|
163
|
+
return text;
|
|
222
164
|
if (this.state.responseId !== null || text)
|
|
223
|
-
return this.renderRaw(text, "
|
|
165
|
+
return this.renderRaw(text, "replace", options);
|
|
224
166
|
return text;
|
|
225
167
|
}
|
|
226
168
|
async run(label, operation, work, extra) {
|
|
@@ -235,43 +177,18 @@ class ProgressiveRenderer {
|
|
|
235
177
|
}
|
|
236
178
|
catch { }
|
|
237
179
|
}
|
|
238
|
-
if (label === "
|
|
180
|
+
if (label === "finalResponse")
|
|
239
181
|
throw err;
|
|
240
182
|
});
|
|
241
183
|
this.queueTail = handled.catch(() => undefined);
|
|
242
184
|
return handled;
|
|
243
185
|
}
|
|
244
|
-
async appendDelta(delta) {
|
|
245
|
-
await this.run("appendResponseDelta", "respond", async () => {
|
|
246
|
-
if (!delta)
|
|
247
|
-
return;
|
|
248
|
-
if (this.state.resetDelta) {
|
|
249
|
-
this.state.source = "";
|
|
250
|
-
this.state.pendingChars = 0;
|
|
251
|
-
this.state.resetDelta = false;
|
|
252
|
-
}
|
|
253
|
-
const sanitized = this.sanitize(delta);
|
|
254
|
-
this.state.source += sanitized;
|
|
255
|
-
this.state.pendingChars += sanitized.length;
|
|
256
|
-
const elapsed = this.now() - this.state.lastFlushAt;
|
|
257
|
-
if (this.state.lastFlushAt === 0 ||
|
|
258
|
-
(elapsed >= this.flushIntervalMs && this.state.pendingChars > 0)) {
|
|
259
|
-
this.state.pendingChars = 0;
|
|
260
|
-
try {
|
|
261
|
-
this.state.source = await this.renderDelta(this.state.source);
|
|
262
|
-
}
|
|
263
|
-
finally {
|
|
264
|
-
this.state.lastFlushAt = this.now();
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}, () => ({ textLength: delta.length, accumulatedLength: this.state.source.length }));
|
|
268
|
-
}
|
|
269
186
|
async respond(text) {
|
|
270
187
|
await this.run("respond", "respond", async () => {
|
|
271
188
|
const sanitized = this.sanitize(text);
|
|
272
189
|
this.state.source = this.state.source ? `${this.state.source}\n${sanitized}` : sanitized;
|
|
273
|
-
this.
|
|
274
|
-
|
|
190
|
+
this.cancelFlush();
|
|
191
|
+
await this.renderView();
|
|
275
192
|
if (this.state.responseId !== null && this.platform.logIntermediateResponses) {
|
|
276
193
|
this.platform.logBotResponse?.(text, this.state.responseId);
|
|
277
194
|
}
|
|
@@ -281,37 +198,109 @@ class ProgressiveRenderer {
|
|
|
281
198
|
accumulatedLength: this.state.source.length,
|
|
282
199
|
}));
|
|
283
200
|
}
|
|
284
|
-
async finishResponse(finalText) {
|
|
285
|
-
await this.run("finishResponse", "set_working", async () => {
|
|
286
|
-
if (finalText !== undefined)
|
|
287
|
-
this.state.source = this.sanitize(finalText);
|
|
288
|
-
this.state.resetDelta = false;
|
|
289
|
-
this.state.pendingChars = 0;
|
|
290
|
-
this.stopTyping();
|
|
291
|
-
this.state.working = false;
|
|
292
|
-
this.state.source = await this.renderFinal(this.state.source);
|
|
293
|
-
if (this.state.responseId !== null) {
|
|
294
|
-
this.platform.logBotResponse?.(this.state.source, this.state.responseId);
|
|
295
|
-
}
|
|
296
|
-
await this.platform.onFinish?.(this.state.source, this.state.responseId);
|
|
297
|
-
}, () => ({ finalTextLength: finalText?.length }));
|
|
298
|
-
}
|
|
299
201
|
async replaceResponse(text, options) {
|
|
300
|
-
await this.run("replaceResponse", "replace_response", async () => {
|
|
202
|
+
await this.run(options?.final ? "finalResponse" : "replaceResponse", "replace_response", async () => {
|
|
301
203
|
this.state.source = this.sanitize(text);
|
|
302
|
-
|
|
303
|
-
|
|
204
|
+
if (options?.final)
|
|
205
|
+
await this.finish(options);
|
|
206
|
+
else
|
|
207
|
+
await this.show(options);
|
|
208
|
+
}, () => ({
|
|
209
|
+
textLength: text.length,
|
|
210
|
+
hadExistingResponse: Boolean(this.state.responseId),
|
|
211
|
+
final: options?.final === true,
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
async show(options) {
|
|
215
|
+
if (this.state.working && !this.state.source.trim())
|
|
216
|
+
return;
|
|
217
|
+
const wait = this.state.lastWriteAt + this.flushIntervalMs - this.now();
|
|
218
|
+
if (this.state.working && wait > 0) {
|
|
219
|
+
this.scheduleFlush(wait);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
await this.renderView(options);
|
|
223
|
+
}
|
|
224
|
+
async finish(options) {
|
|
225
|
+
this.stopTyping();
|
|
226
|
+
this.cancelFlush();
|
|
227
|
+
this.state.working = false;
|
|
228
|
+
this.state.source = await this.renderFinal(this.state.source, options);
|
|
229
|
+
this.state.shown = this.state.source;
|
|
230
|
+
this.state.lastWriteAt = this.now();
|
|
231
|
+
if (this.state.responseId !== null) {
|
|
232
|
+
this.platform.logBotResponse?.(this.state.source, this.state.responseId);
|
|
233
|
+
}
|
|
234
|
+
await this.platform.onFinish?.(this.state.source, this.state.responseId);
|
|
235
|
+
}
|
|
236
|
+
scheduleFlush(delayMs) {
|
|
237
|
+
if (this.state.flushTimer !== null)
|
|
238
|
+
return;
|
|
239
|
+
this.state.flushTimer = setTimeout(() => {
|
|
240
|
+
this.state.flushTimer = null;
|
|
241
|
+
void this.run("flushResponse", "replace_response", () => this.renderView(), () => ({ deferred: true }));
|
|
242
|
+
}, delayMs);
|
|
243
|
+
this.state.flushTimer.unref?.();
|
|
244
|
+
}
|
|
245
|
+
cancelFlush() {
|
|
246
|
+
if (this.state.flushTimer === null)
|
|
247
|
+
return;
|
|
248
|
+
clearTimeout(this.state.flushTimer);
|
|
249
|
+
this.state.flushTimer = null;
|
|
250
|
+
}
|
|
251
|
+
async renderView(options) {
|
|
252
|
+
if (this.state.working && !this.state.source.trim())
|
|
253
|
+
return;
|
|
254
|
+
const prepared = this.platform.prepareSource?.(this.state.source, this.state.working) ?? this.state.source;
|
|
255
|
+
const display = this.provisional(prepared, this.state.working);
|
|
256
|
+
if (display === this.state.shown)
|
|
257
|
+
return;
|
|
258
|
+
try {
|
|
259
|
+
await this.writeView(prepared, display, options);
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
this.state.lastWriteAt = this.now();
|
|
263
|
+
}
|
|
264
|
+
this.state.shown = display;
|
|
265
|
+
}
|
|
266
|
+
async writeView(prepared, display, options) {
|
|
267
|
+
const stream = this.platform.stream;
|
|
268
|
+
const canStream = stream !== undefined &&
|
|
269
|
+
this.state.working &&
|
|
270
|
+
!this.state.streamUnavailable &&
|
|
271
|
+
(this.state.responseId === null ||
|
|
272
|
+
(this.state.streamActive && prepared.startsWith(this.state.streamedSource)));
|
|
273
|
+
try {
|
|
274
|
+
if (canStream && this.state.responseId === null) {
|
|
275
|
+
this.state.responseId = await stream.start(prepared);
|
|
276
|
+
this.state.streamActive = true;
|
|
277
|
+
this.state.streamedSource = prepared;
|
|
278
|
+
}
|
|
279
|
+
else if (canStream && this.state.responseId !== null) {
|
|
280
|
+
const delta = prepared.slice(this.state.streamedSource.length);
|
|
281
|
+
if (delta)
|
|
282
|
+
await stream.append(this.state.responseId, delta);
|
|
283
|
+
this.state.streamedSource = prepared;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
if (this.state.streamActive)
|
|
287
|
+
await this.stopNativeStream();
|
|
288
|
+
await this.renderRaw(display, "render", options, prepared);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
if (!canStream)
|
|
293
|
+
throw err;
|
|
294
|
+
this.state.streamUnavailable = true;
|
|
295
|
+
log.logWarning("Native response streaming unavailable; falling back to message updates", errorMessage(err));
|
|
304
296
|
if (this.state.streamActive)
|
|
305
|
-
await this.stopNativeStream();
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const prepared = this.platform.prepareSource?.(this.state.source, this.state.working) ?? this.state.source;
|
|
309
|
-
this.state.source = await this.renderRaw(this.provisional(prepared, this.state.working), "replace", options, prepared);
|
|
310
|
-
}, () => ({ textLength: text.length, hadExistingResponse: Boolean(this.state.responseId) }));
|
|
297
|
+
await this.stopNativeStream().catch(() => undefined);
|
|
298
|
+
await this.renderRaw(display, "render", options, prepared);
|
|
299
|
+
}
|
|
311
300
|
}
|
|
312
|
-
async replaceSubagentProgress(progress, finalText) {
|
|
301
|
+
async replaceSubagentProgress(progress, finalText, options) {
|
|
313
302
|
const dashboard = this.platform.formatSubagentProgress(progress);
|
|
314
|
-
await this.responder.replaceResponse(finalText ? `${dashboard}\n\n${finalText}` : dashboard);
|
|
303
|
+
await this.responder.replaceResponse(finalText ? `${dashboard}\n\n${finalText}` : dashboard, options);
|
|
315
304
|
}
|
|
316
305
|
async respondDiagnostic(text, options = {}) {
|
|
317
306
|
await this.run("respondDiagnostic", "respond_diagnostic", async () => {
|
|
@@ -353,22 +342,16 @@ class ProgressiveRenderer {
|
|
|
353
342
|
async setWorking(working) {
|
|
354
343
|
await this.run("setWorking", "set_working", async () => {
|
|
355
344
|
this.state.working = working;
|
|
356
|
-
if (!working)
|
|
345
|
+
if (!working) {
|
|
357
346
|
this.stopTyping();
|
|
358
|
-
|
|
359
|
-
if (this.state.responseId === null ||
|
|
360
|
-
(!this.platform.workingIndicator && !this.platform.stream)) {
|
|
361
|
-
return;
|
|
347
|
+
this.cancelFlush();
|
|
362
348
|
}
|
|
363
|
-
|
|
349
|
+
await this.platform.onWorkingChanged?.(working, this.state.responseId);
|
|
350
|
+
if (this.state.responseId === null)
|
|
364
351
|
return;
|
|
365
|
-
if (this.state.streamActive
|
|
352
|
+
if (!working && this.state.streamActive)
|
|
366
353
|
await this.stopNativeStream();
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
if (this.state.responseId !== null) {
|
|
370
|
-
this.state.source = await this.renderRaw(this.provisional(this.state.source, working), "render", undefined, this.state.source);
|
|
371
|
-
}
|
|
354
|
+
await this.renderView();
|
|
372
355
|
}, () => ({ working }));
|
|
373
356
|
}
|
|
374
357
|
async uploadFile(filePath, title) {
|
|
@@ -384,6 +367,8 @@ class ProgressiveRenderer {
|
|
|
384
367
|
async deleteResponse() {
|
|
385
368
|
await this.run("deleteResponse", "respond", async () => {
|
|
386
369
|
this.stopTyping();
|
|
370
|
+
this.cancelFlush();
|
|
371
|
+
this.state.shown = null;
|
|
387
372
|
if (this.state.streamActive)
|
|
388
373
|
await this.stopNativeStream().catch(() => undefined);
|
|
389
374
|
for (const id of [...this.state.extraIds, ...this.state.continuationIds]) {
|
|
@@ -405,7 +390,7 @@ class ProgressiveRenderer {
|
|
|
405
390
|
this.state.streamUnavailable = false;
|
|
406
391
|
this.state.streamedSource = "";
|
|
407
392
|
this.state.streamActive = false;
|
|
408
|
-
this.state.
|
|
393
|
+
this.state.lastWriteAt = 0;
|
|
409
394
|
this.state.working = true;
|
|
410
395
|
}, () => ({}));
|
|
411
396
|
}
|