@geminixiang/mikan 1.0.0-beta.14 → 1.0.0-beta.15
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 +25 -0
- package/README.md +33 -7
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/agent.d.ts +2 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +65 -20
- package/dist/agent.js.map +1 -1
- package/dist/harness/extensions/loader.d.ts +6 -0
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +24 -4
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/registry.d.ts +48 -1
- package/dist/harness/extensions/registry.d.ts.map +1 -1
- package/dist/harness/extensions/registry.js +146 -0
- package/dist/harness/extensions/registry.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +123 -12
- 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 +3 -3
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +1 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/runner.d.ts +13 -2
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +59 -16
- package/dist/harness/runner.js.map +1 -1
- package/dist/main.js +11 -8
- package/dist/main.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +32 -4
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +3 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sessions/agent-memory-file-manager.d.ts.map +1 -1
- package/dist/sessions/agent-memory-file-manager.js +0 -11
- package/dist/sessions/agent-memory-file-manager.js.map +1 -1
- package/dist/tools/generate-image.d.ts +17 -0
- package/dist/tools/generate-image.d.ts.map +1 -0
- package/dist/tools/generate-image.js +63 -0
- package/dist/tools/generate-image.js.map +1 -0
- package/dist/tools/index.d.ts +5 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +10 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +1 -17
- package/dist/vault/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,31 @@ any release.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [1.0.0-beta.15]
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Add native image generation with automatic upload through the active model provider.
|
|
17
|
+
- Add extension chat commands via `api.registerCommand`: deterministic `/name` dispatch with no model call; built-ins and first registrations win.
|
|
18
|
+
- Add an extension disposal lifecycle (`api.onDispose` or an `activate` return value), run when a harness instance is discarded (`/pi-new`, idle eviction, session rotation).
|
|
19
|
+
- Add `api.triggerRun(text)` to fire an immediate autonomous agent run, `api.uploadFile(path, title)` for proactive file uploads, and an explicit `conversationId` option on `api.notify` for cross-conversation posting.
|
|
20
|
+
- Add `agent_error` and `budget_exceeded` extension hooks so monitoring extensions see failed turns and tripped run budgets.
|
|
21
|
+
- Pass a `RunOrigin` (platform, triggering message id, user identity, attachments) to extension hook events, making `api.react` and per-user extension policy usable.
|
|
22
|
+
- Let `before_agent_start` extensions rewrite the user prompt or block the turn before the model runs; blocked turns leave no trace in the transcript or session store.
|
|
23
|
+
- Let `tool_result` extensions rewrite tool output (content and error flag) before the model and the session store see it, enabling secret redaction and output truncation.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Dispatch `before_agent_start` and `tool_result` hooks with chaining semantics (each handler sees earlier handlers' rewrites; any `block` wins) instead of first-result-wins.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Dispose cached runners when models switch or environment credentials refresh.
|
|
32
|
+
|
|
33
|
+
### Tests
|
|
34
|
+
|
|
35
|
+
- Add coverage for image generation, extension lifecycle and hook rewrites, and runner disposal.
|
|
36
|
+
|
|
12
37
|
## [1.0.0-beta.14]
|
|
13
38
|
|
|
14
39
|
### Added
|
package/README.md
CHANGED
|
@@ -51,19 +51,45 @@ npm install && npm run build
|
|
|
51
51
|
|
|
52
52
|
## Quick Start
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
Run mikan under [PM2](https://pm2.keymetrics.io/) so it stays up, restarts after failures, and starts on boot:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
|
|
57
|
+
npm i -g @geminixiang/mikan pm2
|
|
58
|
+
|
|
59
|
+
# One-time setup: create the state directory and settings
|
|
60
|
+
mikan --onboard --state-dir=~/.mikan
|
|
61
|
+
|
|
62
|
+
# Grab the maintained ecosystem file, then edit `args` and `env`
|
|
63
|
+
curl -O https://raw.githubusercontent.com/geminixiang/mikan/main/deploy/pm2/ecosystem.config.cjs
|
|
64
|
+
|
|
65
|
+
pm2 start ecosystem.config.cjs
|
|
66
|
+
pm2 save
|
|
67
|
+
pm2 startup # run the printed command to enable boot autostart
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
In `ecosystem.config.cjs`, point `args` at your state dir, sandbox mode, and working directory:
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
args: "--state-dir=/srv/mikan/state --sandbox=host /srv/mikan/workspace",
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then set the platform tokens you need in `env`; you can run multiple platforms at once:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
env: {
|
|
80
|
+
SLACK_APP_TOKEN: "xapp-...",
|
|
81
|
+
SLACK_BOT_TOKEN: "xoxb-...",
|
|
82
|
+
TELEGRAM_BOT_TOKEN: "123456:ABC-...",
|
|
83
|
+
DISCORD_BOT_TOKEN: "MTI...",
|
|
84
|
+
},
|
|
58
85
|
```
|
|
59
86
|
|
|
60
|
-
|
|
87
|
+
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.
|
|
88
|
+
|
|
89
|
+
For a one-off foreground run, the same CLI works directly:
|
|
61
90
|
|
|
62
91
|
```bash
|
|
63
|
-
|
|
64
|
-
export SLACK_BOT_TOKEN=xoxb-...
|
|
65
|
-
export TELEGRAM_BOT_TOKEN=123456:ABC-...
|
|
66
|
-
export DISCORD_BOT_TOKEN=MTI...
|
|
92
|
+
mikan [--state-dir=~/.mikan] [--sandbox=<mode>] <working-directory>
|
|
67
93
|
```
|
|
68
94
|
|
|
69
95
|
## Platforms
|
package/dist/adapter.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { MessagingBot, ConversationContext, ConversationEvent, MessagingEventHandler, ChatAdapter, ConversationMessage, ConversationResponder, ChatToolResult, ConversationKind, MessagingInfo, PlatformName, PlatformNotifier, PlatformReactor, RunningSession, } from "./types.js";
|
|
1
|
+
export type { MessagingBot, ConversationContext, ConversationEvent, MessagingEventHandler, ChatAdapter, ConversationMessage, ConversationResponder, ChatToolResult, ConversationKind, MessagingInfo, PlatformName, PlatformNotifier, PlatformReactor, PlatformUploader, RunningSession, } from "./types.js";
|
|
2
2
|
//# sourceMappingURL=adapter.d.ts.map
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"","sourcesContent":["export type {\n MessagingBot,\n ConversationContext,\n ConversationEvent,\n MessagingEventHandler,\n ChatAdapter,\n ConversationMessage,\n ConversationResponder,\n ChatToolResult,\n ConversationKind,\n MessagingInfo,\n PlatformName,\n PlatformNotifier,\n PlatformReactor,\n RunningSession,\n} from \"./types.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"","sourcesContent":["export type {\n MessagingBot,\n ConversationContext,\n ConversationEvent,\n MessagingEventHandler,\n ChatAdapter,\n ConversationMessage,\n ConversationResponder,\n ChatToolResult,\n ConversationKind,\n MessagingInfo,\n PlatformName,\n PlatformNotifier,\n PlatformReactor,\n PlatformUploader,\n RunningSession,\n} from \"./types.js\";\n"]}
|
package/dist/agent.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { PiAgentWrapper } from "./types.js";
|
|
|
7
7
|
import { type ImageContent } from "@earendil-works/pi-ai";
|
|
8
8
|
import { MikanModels } from "./harness/index.js";
|
|
9
9
|
import type { ConversationMessage } from "./adapter.js";
|
|
10
|
-
import type { PlatformNotifier, PlatformReactor } from "./types.js";
|
|
10
|
+
import type { PlatformNotifier, PlatformReactor, PlatformUploader } from "./types.js";
|
|
11
11
|
import type { SessionViewTokenStoreLike } from "./commands/types.js";
|
|
12
12
|
import type { DockerContainerManager } from "./provisioner.js";
|
|
13
13
|
import { type RuntimePathContext, type SandboxConfig } from "./sandbox/index.js";
|
|
@@ -46,6 +46,7 @@ export interface CreateRunnerOptions {
|
|
|
46
46
|
};
|
|
47
47
|
platformNotifier?: PlatformNotifier;
|
|
48
48
|
platformReactor?: PlatformReactor;
|
|
49
|
+
platformUploader?: PlatformUploader;
|
|
49
50
|
platformToolPackFactories?: readonly PlatformToolPackFactory[];
|
|
50
51
|
/** Model registry override; defaults to the process-wide models.json load. */
|
|
51
52
|
models?: MikanModels;
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAY,KAAK,YAAY,EAAc,MAAM,uBAAuB,CAAC;AAChF,OAAO,
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Agent runner: prompt construction, path translation, run lifecycle, and createRunner.
|
|
3
3
|
* Single module — do not split helpers that only this file uses.
|
|
4
4
|
*/
|
|
5
|
-
import { DEFAULT_EVENT_BUDGET, defaultExtensionDirs, formatSkillsForPrompt, loadExtensions, loadSkillsFromDir, MikanAgentSession, MikanModels, } from "./harness/index.js";
|
|
5
|
+
import { DEFAULT_EVENT_BUDGET, defaultExtensionDirs, formatSkillsForPrompt, loadExtensions, loadSkillsFromDir, MikanAgentSession, MikanModels, parseCommandInput, } from "./harness/index.js";
|
|
6
6
|
import { createHash } from "crypto";
|
|
7
7
|
import { existsSync, readFileSync } from "fs";
|
|
8
|
-
import { mkdir, readFile
|
|
8
|
+
import { mkdir, readFile } from "fs/promises";
|
|
9
9
|
import { join, posix } from "path";
|
|
10
10
|
import { resolveConversationSettings } from "./config.js";
|
|
11
11
|
import { readEnv } from "./utils/env.js";
|
|
@@ -88,15 +88,6 @@ export function buildPromptPayload(message, workspacePath, pathContext) {
|
|
|
88
88
|
}
|
|
89
89
|
return { userMessage, imageAttachments };
|
|
90
90
|
}
|
|
91
|
-
async function writePromptDebugContext(conversationDir, systemPrompt, session, userMessage, imageAttachmentCount) {
|
|
92
|
-
const debugContext = {
|
|
93
|
-
systemPrompt,
|
|
94
|
-
messages: session.messages,
|
|
95
|
-
newUserMessage: userMessage,
|
|
96
|
-
imageAttachmentCount,
|
|
97
|
-
};
|
|
98
|
-
await writeFile(join(conversationDir, "last_prompt.jsonl"), JSON.stringify(debugContext, null, 2));
|
|
99
|
-
}
|
|
100
91
|
async function getMemory(conversationDir) {
|
|
101
92
|
const parts = [];
|
|
102
93
|
// Read workspace-level memory (shared across all conversations)
|
|
@@ -722,7 +713,7 @@ function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner,
|
|
|
722
713
|
* notify posts through the platform bots when main.ts provides a notifier.
|
|
723
714
|
*/
|
|
724
715
|
function buildExtensionHostServices(params) {
|
|
725
|
-
const { workspaceDir, vaultManager, platformNotifier, platformReactor } = params;
|
|
716
|
+
const { workspaceDir, vaultManager, platformNotifier, platformReactor, platformUploader } = params;
|
|
726
717
|
const eventStore = HostEventStore.fromWorkspaceDir(workspaceDir);
|
|
727
718
|
return {
|
|
728
719
|
stateDir: readEnv("STATE_DIR"),
|
|
@@ -742,6 +733,7 @@ function buildExtensionHostServices(params) {
|
|
|
742
733
|
},
|
|
743
734
|
...(platformNotifier ? { postMessage: platformNotifier } : {}),
|
|
744
735
|
...(platformReactor ? { addReaction: platformReactor } : {}),
|
|
736
|
+
...(platformUploader ? { uploadFile: platformUploader } : {}),
|
|
745
737
|
...(vaultManager
|
|
746
738
|
? {
|
|
747
739
|
resolveSecrets: (slug) => vaultManager.resolve(`extensions/${slug}`)?.env ?? {},
|
|
@@ -750,7 +742,7 @@ function buildExtensionHostServices(params) {
|
|
|
750
742
|
};
|
|
751
743
|
}
|
|
752
744
|
async function createConfiguredAgentSession(params) {
|
|
753
|
-
const { conversationId, workspaceDir, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, platformReactor, } = params;
|
|
745
|
+
const { conversationId, workspaceDir, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, platformReactor, platformUploader, } = params;
|
|
754
746
|
// Host-only dirs under the state dir: extension code runs in the mikan
|
|
755
747
|
// process, so it must never load from workspace paths — those are mounted
|
|
756
748
|
// into sandbox containers and agent-writable (sandbox escape otherwise).
|
|
@@ -762,6 +754,7 @@ async function createConfiguredAgentSession(params) {
|
|
|
762
754
|
vaultManager,
|
|
763
755
|
platformNotifier,
|
|
764
756
|
platformReactor,
|
|
757
|
+
platformUploader,
|
|
765
758
|
}),
|
|
766
759
|
});
|
|
767
760
|
for (const err of extensionsResult.errors) {
|
|
@@ -783,7 +776,12 @@ async function createConfiguredAgentSession(params) {
|
|
|
783
776
|
if (reloaded > 0) {
|
|
784
777
|
log.logInfo(`[${conversationId}] Reloaded ${reloaded} messages from session context`);
|
|
785
778
|
}
|
|
786
|
-
return {
|
|
779
|
+
return {
|
|
780
|
+
session,
|
|
781
|
+
extensionSkills: extensionsResult.skills,
|
|
782
|
+
extensionRegistry: extensionsResult.registry,
|
|
783
|
+
disposeExtensions: extensionsResult.dispose,
|
|
784
|
+
};
|
|
787
785
|
}
|
|
788
786
|
function reloadSessionMessages(session, conversationId) {
|
|
789
787
|
const reloaded = session.reloadFromSession();
|
|
@@ -846,7 +844,6 @@ async function prepareRunContext(params) {
|
|
|
846
844
|
const { userMessage, imageAttachments } = buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext);
|
|
847
845
|
const turnInstructions = buildTurnInstructions(message.id.startsWith("event:"), triggerAttribution, platform.name);
|
|
848
846
|
const finalUserMessage = turnInstructions ? `${turnInstructions}\n\n${userMessage}` : userMessage;
|
|
849
|
-
await writePromptDebugContext(conversationDir, systemPrompt, session, finalUserMessage, imageAttachments.length);
|
|
850
847
|
return {
|
|
851
848
|
sessionConversation,
|
|
852
849
|
runQueue,
|
|
@@ -1133,18 +1130,21 @@ function attachSessionEventHandlers(params) {
|
|
|
1133
1130
|
* This is a stateless factory function.
|
|
1134
1131
|
*/
|
|
1135
1132
|
export async function createRunner(options) {
|
|
1136
|
-
const { sandboxConfig, sessionKey, conversationId, conversationDir, workspaceDir, sessionScope, vaultManager, provisioner, sessionView, platformNotifier, platformReactor, platformToolPackFactories, } = options;
|
|
1133
|
+
const { sandboxConfig, sessionKey, conversationId, conversationDir, workspaceDir, sessionScope, vaultManager, provisioner, sessionView, platformNotifier, platformReactor, platformUploader, platformToolPackFactories, } = options;
|
|
1137
1134
|
const agentConfig = resolveConversationSettings(conversationDir);
|
|
1138
1135
|
const workspaceBase = join(conversationDir, "..");
|
|
1139
1136
|
const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspaceDir, workspaceBase);
|
|
1140
1137
|
let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceBase);
|
|
1141
|
-
// Create tools (per-runner, with per-runner upload function setter)
|
|
1142
|
-
const { tools, setUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, provisioner }, platformToolPackFactories ?? []);
|
|
1143
1138
|
const modelRegistry = options.models ?? MikanModels.create();
|
|
1144
1139
|
if (modelRegistry.getError()) {
|
|
1145
1140
|
log.logWarning("models.json load error", modelRegistry.getError());
|
|
1146
1141
|
}
|
|
1147
1142
|
const model = modelRegistry.resolve(agentConfig.provider, agentConfig.model);
|
|
1143
|
+
// Create tools (per-runner, with per-runner upload function setter)
|
|
1144
|
+
const { tools, setUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, provisioner }, platformToolPackFactories ?? [], {
|
|
1145
|
+
model,
|
|
1146
|
+
getApiKey: () => modelRegistry.getApiKeyForProvider(model.provider),
|
|
1147
|
+
});
|
|
1148
1148
|
// Initial system prompt (will be updated each run with fresh memory/channels/users/skills)
|
|
1149
1149
|
const memory = await getMemory(conversationDir);
|
|
1150
1150
|
const skills = loadMikanSkills(conversationDir, pathContext.runtimeWorkspaceRoot);
|
|
@@ -1168,7 +1168,7 @@ export async function createRunner(options) {
|
|
|
1168
1168
|
}
|
|
1169
1169
|
const sessionUuid = extractSessionUuid(contextFile);
|
|
1170
1170
|
const chatSessionManager = new AgentMemoryFileManager();
|
|
1171
|
-
const { session, extensionSkills } = await createConfiguredAgentSession({
|
|
1171
|
+
const { session, extensionSkills, extensionRegistry, disposeExtensions } = await createConfiguredAgentSession({
|
|
1172
1172
|
conversationId,
|
|
1173
1173
|
workspaceDir,
|
|
1174
1174
|
systemPrompt,
|
|
@@ -1180,6 +1180,7 @@ export async function createRunner(options) {
|
|
|
1180
1180
|
vaultManager,
|
|
1181
1181
|
platformNotifier,
|
|
1182
1182
|
platformReactor,
|
|
1183
|
+
platformUploader,
|
|
1183
1184
|
});
|
|
1184
1185
|
// Mutable per-run state - event handler references this
|
|
1185
1186
|
const runState = createRunState();
|
|
@@ -1241,10 +1242,39 @@ export async function createRunner(options) {
|
|
|
1241
1242
|
// Autonomous (event/trigger) runs get an explicit resource ceiling since
|
|
1242
1243
|
// no human is watching the loop; interactive turns stay human-gated.
|
|
1243
1244
|
const isEventRun = message.id.startsWith("event:");
|
|
1244
|
-
|
|
1245
|
+
// Event runs have no triggering platform message, so identity fields
|
|
1246
|
+
// stay unset and extensions must null-check them.
|
|
1247
|
+
const origin = isEventRun
|
|
1248
|
+
? { kind: "event", platform: platform.name }
|
|
1249
|
+
: {
|
|
1250
|
+
kind: "interactive",
|
|
1251
|
+
platform: platform.name,
|
|
1252
|
+
messageTs: message.id,
|
|
1253
|
+
userId: message.userId,
|
|
1254
|
+
userName: message.userName,
|
|
1255
|
+
threadTs: message.threadTs,
|
|
1256
|
+
attachments: message.attachments,
|
|
1257
|
+
};
|
|
1258
|
+
const outcome = await session.prompt(prepared.userMessage, {
|
|
1259
|
+
origin,
|
|
1245
1260
|
...(prepared.imageAttachments.length > 0 ? { images: prepared.imageAttachments } : {}),
|
|
1246
1261
|
...(isEventRun ? { budget: DEFAULT_EVENT_BUDGET } : {}),
|
|
1247
1262
|
});
|
|
1263
|
+
if (outcome?.blocked) {
|
|
1264
|
+
const text = outcome.reason
|
|
1265
|
+
? `_Turn blocked by an extension: ${outcome.reason}_`
|
|
1266
|
+
: "_Turn blocked by an extension._";
|
|
1267
|
+
sendAgentEvent({
|
|
1268
|
+
sessionId: sessionUuid,
|
|
1269
|
+
actorName: formatAgentActorName(message.userName, prepared.sessionConversation),
|
|
1270
|
+
event: { kind: "diagnostic", text },
|
|
1271
|
+
});
|
|
1272
|
+
await responder.respondDiagnostic(text, { style: "muted" });
|
|
1273
|
+
runState.responder = null;
|
|
1274
|
+
runState.logCtx = null;
|
|
1275
|
+
runState.queue = null;
|
|
1276
|
+
return { stopReason: "blocked" };
|
|
1277
|
+
}
|
|
1248
1278
|
// Wait for queued messages
|
|
1249
1279
|
await prepared.runQueue.wait();
|
|
1250
1280
|
const sessionViewTokenStore = sessionView?.tokenStore;
|
|
@@ -1290,6 +1320,21 @@ export async function createRunner(options) {
|
|
|
1290
1320
|
abort() {
|
|
1291
1321
|
session.abort();
|
|
1292
1322
|
},
|
|
1323
|
+
async tryExtensionCommand(message, responder) {
|
|
1324
|
+
const parsed = parseCommandInput(message.text);
|
|
1325
|
+
if (!parsed)
|
|
1326
|
+
return false;
|
|
1327
|
+
return extensionRegistry.dispatchCommand(parsed.name, {
|
|
1328
|
+
args: parsed.args,
|
|
1329
|
+
conversationId,
|
|
1330
|
+
userId: message.userId,
|
|
1331
|
+
userName: message.userName,
|
|
1332
|
+
respond: (text) => responder.respond(text),
|
|
1333
|
+
});
|
|
1334
|
+
},
|
|
1335
|
+
async dispose() {
|
|
1336
|
+
await disposeExtensions();
|
|
1337
|
+
},
|
|
1293
1338
|
getCurrentStep() {
|
|
1294
1339
|
const pending = runState.pendingTools;
|
|
1295
1340
|
if (pending.size === 0)
|