@geminixiang/mikan 1.0.0-beta.20 → 1.0.0-beta.22
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 +60 -0
- package/README.md +18 -11
- package/dist/adapters/buffered-responder.d.ts +60 -0
- package/dist/adapters/buffered-responder.d.ts.map +1 -0
- package/dist/adapters/buffered-responder.js +201 -0
- package/dist/adapters/buffered-responder.js.map +1 -0
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +42 -177
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +14 -76
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +52 -443
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/client.d.ts +4 -0
- package/dist/adapters/github/client.d.ts.map +1 -1
- package/dist/adapters/github/client.js +5 -0
- package/dist/adapters/github/client.js.map +1 -1
- package/dist/adapters/github/context.d.ts.map +1 -1
- package/dist/adapters/github/context.js +32 -104
- package/dist/adapters/github/context.js.map +1 -1
- package/dist/adapters/github/github-ops.d.ts +90 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +405 -0
- package/dist/adapters/github/github-ops.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +2 -0
- package/dist/adapters/github/repo.d.ts.map +1 -1
- package/dist/adapters/github/repo.js +5 -0
- package/dist/adapters/github/repo.js.map +1 -1
- package/dist/adapters/github/tools/checks.d.ts.map +1 -1
- package/dist/adapters/github/tools/checks.js +6 -17
- package/dist/adapters/github/tools/checks.js.map +1 -1
- package/dist/adapters/github/tools/issue.d.ts.map +1 -1
- package/dist/adapters/github/tools/issue.js +6 -17
- package/dist/adapters/github/tools/issue.js.map +1 -1
- package/dist/adapters/github/tools/pr.d.ts.map +1 -1
- package/dist/adapters/github/tools/pr.js +6 -17
- package/dist/adapters/github/tools/pr.js.map +1 -1
- package/dist/adapters/github/tools/read.d.ts.map +1 -1
- package/dist/adapters/github/tools/read.js +6 -17
- package/dist/adapters/github/tools/read.js.map +1 -1
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
- package/dist/adapters/github/tools/review-reply.js +6 -17
- package/dist/adapters/github/tools/review-reply.js.map +1 -1
- package/dist/adapters/github/tools/sync.d.ts.map +1 -1
- package/dist/adapters/github/tools/sync.js +6 -17
- package/dist/adapters/github/tools/sync.js.map +1 -1
- package/dist/adapters/intake.d.ts.map +1 -1
- package/dist/adapters/intake.js +5 -0
- package/dist/adapters/intake.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +14 -3
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/types.d.ts +2 -0
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +33 -151
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/agent.d.ts +0 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +50 -43
- package/dist/agent.js.map +1 -1
- package/dist/cli/arg-grammar.d.ts +25 -0
- package/dist/cli/arg-grammar.d.ts.map +1 -0
- package/dist/cli/arg-grammar.js +59 -0
- package/dist/cli/arg-grammar.js.map +1 -0
- package/dist/cli/boot.d.ts +16 -0
- package/dist/cli/boot.d.ts.map +1 -0
- package/dist/cli/boot.js +119 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/ext.js +9 -11
- package/dist/cli/ext.js.map +1 -1
- package/dist/commands/extensions.js +2 -2
- package/dist/commands/extensions.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +5 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +8 -8
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +7 -5
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/config.d.ts +0 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -41
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.d.ts +35 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +225 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events.d.ts +0 -10
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +9 -82
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +5 -5
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +84 -118
- package/dist/execution-resolver.js.map +1 -1
- package/dist/harness/event-format.d.ts +66 -0
- package/dist/harness/event-format.d.ts.map +1 -0
- package/dist/harness/event-format.js +112 -0
- package/dist/harness/event-format.js.map +1 -0
- package/dist/harness/extensions/loader.d.ts +9 -6
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +35 -50
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +10 -14
- package/dist/harness/extensions/types.d.ts.map +1 -1
- package/dist/harness/extensions/types.js.map +1 -1
- package/dist/harness/index.d.ts +2 -1
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +1 -0
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/runner.d.ts +20 -0
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +42 -2
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/subagent-runner.d.ts +21 -3
- package/dist/harness/subagent-runner.d.ts.map +1 -1
- package/dist/harness/subagent-runner.js +165 -47
- package/dist/harness/subagent-runner.js.map +1 -1
- package/dist/harness/types.d.ts +11 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.js +69 -121
- package/dist/main.js.map +1 -1
- package/dist/observability/instrument.js +6 -4
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +3 -2
- package/dist/observability/sentry.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +33 -79
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +19 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -0
- package/dist/runtime/session-lifecycle.js +76 -0
- package/dist/runtime/session-lifecycle.js.map +1 -0
- package/dist/runtime/types.d.ts +9 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +1 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +5 -1
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +1 -0
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +5 -1
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +1 -0
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +5 -1
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/gondolin-bootstrap.d.ts +26 -0
- package/dist/sandbox/gondolin-bootstrap.d.ts.map +1 -0
- package/dist/sandbox/gondolin-bootstrap.js +27 -0
- package/dist/sandbox/gondolin-bootstrap.js.map +1 -0
- package/dist/sandbox/gondolin-contract.d.ts +125 -0
- package/dist/sandbox/gondolin-contract.d.ts.map +1 -0
- package/dist/sandbox/gondolin-contract.js +155 -0
- package/dist/sandbox/gondolin-contract.js.map +1 -0
- package/dist/sandbox/gondolin-fleet.d.ts +1 -1
- package/dist/sandbox/gondolin-fleet.d.ts.map +1 -1
- package/dist/sandbox/gondolin-fleet.js +1 -1
- package/dist/sandbox/gondolin-fleet.js.map +1 -1
- package/dist/sandbox/gondolin-gateway.d.ts +1 -0
- package/dist/sandbox/gondolin-gateway.d.ts.map +1 -1
- package/dist/sandbox/gondolin-gateway.js +13 -6
- package/dist/sandbox/gondolin-gateway.js.map +1 -1
- package/dist/sandbox/gondolin-inventory.d.ts +2 -16
- package/dist/sandbox/gondolin-inventory.d.ts.map +1 -1
- package/dist/sandbox/gondolin-inventory.js +2 -12
- package/dist/sandbox/gondolin-inventory.js.map +1 -1
- package/dist/sandbox/gondolin-placement.d.ts +0 -2
- package/dist/sandbox/gondolin-placement.d.ts.map +1 -1
- package/dist/sandbox/gondolin-placement.js +0 -6
- package/dist/sandbox/gondolin-placement.js.map +1 -1
- package/dist/sandbox/gondolin-recovery.d.ts +33 -0
- package/dist/sandbox/gondolin-recovery.d.ts.map +1 -0
- package/dist/sandbox/gondolin-recovery.js +39 -0
- package/dist/sandbox/gondolin-recovery.js.map +1 -0
- package/dist/sandbox/gondolin-remote.d.ts +2 -5
- package/dist/sandbox/gondolin-remote.d.ts.map +1 -1
- package/dist/sandbox/gondolin-remote.js +12 -39
- package/dist/sandbox/gondolin-remote.js.map +1 -1
- package/dist/sandbox/gondolin-worker-client.d.ts +8 -12
- package/dist/sandbox/gondolin-worker-client.d.ts.map +1 -1
- package/dist/sandbox/gondolin-worker-client.js +13 -15
- package/dist/sandbox/gondolin-worker-client.js.map +1 -1
- package/dist/sandbox/gondolin-worker.d.ts +2 -40
- package/dist/sandbox/gondolin-worker.d.ts.map +1 -1
- package/dist/sandbox/gondolin-worker.js.map +1 -1
- package/dist/sandbox/gondolin.d.ts +1 -0
- package/dist/sandbox/gondolin.d.ts.map +1 -1
- package/dist/sandbox/gondolin.js +9 -4
- package/dist/sandbox/gondolin.js.map +1 -1
- package/dist/sandbox/host.d.ts +1 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +4 -0
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/identity.d.ts +11 -16
- package/dist/sandbox/identity.d.ts.map +1 -1
- package/dist/sandbox/identity.js +32 -26
- package/dist/sandbox/identity.js.map +1 -1
- package/dist/sandbox/image.d.ts.map +1 -1
- package/dist/sandbox/image.js +1 -0
- package/dist/sandbox/image.js.map +1 -1
- package/dist/sandbox/index.d.ts +10 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +20 -0
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/types.d.ts +10 -0
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +1 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +5 -2
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +32 -0
- package/dist/sessions/chat-history-sync.d.ts.map +1 -0
- package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +24 -83
- package/dist/sessions/chat-history-sync.js.map +1 -0
- package/dist/sessions/conversation-log.d.ts +13 -0
- package/dist/sessions/conversation-log.d.ts.map +1 -0
- package/dist/sessions/conversation-log.js +47 -0
- package/dist/sessions/conversation-log.js.map +1 -0
- package/dist/sessions/rotation.d.ts +2 -0
- package/dist/sessions/rotation.d.ts.map +1 -0
- package/dist/sessions/rotation.js +39 -0
- package/dist/sessions/rotation.js.map +1 -0
- package/dist/sessions/session-key.d.ts +9 -0
- package/dist/sessions/session-key.d.ts.map +1 -1
- package/dist/sessions/session-key.js +50 -2
- package/dist/sessions/session-key.js.map +1 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +40 -18
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +2 -2
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts +23 -0
- package/dist/settings-mutation.d.ts.map +1 -0
- package/dist/settings-mutation.js +42 -0
- package/dist/settings-mutation.js.map +1 -0
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +27 -46
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/host-fn-tool.d.ts +21 -0
- package/dist/tools/host-fn-tool.d.ts.map +1 -0
- package/dist/tools/host-fn-tool.js +32 -0
- package/dist/tools/host-fn-tool.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/react.d.ts.map +1 -1
- package/dist/tools/react.js +6 -17
- package/dist/tools/react.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +7 -26
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +5 -2
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/subagent-slots.d.ts +28 -0
- package/dist/tools/subagent-slots.d.ts.map +1 -0
- package/dist/tools/subagent-slots.js +72 -0
- package/dist/tools/subagent-slots.js.map +1 -0
- package/dist/tools/subagent.d.ts +17 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +159 -110
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/types.d.ts +10 -9
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/types.d.ts +12 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/date.d.ts +1 -1
- package/dist/utils/date.js +1 -1
- package/dist/utils/date.js.map +1 -1
- package/dist/vault/disabled.d.ts.map +1 -1
- package/dist/vault/disabled.js +0 -1
- package/dist/vault/disabled.js.map +1 -1
- package/dist/vault/index.d.ts +0 -2
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +0 -10
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/injection.d.ts +10 -0
- package/dist/vault/injection.d.ts.map +1 -0
- package/dist/vault/injection.js +30 -0
- package/dist/vault/injection.js.map +1 -0
- package/dist/vault/types.d.ts +4 -2
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/dist/web/admin/portal.d.ts +3 -3
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +41 -39
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/admin/types.d.ts +3 -0
- package/dist/web/admin/types.d.ts.map +1 -1
- package/dist/web/admin/types.js.map +1 -1
- package/dist/web/agent-events/portal.d.ts.map +1 -1
- package/dist/web/agent-events/portal.js +2 -1
- package/dist/web/agent-events/portal.js.map +1 -1
- package/dist/workspace-projection/index.d.ts +5 -0
- package/dist/workspace-projection/index.d.ts.map +1 -0
- package/dist/workspace-projection/index.js +71 -0
- package/dist/workspace-projection/index.js.map +1 -0
- package/dist/workspace-projection/types.d.ts +7 -0
- package/dist/workspace-projection/types.d.ts.map +1 -0
- package/dist/workspace-projection/types.js +2 -0
- package/dist/workspace-projection/types.js.map +1 -0
- package/package.json +1 -1
- package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
- package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
- package/dist/sessions/agent-memory-file-manager.js.map +0 -1
- package/dist/vault/routing.d.ts +0 -4
- package/dist/vault/routing.d.ts.map +0 -1
- package/dist/vault/routing.js +0 -6
- package/dist/vault/routing.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,66 @@ any release.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [1.0.0-beta.22]
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Let subagents opt into a normalized reference snapshot of the active parent conversation with `parentContext`, while keeping fresh isolated context as the default.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Raise default subagent limits from 8 to 100 turns, $0.50 to $10, and 2 to 10 minutes; return concrete budget or timeout reasons.
|
|
21
|
+
- Apply the process-wide subagent concurrency ceiling to both tool- and extension-initiated runs, with cancellation while queued and usage attribution only to the active parent run.
|
|
22
|
+
- Use collision-safe hashed keys for credential authorization and runtime resources. Exact legacy host and shared-container credentials remain readable, but users of ambiguous legacy managed-sandbox keys may need to run `/login` again.
|
|
23
|
+
- Reject unsupported vault file mounts and mounts that overlap workspace or other credential targets.
|
|
24
|
+
- Extract workspace projection and session lifecycle responsibilities into focused modules without intended runtime behavior changes.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Reject session keys belonging to another conversation and unsafe conversation or thread identifiers.
|
|
29
|
+
- Prevent session pointers and thread files from escaping their owning directory or resolving through symlinks.
|
|
30
|
+
- Process Slack messages posted by known human users through user tokens even when Slack includes the posting app's `bot_id`; bot-authored messages remain ignored.
|
|
31
|
+
- Clearly report subagent budget exhaustion instead of returning a generic incomplete status.
|
|
32
|
+
|
|
33
|
+
### Tests
|
|
34
|
+
|
|
35
|
+
- Add Slack E2E coverage for DMs, idle stop, thread isolation, busy queues, images, and multi-file uploads.
|
|
36
|
+
- Add unit coverage for session identity and path safety, collision-safe sandbox identities, vault mount policy, session lifecycle, normalized subagent context, shared slots, cancellation, and budget reporting.
|
|
37
|
+
|
|
38
|
+
## [1.0.0-beta.21]
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Fold each subagent's tokens and cost into the parent run's tally (`MikanAgentSession.recordExternalUsage`), so delegated spend counts against the parent run's budget instead of staying invisible to it.
|
|
43
|
+
- Add a process-wide subagent fan-out ceiling shared across conversations.
|
|
44
|
+
- Add `mikan --help` and a generated `mikan env` inventory from the daemon environment manifest.
|
|
45
|
+
- Make the working-directory argument optional, defaulting to `<state-dir>/workspace`.
|
|
46
|
+
- Add a public Gondolin runtime bootstrap seam for embedders.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Subagent runs never reject: request validation failures (unknown tools, invalid budgets, empty tasks, nested runs) now resolve to `failed` results, so one bad request in a `tasks`/`dag` batch can no longer orphan in-flight sibling subagents.
|
|
51
|
+
- Cap parallel `tasks[]` batches at 4 concurrent subagents (the same limit as DAG mode) and run DAG waves through a slot pool instead of chunk barriers.
|
|
52
|
+
- Report a subagent final response with no text as `failed` instead of `completed` with empty output.
|
|
53
|
+
- Enforce parent budgets immediately when subagent usage is folded into the parent run.
|
|
54
|
+
- Apply one state-directory precedence rule across boot, extensions, Sentry, and runtime readers.
|
|
55
|
+
- Refuse model and sandbox settings updates while a conversation is busy, and invalidate affected cached runners consistently.
|
|
56
|
+
- Drive PM2 environment configuration from `~/.mikan/mikan.env` instead of inline secrets.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- Harden Gondolin dial-home reconnects after transport failures and stale sessions.
|
|
61
|
+
- Reject invalid one-shot event timestamps consistently across all event writers.
|
|
62
|
+
- Apply global model settings to idle conversations and report busy conversations as stale.
|
|
63
|
+
|
|
64
|
+
### Security
|
|
65
|
+
|
|
66
|
+
- Keep PM2 secrets in an owner-only file outside repository trees and make the PM2 template supervision-only.
|
|
67
|
+
|
|
68
|
+
### Tests
|
|
69
|
+
|
|
70
|
+
- Add coverage for subagent accounting and concurrency, CLI and environment manifests, settings mutation, Gondolin reconnects and contracts, event formatting, and worker state layout.
|
|
71
|
+
|
|
12
72
|
## [1.0.0-beta.20]
|
|
13
73
|
|
|
14
74
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
A multi-platform AI coding agent for Slack, Telegram, and Discord.
|
|
11
11
|
|
|
12
|
+
> [!WARNING]
|
|
13
|
+
> **Pre-1.0 status** — the overall framework stabilizes at 1.0.0. Until then, releases may change settings and on-disk data formats without migrations: upgrading between pre-1.0 versions can require resetting or manually adjusting existing state and workspace data.
|
|
14
|
+
|
|
12
15
|
## Architecture
|
|
13
16
|
|
|
14
17
|
mikan keeps the chat record, agent session, and execution runtime separate:
|
|
@@ -59,7 +62,11 @@ npm i -g @geminixiang/mikan pm2
|
|
|
59
62
|
# One-time setup: create the state directory and settings
|
|
60
63
|
mikan --onboard --state-dir=~/.mikan
|
|
61
64
|
|
|
62
|
-
#
|
|
65
|
+
# Secrets live in ~/.mikan/mikan.env (0600), outside any repo tree
|
|
66
|
+
curl -o ~/.mikan/mikan.env https://raw.githubusercontent.com/geminixiang/mikan/main/deploy/pm2/mikan.env.example
|
|
67
|
+
chmod 600 ~/.mikan/mikan.env # then fill in your tokens
|
|
68
|
+
|
|
69
|
+
# Grab the maintained ecosystem file (supervision only), edit `args`
|
|
63
70
|
curl -O https://raw.githubusercontent.com/geminixiang/mikan/main/deploy/pm2/ecosystem.config.cjs
|
|
64
71
|
|
|
65
72
|
pm2 start ecosystem.config.cjs
|
|
@@ -67,21 +74,19 @@ pm2 save
|
|
|
67
74
|
pm2 startup # run the printed command to enable boot autostart
|
|
68
75
|
```
|
|
69
76
|
|
|
70
|
-
In `ecosystem.config.cjs`, point `args` at your state dir, sandbox mode, and working directory:
|
|
77
|
+
Each file has one job: `settings.json` holds behavior (model, sandbox limits, reply modes — the Admin surface), `~/.mikan/mikan.env` holds secrets and platform tokens, and `ecosystem.config.cjs` holds process supervision only. In `ecosystem.config.cjs`, point `args` at your state dir, sandbox mode, and working directory (`mikan --help` documents the flags):
|
|
71
78
|
|
|
72
79
|
```js
|
|
73
80
|
args: "--state-dir=/srv/mikan/state --sandbox=host /srv/mikan/workspace",
|
|
74
81
|
```
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
Set the platform tokens you need in `~/.mikan/mikan.env`; you can run multiple platforms at once. `mikan env` prints the full inventory and what is currently set:
|
|
77
84
|
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
DISCORD_BOT_TOKEN: "MTI...",
|
|
84
|
-
},
|
|
85
|
+
```bash
|
|
86
|
+
SLACK_APP_TOKEN=xapp-...
|
|
87
|
+
SLACK_BOT_TOKEN=xoxb-...
|
|
88
|
+
TELEGRAM_BOT_TOKEN=123456:ABC-...
|
|
89
|
+
DISCORD_BOT_TOKEN=MTI...
|
|
85
90
|
```
|
|
86
91
|
|
|
87
92
|
Tail logs with `pm2 logs mikan`; upgrade with `npm i -g @geminixiang/mikan && pm2 reload mikan`. See [the deployment guide](src/content/docs/deployment.mdx) for sandbox images, graceful shutdown, and the health endpoint.
|
|
@@ -89,9 +94,11 @@ Tail logs with `pm2 logs mikan`; upgrade with `npm i -g @geminixiang/mikan && pm
|
|
|
89
94
|
For a one-off foreground run, the same CLI works directly:
|
|
90
95
|
|
|
91
96
|
```bash
|
|
92
|
-
mikan [--state-dir=~/.mikan] [--sandbox=<mode>] <working-directory>
|
|
97
|
+
mikan [--state-dir=~/.mikan] [--sandbox=<mode>] [<working-directory>]
|
|
93
98
|
```
|
|
94
99
|
|
|
100
|
+
The working directory is optional: it defaults to `<state-dir>/workspace` (so `~/.mikan/workspace` with the default state dir) and is created on first run.
|
|
101
|
+
|
|
95
102
|
## Platforms
|
|
96
103
|
|
|
97
104
|
- **Slack** — create a Socket Mode app using [src/content/docs/slack-bot-minimal-guide.md](src/content/docs/slack-bot-minimal-guide.md). The bot responds when `@mentioned` in channels and to all DMs.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ChatToolResult, ConversationResponder } from "../adapter.js";
|
|
2
|
+
import { type ChatResponseErrorOperation } from "./shared.js";
|
|
3
|
+
/**
|
|
4
|
+
* The per-platform verbs and policy behind one buffered responder. Everything
|
|
5
|
+
* else — the accumulated-text state machine, split-first-then-continuations
|
|
6
|
+
* posting, response-id capture, ordered-queue error choreography, typing
|
|
7
|
+
* interval, working indicator, delete semantics — is owned by
|
|
8
|
+
* {@link createBufferedResponder} and identical on every buffered platform.
|
|
9
|
+
* (Slack keeps its own streaming lifecycle; this covers the platforms that
|
|
10
|
+
* edit one response message in place.)
|
|
11
|
+
*/
|
|
12
|
+
export interface BufferedResponderPlatform {
|
|
13
|
+
/** Log label, e.g. "Discord". */
|
|
14
|
+
label: string;
|
|
15
|
+
/** Hard message length; longer responses continue in extra messages. */
|
|
16
|
+
maxLength: number;
|
|
17
|
+
formatContinuation: (partNum: number) => string;
|
|
18
|
+
/** Prefix for respondDiagnostic({style:"error"}). */
|
|
19
|
+
errorPrefix: string;
|
|
20
|
+
/** Platform text normalization applied before accumulation (e.g. HTML). */
|
|
21
|
+
sanitize?: (text: string) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Suffix rendered while the run is working (and re-rendered away by
|
|
24
|
+
* setWorking(false)). Platforms without one leave setWorking to typing.
|
|
25
|
+
*/
|
|
26
|
+
workingIndicator?: string;
|
|
27
|
+
/** Enable appendResponseDelta/finishResponse over a buffered stream. */
|
|
28
|
+
streaming: boolean;
|
|
29
|
+
typing?: {
|
|
30
|
+
send: () => Promise<unknown>;
|
|
31
|
+
intervalMs: number;
|
|
32
|
+
/** Also stop the indicator when a message is actually sent. */
|
|
33
|
+
stopOnSend?: boolean;
|
|
34
|
+
};
|
|
35
|
+
formatToolResult: (result: ChatToolResult) => string;
|
|
36
|
+
reportError: (err: unknown, operation: ChatResponseErrorOperation, extra: Record<string, unknown>) => void;
|
|
37
|
+
/** Posted into the conversation after a send fails (e.g. Telegram's ⚠️). */
|
|
38
|
+
notifySendFailure?: (errorMessage: string) => Promise<void>;
|
|
39
|
+
/** Post the first response message; returns its platform id. */
|
|
40
|
+
post: (text: string) => Promise<string>;
|
|
41
|
+
/** Edit the existing response message. */
|
|
42
|
+
update: (id: string, text: string) => Promise<void>;
|
|
43
|
+
/** Post an out-of-band message (continuations, diagnostics). */
|
|
44
|
+
postExtra: (text: string, responseId: string | null) => Promise<unknown>;
|
|
45
|
+
/** Delete the response message. */
|
|
46
|
+
delete?: (id: string) => Promise<void>;
|
|
47
|
+
/** Record a bot response chunk against the response message id. */
|
|
48
|
+
logBotResponse?: (text: string, id: string) => void;
|
|
49
|
+
/** Direct upload; absent platforms fall back to uploadFallbackNote. */
|
|
50
|
+
uploadFile?: (filePath: string, title?: string) => Promise<void>;
|
|
51
|
+
/** Posted (queued) instead of uploading when uploadFile is absent. */
|
|
52
|
+
uploadFallbackNote?: (name: string) => string;
|
|
53
|
+
react?: (emoji: string) => Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/** The tool-result rendering shared by the Markdown platforms (Discord, GitHub). */
|
|
56
|
+
export declare function formatMarkdownToolResult(result: ChatToolResult): string;
|
|
57
|
+
export declare function createBufferedResponder(platform: BufferedResponderPlatform): {
|
|
58
|
+
responder: ConversationResponder;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=buffered-responder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffered-responder.d.ts","sourceRoot":"","sources":["../../src/adapters/buffered-responder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE3E,OAAO,EAA6B,KAAK,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAGzF;;;;;;;;GAQG;AACH,MAAM,WAAW,yBAAyB;IACxC,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,+DAA+D;QAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,gBAAgB,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,MAAM,CAAC;IACrD,WAAW,EAAE,CACX,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,0BAA0B,EACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,IAAI,CAAC;IACV,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,gEAAgE;IAChE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,0CAA0C;IAC1C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,gEAAgE;IAChE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,mCAAmC;IACnC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,mEAAmE;IACnE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,oFAAoF;AACpF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CASvE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,yBAAyB,GAAG;IAC5E,SAAS,EAAE,qBAAqB,CAAC;CAClC,CAoPA"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import * as log from "../log.js";
|
|
2
|
+
import { formatToolArgs, splitText } from "./shared.js";
|
|
3
|
+
import { BufferedResponseStream, OrderedResponseOperations } from "./streaming.js";
|
|
4
|
+
/** The tool-result rendering shared by the Markdown platforms (Discord, GitHub). */
|
|
5
|
+
export function formatMarkdownToolResult(result) {
|
|
6
|
+
const argsFormatted = formatToolArgs(result.args);
|
|
7
|
+
const duration = (result.durationMs / 1000).toFixed(1);
|
|
8
|
+
let text = `**${result.isError ? "Error" : "Done"} ${result.toolName}**`;
|
|
9
|
+
if (result.label)
|
|
10
|
+
text += `: ${result.label}`;
|
|
11
|
+
text += ` (${duration}s)\n`;
|
|
12
|
+
if (argsFormatted)
|
|
13
|
+
text += `\`\`\`\n${argsFormatted}\n\`\`\`\n`;
|
|
14
|
+
text += `**Result:**\n\`\`\`\n${result.result}\n\`\`\``;
|
|
15
|
+
return text;
|
|
16
|
+
}
|
|
17
|
+
export function createBufferedResponder(platform) {
|
|
18
|
+
let responseId = null;
|
|
19
|
+
let accumulatedText = "";
|
|
20
|
+
let isWorking = true;
|
|
21
|
+
const queue = new OrderedResponseOperations();
|
|
22
|
+
let typingInterval = null;
|
|
23
|
+
let typingFailureWarned = false;
|
|
24
|
+
const sanitize = platform.sanitize ?? ((text) => text);
|
|
25
|
+
function stopTyping() {
|
|
26
|
+
if (typingInterval !== null) {
|
|
27
|
+
clearInterval(typingInterval);
|
|
28
|
+
typingInterval = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** The response text as currently displayed (working indicator applied). */
|
|
32
|
+
function render(text) {
|
|
33
|
+
return platform.workingIndicator && isWorking ? text + platform.workingIndicator : text;
|
|
34
|
+
}
|
|
35
|
+
async function postOrUpdate(displayText) {
|
|
36
|
+
if (responseId !== null) {
|
|
37
|
+
await platform.update(responseId, displayText);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (platform.typing?.stopOnSend)
|
|
41
|
+
stopTyping();
|
|
42
|
+
responseId = await platform.post(displayText);
|
|
43
|
+
}
|
|
44
|
+
async function postExtra(text) {
|
|
45
|
+
if (platform.typing?.stopOnSend)
|
|
46
|
+
stopTyping();
|
|
47
|
+
await platform.postExtra(text, responseId);
|
|
48
|
+
}
|
|
49
|
+
async function postSplit(text) {
|
|
50
|
+
const [head, ...tail] = splitText(text, platform.maxLength, platform.formatContinuation);
|
|
51
|
+
await postOrUpdate(head);
|
|
52
|
+
for (const part of tail) {
|
|
53
|
+
await postExtra(part);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const stream = new BufferedResponseStream({
|
|
57
|
+
flush: async (text) => {
|
|
58
|
+
await postSplit(render(text));
|
|
59
|
+
},
|
|
60
|
+
finish: async (text) => {
|
|
61
|
+
isWorking = false;
|
|
62
|
+
stopTyping();
|
|
63
|
+
await postSplit(text);
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
function run(label, operation, work, extra) {
|
|
67
|
+
return queue.run(work, async (err) => {
|
|
68
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69
|
+
log.logWarning(`${platform.label} ${label} error`, message);
|
|
70
|
+
platform.reportError(err, operation, extra(err));
|
|
71
|
+
if (platform.notifySendFailure) {
|
|
72
|
+
try {
|
|
73
|
+
await platform.notifySendFailure(message);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// ignore secondary failure
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const responder = {
|
|
82
|
+
respond: async (text) => {
|
|
83
|
+
await run("respond", "respond", async () => {
|
|
84
|
+
const sanitized = sanitize(text);
|
|
85
|
+
accumulatedText = accumulatedText ? `${accumulatedText}\n${sanitized}` : sanitized;
|
|
86
|
+
stream.setText(accumulatedText);
|
|
87
|
+
await postSplit(render(accumulatedText));
|
|
88
|
+
if (responseId !== null) {
|
|
89
|
+
platform.logBotResponse?.(text, responseId);
|
|
90
|
+
}
|
|
91
|
+
}, () => ({
|
|
92
|
+
phase: responseId ? "update" : "initial_post",
|
|
93
|
+
textLength: text.length,
|
|
94
|
+
accumulatedLength: accumulatedText.length,
|
|
95
|
+
}));
|
|
96
|
+
},
|
|
97
|
+
...(platform.streaming
|
|
98
|
+
? {
|
|
99
|
+
appendResponseDelta: async (delta) => {
|
|
100
|
+
await run("appendResponseDelta", "respond", async () => {
|
|
101
|
+
await stream.append(sanitize(delta));
|
|
102
|
+
accumulatedText = stream.getText();
|
|
103
|
+
if (responseId !== null) {
|
|
104
|
+
platform.logBotResponse?.(delta, responseId);
|
|
105
|
+
}
|
|
106
|
+
}, () => ({ textLength: delta.length, accumulatedLength: stream.getText().length }));
|
|
107
|
+
},
|
|
108
|
+
finishResponse: async (finalText) => {
|
|
109
|
+
await run("finishResponse", "set_working", async () => {
|
|
110
|
+
await stream.finish(finalText === undefined ? undefined : sanitize(finalText));
|
|
111
|
+
accumulatedText = stream.getText();
|
|
112
|
+
}, () => ({ finalTextLength: finalText?.length }));
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
: {}),
|
|
116
|
+
replaceResponse: async (text) => {
|
|
117
|
+
await run("replaceResponse", "replace_response", async () => {
|
|
118
|
+
accumulatedText = sanitize(text);
|
|
119
|
+
stream.setText(accumulatedText);
|
|
120
|
+
await postSplit(accumulatedText);
|
|
121
|
+
}, () => ({
|
|
122
|
+
textLength: text.length,
|
|
123
|
+
hadExistingResponse: Boolean(responseId),
|
|
124
|
+
}));
|
|
125
|
+
},
|
|
126
|
+
respondDiagnostic: async (text, options) => {
|
|
127
|
+
await run("respondDiagnostic", "respond_diagnostic", async () => {
|
|
128
|
+
const prefix = options?.style === "error" ? platform.errorPrefix : "";
|
|
129
|
+
for (const part of splitText(sanitize(`${prefix}${text}`), platform.maxLength, platform.formatContinuation)) {
|
|
130
|
+
await postExtra(part);
|
|
131
|
+
}
|
|
132
|
+
}, () => ({ textLength: text.length, style: options?.style }));
|
|
133
|
+
},
|
|
134
|
+
respondToolResult: async (result) => {
|
|
135
|
+
await responder.respondDiagnostic(platform.formatToolResult(result));
|
|
136
|
+
},
|
|
137
|
+
setTyping: async (isTyping) => {
|
|
138
|
+
const typing = platform.typing;
|
|
139
|
+
if (!typing)
|
|
140
|
+
return;
|
|
141
|
+
const onTypingError = (err) => {
|
|
142
|
+
if (typingFailureWarned)
|
|
143
|
+
return;
|
|
144
|
+
typingFailureWarned = true;
|
|
145
|
+
log.logWarning(`${platform.label} sendTyping failed (further occurrences suppressed for this session)`, err instanceof Error ? err.message : String(err));
|
|
146
|
+
};
|
|
147
|
+
if (isTyping && typingInterval === null) {
|
|
148
|
+
typing.send().catch(onTypingError);
|
|
149
|
+
typingInterval = setInterval(() => {
|
|
150
|
+
typing.send().catch(onTypingError);
|
|
151
|
+
}, typing.intervalMs);
|
|
152
|
+
}
|
|
153
|
+
else if (!isTyping) {
|
|
154
|
+
stopTyping();
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
setWorking: async (working) => {
|
|
158
|
+
if (!platform.workingIndicator) {
|
|
159
|
+
if (!working)
|
|
160
|
+
stopTyping();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
await run("setWorking", "set_working", async () => {
|
|
164
|
+
isWorking = working;
|
|
165
|
+
if (!working)
|
|
166
|
+
stopTyping();
|
|
167
|
+
if (responseId !== null) {
|
|
168
|
+
const [head] = splitText(render(accumulatedText), platform.maxLength, platform.formatContinuation);
|
|
169
|
+
await platform.update(responseId, head);
|
|
170
|
+
}
|
|
171
|
+
}, () => ({ working }));
|
|
172
|
+
},
|
|
173
|
+
uploadFile: async (filePath, title) => {
|
|
174
|
+
if (platform.uploadFile) {
|
|
175
|
+
await platform.uploadFile(filePath, title);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const note = platform.uploadFallbackNote?.(title ?? filePath);
|
|
179
|
+
if (note === undefined)
|
|
180
|
+
return;
|
|
181
|
+
await run("uploadFile", "respond_diagnostic", () => postExtra(note), () => ({ filePath }));
|
|
182
|
+
},
|
|
183
|
+
...(platform.react ? { react: platform.react } : {}),
|
|
184
|
+
deleteResponse: async () => {
|
|
185
|
+
await queue.run(async () => {
|
|
186
|
+
stopTyping();
|
|
187
|
+
if (responseId !== null) {
|
|
188
|
+
try {
|
|
189
|
+
await platform.delete?.(responseId);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Ignore errors
|
|
193
|
+
}
|
|
194
|
+
responseId = null;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
return { responder };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=buffered-responder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffered-responder.js","sourceRoot":"","sources":["../../src/adapters/buffered-responder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatToolResult, ConversationResponder } from \"../adapter.js\";\nimport * as log from \"../log.js\";\nimport { formatToolArgs, splitText, type ChatResponseErrorOperation } from \"./shared.js\";\nimport { BufferedResponseStream, OrderedResponseOperations } from \"./streaming.js\";\n\n/**\n * The per-platform verbs and policy behind one buffered responder. Everything\n * else — the accumulated-text state machine, split-first-then-continuations\n * posting, response-id capture, ordered-queue error choreography, typing\n * interval, working indicator, delete semantics — is owned by\n * {@link createBufferedResponder} and identical on every buffered platform.\n * (Slack keeps its own streaming lifecycle; this covers the platforms that\n * edit one response message in place.)\n */\nexport interface BufferedResponderPlatform {\n /** Log label, e.g. \"Discord\". */\n label: string;\n /** Hard message length; longer responses continue in extra messages. */\n maxLength: number;\n formatContinuation: (partNum: number) => string;\n /** Prefix for respondDiagnostic({style:\"error\"}). */\n errorPrefix: string;\n /** Platform text normalization applied before accumulation (e.g. HTML). */\n sanitize?: (text: string) => string;\n /**\n * Suffix rendered while the run is working (and re-rendered away by\n * setWorking(false)). Platforms without one leave setWorking to typing.\n */\n workingIndicator?: string;\n /** Enable appendResponseDelta/finishResponse over a buffered stream. */\n streaming: boolean;\n typing?: {\n send: () => Promise<unknown>;\n intervalMs: number;\n /** Also stop the indicator when a message is actually sent. */\n stopOnSend?: boolean;\n };\n formatToolResult: (result: ChatToolResult) => string;\n reportError: (\n err: unknown,\n operation: ChatResponseErrorOperation,\n extra: Record<string, unknown>,\n ) => void;\n /** Posted into the conversation after a send fails (e.g. Telegram's ⚠️). */\n notifySendFailure?: (errorMessage: string) => Promise<void>;\n /** Post the first response message; returns its platform id. */\n post: (text: string) => Promise<string>;\n /** Edit the existing response message. */\n update: (id: string, text: string) => Promise<void>;\n /** Post an out-of-band message (continuations, diagnostics). */\n postExtra: (text: string, responseId: string | null) => Promise<unknown>;\n /** Delete the response message. */\n delete?: (id: string) => Promise<void>;\n /** Record a bot response chunk against the response message id. */\n logBotResponse?: (text: string, id: string) => void;\n /** Direct upload; absent platforms fall back to uploadFallbackNote. */\n uploadFile?: (filePath: string, title?: string) => Promise<void>;\n /** Posted (queued) instead of uploading when uploadFile is absent. */\n uploadFallbackNote?: (name: string) => string;\n react?: (emoji: string) => Promise<void>;\n}\n\n/** The tool-result rendering shared by the Markdown platforms (Discord, GitHub). */\nexport function formatMarkdownToolResult(result: ChatToolResult): string {\n const argsFormatted = formatToolArgs(result.args);\n const duration = (result.durationMs / 1000).toFixed(1);\n let text = `**${result.isError ? \"Error\" : \"Done\"} ${result.toolName}**`;\n if (result.label) text += `: ${result.label}`;\n text += ` (${duration}s)\\n`;\n if (argsFormatted) text += `\\`\\`\\`\\n${argsFormatted}\\n\\`\\`\\`\\n`;\n text += `**Result:**\\n\\`\\`\\`\\n${result.result}\\n\\`\\`\\``;\n return text;\n}\n\nexport function createBufferedResponder(platform: BufferedResponderPlatform): {\n responder: ConversationResponder;\n} {\n let responseId: string | null = null;\n let accumulatedText = \"\";\n let isWorking = true;\n const queue = new OrderedResponseOperations();\n let typingInterval: ReturnType<typeof setInterval> | null = null;\n let typingFailureWarned = false;\n\n const sanitize = platform.sanitize ?? ((text: string) => text);\n\n function stopTyping(): void {\n if (typingInterval !== null) {\n clearInterval(typingInterval);\n typingInterval = null;\n }\n }\n\n /** The response text as currently displayed (working indicator applied). */\n function render(text: string): string {\n return platform.workingIndicator && isWorking ? text + platform.workingIndicator : text;\n }\n\n async function postOrUpdate(displayText: string): Promise<void> {\n if (responseId !== null) {\n await platform.update(responseId, displayText);\n return;\n }\n if (platform.typing?.stopOnSend) stopTyping();\n responseId = await platform.post(displayText);\n }\n\n async function postExtra(text: string): Promise<void> {\n if (platform.typing?.stopOnSend) stopTyping();\n await platform.postExtra(text, responseId);\n }\n\n async function postSplit(text: string): Promise<void> {\n const [head, ...tail] = splitText(text, platform.maxLength, platform.formatContinuation);\n await postOrUpdate(head);\n for (const part of tail) {\n await postExtra(part);\n }\n }\n\n const stream = new BufferedResponseStream({\n flush: async (text) => {\n await postSplit(render(text));\n },\n finish: async (text) => {\n isWorking = false;\n stopTyping();\n await postSplit(text);\n },\n });\n\n function run(\n label: string,\n operation: ChatResponseErrorOperation,\n work: () => Promise<void>,\n extra: (err: unknown) => Record<string, unknown>,\n ): Promise<void> {\n return queue.run(work, async (err) => {\n const message = err instanceof Error ? err.message : String(err);\n log.logWarning(`${platform.label} ${label} error`, message);\n platform.reportError(err, operation, extra(err));\n if (platform.notifySendFailure) {\n try {\n await platform.notifySendFailure(message);\n } catch {\n // ignore secondary failure\n }\n }\n });\n }\n\n const responder: ConversationResponder = {\n respond: async (text: string) => {\n await run(\n \"respond\",\n \"respond\",\n async () => {\n const sanitized = sanitize(text);\n accumulatedText = accumulatedText ? `${accumulatedText}\\n${sanitized}` : sanitized;\n stream.setText(accumulatedText);\n await postSplit(render(accumulatedText));\n if (responseId !== null) {\n platform.logBotResponse?.(text, responseId);\n }\n },\n () => ({\n phase: responseId ? \"update\" : \"initial_post\",\n textLength: text.length,\n accumulatedLength: accumulatedText.length,\n }),\n );\n },\n\n ...(platform.streaming\n ? {\n appendResponseDelta: async (delta: string) => {\n await run(\n \"appendResponseDelta\",\n \"respond\",\n async () => {\n await stream.append(sanitize(delta));\n accumulatedText = stream.getText();\n if (responseId !== null) {\n platform.logBotResponse?.(delta, responseId);\n }\n },\n () => ({ textLength: delta.length, accumulatedLength: stream.getText().length }),\n );\n },\n\n finishResponse: async (finalText?: string) => {\n await run(\n \"finishResponse\",\n \"set_working\",\n async () => {\n await stream.finish(finalText === undefined ? undefined : sanitize(finalText));\n accumulatedText = stream.getText();\n },\n () => ({ finalTextLength: finalText?.length }),\n );\n },\n }\n : {}),\n\n replaceResponse: async (text: string) => {\n await run(\n \"replaceResponse\",\n \"replace_response\",\n async () => {\n accumulatedText = sanitize(text);\n stream.setText(accumulatedText);\n await postSplit(accumulatedText);\n },\n () => ({\n textLength: text.length,\n hadExistingResponse: Boolean(responseId),\n }),\n );\n },\n\n respondDiagnostic: async (text: string, options?: { style?: \"muted\" | \"error\" }) => {\n await run(\n \"respondDiagnostic\",\n \"respond_diagnostic\",\n async () => {\n const prefix = options?.style === \"error\" ? platform.errorPrefix : \"\";\n for (const part of splitText(\n sanitize(`${prefix}${text}`),\n platform.maxLength,\n platform.formatContinuation,\n )) {\n await postExtra(part);\n }\n },\n () => ({ textLength: text.length, style: options?.style }),\n );\n },\n\n respondToolResult: async (result: ChatToolResult) => {\n await responder.respondDiagnostic(platform.formatToolResult(result));\n },\n\n setTyping: async (isTyping: boolean) => {\n const typing = platform.typing;\n if (!typing) return;\n const onTypingError = (err: unknown): void => {\n if (typingFailureWarned) return;\n typingFailureWarned = true;\n log.logWarning(\n `${platform.label} sendTyping failed (further occurrences suppressed for this session)`,\n err instanceof Error ? err.message : String(err),\n );\n };\n if (isTyping && typingInterval === null) {\n typing.send().catch(onTypingError);\n typingInterval = setInterval(() => {\n typing.send().catch(onTypingError);\n }, typing.intervalMs);\n } else if (!isTyping) {\n stopTyping();\n }\n },\n\n setWorking: async (working: boolean) => {\n if (!platform.workingIndicator) {\n if (!working) stopTyping();\n return;\n }\n await run(\n \"setWorking\",\n \"set_working\",\n async () => {\n isWorking = working;\n if (!working) stopTyping();\n if (responseId !== null) {\n const [head] = splitText(\n render(accumulatedText),\n platform.maxLength,\n platform.formatContinuation,\n );\n await platform.update(responseId, head);\n }\n },\n () => ({ working }),\n );\n },\n\n uploadFile: async (filePath: string, title?: string) => {\n if (platform.uploadFile) {\n await platform.uploadFile(filePath, title);\n return;\n }\n const note = platform.uploadFallbackNote?.(title ?? filePath);\n if (note === undefined) return;\n await run(\n \"uploadFile\",\n \"respond_diagnostic\",\n () => postExtra(note),\n () => ({ filePath }),\n );\n },\n\n ...(platform.react ? { react: platform.react } : {}),\n\n deleteResponse: async () => {\n await queue.run(async () => {\n stopTyping();\n if (responseId !== null) {\n try {\n await platform.delete?.(responseId);\n } catch {\n // Ignore errors\n }\n responseId = null;\n }\n });\n },\n };\n\n return { responder };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/adapters/discord/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/adapters/discord/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIlG,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAWlE,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,mBAAmB,GACvB;IACD,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,qBAAqB,CAAC;IACjC,QAAQ,EAAE,aAAa,CAAC;CACzB,CAmFA"}
|