@amodalai/runtime 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/agent/local-server.js +70 -3
- package/dist/src/agent/local-server.js.map +1 -1
- package/dist/src/agent/local-server.test.js +0 -3
- package/dist/src/agent/local-server.test.js.map +1 -1
- package/dist/src/agent/loop-types.d.ts +0 -5
- package/dist/src/agent/loop.test.js +1 -2
- package/dist/src/agent/loop.test.js.map +1 -1
- package/dist/src/agent/page-builder.js +20 -17
- package/dist/src/agent/page-builder.js.map +1 -1
- package/dist/src/agent/proactive/proactive-runner.test.js +0 -1
- package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -1
- package/dist/src/agent/routes/admin-chat-abort.test.js +1 -0
- package/dist/src/agent/routes/admin-chat-abort.test.js.map +1 -1
- package/dist/src/agent/routes/admin-chat.js +0 -1
- package/dist/src/agent/routes/admin-chat.js.map +1 -1
- package/dist/src/agent/routes/files.js +46 -52
- package/dist/src/agent/routes/files.js.map +1 -1
- package/dist/src/agent/routes/inspect.js +4 -6
- package/dist/src/agent/routes/inspect.js.map +1 -1
- package/dist/src/agent/routes/task.test.js +0 -1
- package/dist/src/agent/routes/task.test.js.map +1 -1
- package/dist/src/agent/snapshot-server.js +37 -1
- package/dist/src/agent/snapshot-server.js.map +1 -1
- package/dist/src/agent/states/dispatching.js +0 -1
- package/dist/src/agent/states/dispatching.js.map +1 -1
- package/dist/src/agent/states/streaming.js +7 -27
- package/dist/src/agent/states/streaming.js.map +1 -1
- package/dist/src/agent/states/thinking.js +28 -1
- package/dist/src/agent/states/thinking.js.map +1 -1
- package/dist/src/agent/tool-executor-local.test.js +0 -1
- package/dist/src/agent/tool-executor-local.test.js.map +1 -1
- package/dist/src/agent/tool-harness-template.js +0 -1
- package/dist/src/agent/tool-harness-template.js.map +1 -1
- package/dist/src/api/create-agent.js +1 -2
- package/dist/src/api/create-agent.js.map +1 -1
- package/dist/src/api/types.d.ts +1 -3
- package/dist/src/channels/bootstrap.d.ts +59 -0
- package/dist/src/channels/bootstrap.js +89 -0
- package/dist/src/channels/bootstrap.js.map +1 -0
- package/dist/src/channels/channel-session-mapper.d.ts +42 -0
- package/dist/src/channels/channel-session-mapper.js +91 -0
- package/dist/src/channels/channel-session-mapper.js.map +1 -0
- package/dist/src/channels/dedup-cache.d.ts +17 -0
- package/dist/src/channels/dedup-cache.js +51 -0
- package/dist/src/channels/dedup-cache.js.map +1 -0
- package/dist/src/{agent/user-context-fetcher.test.d.ts → channels/dedup-cache.test.d.ts} +1 -1
- package/dist/src/channels/dedup-cache.test.js +51 -0
- package/dist/src/channels/dedup-cache.test.js.map +1 -0
- package/dist/src/channels/errors.d.ts +28 -0
- package/dist/src/channels/errors.js +38 -0
- package/dist/src/channels/errors.js.map +1 -0
- package/dist/src/channels/in-memory-session-mapper.d.ts +34 -0
- package/dist/src/channels/in-memory-session-mapper.js +50 -0
- package/dist/src/channels/in-memory-session-mapper.js.map +1 -0
- package/dist/src/channels/plugin-loader.d.ts +20 -0
- package/dist/src/channels/plugin-loader.js +136 -0
- package/dist/src/channels/plugin-loader.js.map +1 -0
- package/dist/src/channels/plugin-loader.test.d.ts +6 -0
- package/dist/src/channels/plugin-loader.test.js +113 -0
- package/dist/src/channels/plugin-loader.test.js.map +1 -0
- package/dist/src/channels/routes.d.ts +29 -0
- package/dist/src/channels/routes.js +165 -0
- package/dist/src/channels/routes.js.map +1 -0
- package/dist/src/config.d.ts +0 -2
- package/dist/src/config.js +0 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/config.test.js +0 -2
- package/dist/src/config.test.js.map +1 -1
- package/dist/src/context/compiler.js +11 -34
- package/dist/src/context/compiler.js.map +1 -1
- package/dist/src/context/compiler.test.js +7 -60
- package/dist/src/context/compiler.test.js.map +1 -1
- package/dist/src/context/types.d.ts +0 -4
- package/dist/src/index.d.ts +13 -0
- package/dist/src/index.js +10 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/providers/create-provider.js +1 -0
- package/dist/src/providers/create-provider.js.map +1 -1
- package/dist/src/providers/failover.js +8 -0
- package/dist/src/providers/failover.js.map +1 -1
- package/dist/src/providers/search-provider.js +9 -2
- package/dist/src/providers/search-provider.js.map +1 -1
- package/dist/src/providers/types.d.ts +10 -3
- package/dist/src/routes/ai-stream.d.ts +3 -4
- package/dist/src/routes/ai-stream.js +1 -2
- package/dist/src/routes/ai-stream.js.map +1 -1
- package/dist/src/routes/chat-stream.d.ts +3 -1
- package/dist/src/routes/chat-stream.js +1 -1
- package/dist/src/routes/chat-stream.js.map +1 -1
- package/dist/src/routes/chat.js +0 -1
- package/dist/src/routes/chat.js.map +1 -1
- package/dist/src/routes/session-resolver.d.ts +10 -2
- package/dist/src/routes/session-resolver.js +21 -10
- package/dist/src/routes/session-resolver.js.map +1 -1
- package/dist/src/routes/session-resolver.test.js +110 -14
- package/dist/src/routes/session-resolver.test.js.map +1 -1
- package/dist/src/server.d.ts +29 -1
- package/dist/src/server.js +27 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/session/drizzle-session-store.d.ts +2 -1
- package/dist/src/session/drizzle-session-store.js +1 -0
- package/dist/src/session/drizzle-session-store.js.map +1 -1
- package/dist/src/session/manager.js +0 -3
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/manager.test.js +1 -0
- package/dist/src/session/manager.test.js.map +1 -1
- package/dist/src/session/pglite-session-store.js +16 -0
- package/dist/src/session/pglite-session-store.js.map +1 -1
- package/dist/src/session/postgres-session-store.js +15 -0
- package/dist/src/session/postgres-session-store.js.map +1 -1
- package/dist/src/session/session-builder.d.ts +0 -3
- package/dist/src/session/session-builder.js +1 -5
- package/dist/src/session/session-builder.js.map +1 -1
- package/dist/src/session/session-builder.test.js +3 -6
- package/dist/src/session/session-builder.test.js.map +1 -1
- package/dist/src/session/tool-context-factory.d.ts +0 -5
- package/dist/src/session/tool-context-factory.js +0 -1
- package/dist/src/session/tool-context-factory.js.map +1 -1
- package/dist/src/session/tool-context-factory.test.js +1 -3
- package/dist/src/session/tool-context-factory.test.js.map +1 -1
- package/dist/src/session/types.d.ts +0 -4
- package/dist/src/stores/schema.d.ts +111 -0
- package/dist/src/stores/schema.js +15 -0
- package/dist/src/stores/schema.js.map +1 -1
- package/dist/src/tools/admin-file-tools.js +2 -2
- package/dist/src/tools/admin-file-tools.js.map +1 -1
- package/dist/src/tools/admin-file-tools.test.js +9 -7
- package/dist/src/tools/admin-file-tools.test.js.map +1 -1
- package/dist/src/tools/custom-tool-adapter.js +0 -1
- package/dist/src/tools/custom-tool-adapter.js.map +1 -1
- package/dist/src/tools/custom-tool-adapter.test.js +0 -1
- package/dist/src/tools/custom-tool-adapter.test.js.map +1 -1
- package/dist/src/tools/fetch-url-tool.test.js +0 -1
- package/dist/src/tools/fetch-url-tool.test.js.map +1 -1
- package/dist/src/tools/mcp-tool-adapter.test.js +0 -1
- package/dist/src/tools/mcp-tool-adapter.test.js.map +1 -1
- package/dist/src/tools/registry.test.js +0 -1
- package/dist/src/tools/registry.test.js.map +1 -1
- package/dist/src/tools/request-tool.test.js +0 -1
- package/dist/src/tools/request-tool.test.js.map +1 -1
- package/dist/src/tools/store-tools.test.js +0 -1
- package/dist/src/tools/store-tools.test.js.map +1 -1
- package/dist/src/tools/types.d.ts +0 -5
- package/dist/src/tools/web-search-tool.test.js +0 -1
- package/dist/src/tools/web-search-tool.test.js.map +1 -1
- package/dist/src/types.d.ts +0 -4
- package/dist/src/types.js +0 -2
- package/dist/src/types.js.map +1 -1
- package/dist/src/types.test.js +0 -3
- package/dist/src/types.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/src/agent/user-context-fetcher.d.ts +0 -25
- package/dist/src/agent/user-context-fetcher.js +0 -79
- package/dist/src/agent/user-context-fetcher.js.map +0 -1
- package/dist/src/agent/user-context-fetcher.test.js +0 -121
- package/dist/src/agent/user-context-fetcher.test.js.map +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { AmodalError } from '../errors.js';
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Channel plugin errors
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
/**
|
|
11
|
+
* Error loading a channel plugin package (missing, invalid export shape).
|
|
12
|
+
*/
|
|
13
|
+
export class ChannelPluginError extends AmodalError {
|
|
14
|
+
channelType;
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super('CHANNEL_PLUGIN_ERROR', message, {
|
|
17
|
+
channelType: options.channelType,
|
|
18
|
+
...options.context,
|
|
19
|
+
}, options.cause);
|
|
20
|
+
this.name = 'ChannelPluginError';
|
|
21
|
+
this.channelType = options.channelType;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Error validating a channel's config block against its plugin schema.
|
|
26
|
+
*/
|
|
27
|
+
export class ChannelConfigError extends AmodalError {
|
|
28
|
+
channelType;
|
|
29
|
+
constructor(message, options) {
|
|
30
|
+
super('CHANNEL_CONFIG_ERROR', message, {
|
|
31
|
+
channelType: options.channelType,
|
|
32
|
+
...options.context,
|
|
33
|
+
}, options.cause);
|
|
34
|
+
this.name = 'ChannelConfigError';
|
|
35
|
+
this.channelType = options.channelType;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/channels/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAC;AAEzC,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,WAAW;IACxC,WAAW,CAAS;IAE7B,YACE,OAAe,EACf,OAIC;QAED,KAAK,CAAC,sBAAsB,EAAE,OAAO,EAAE;YACrC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,GAAG,OAAO,CAAC,OAAO;SACnB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAClB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACzC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,WAAW;IACxC,WAAW,CAAS;IAE7B,YACE,OAAe,EACf,OAIC;QAED,KAAK,CAAC,sBAAsB,EAAE,OAAO,EAAE;YACrC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,GAAG,OAAO,CAAC,OAAO;SACnB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAClB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* In-memory channel session mapper.
|
|
8
|
+
*
|
|
9
|
+
* Simple Map-backed implementation for environments without a database
|
|
10
|
+
* (snapshot preview server, testing). Sessions are not persisted across
|
|
11
|
+
* restarts — that's fine for preview and test use cases.
|
|
12
|
+
*/
|
|
13
|
+
import type { ChannelSessionMapper, ChannelSessionMapResult } from '@amodalai/types';
|
|
14
|
+
import type { CreateChannelSession } from './channel-session-mapper.js';
|
|
15
|
+
import type { Logger } from '../logger.js';
|
|
16
|
+
export interface InMemoryChannelSessionMapperOptions {
|
|
17
|
+
logger: Logger;
|
|
18
|
+
eventBus?: {
|
|
19
|
+
emit(payload: {
|
|
20
|
+
type: string;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}): unknown;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare class InMemoryChannelSessionMapper implements ChannelSessionMapper {
|
|
26
|
+
private readonly sessions;
|
|
27
|
+
private readonly logger;
|
|
28
|
+
private readonly eventBus?;
|
|
29
|
+
private createSession;
|
|
30
|
+
constructor(opts: InMemoryChannelSessionMapperOptions);
|
|
31
|
+
setSessionFactory(factory: CreateChannelSession): void;
|
|
32
|
+
findOrCreateSession(channelType: string, channelUserId: string, displayName?: string): Promise<ChannelSessionMapResult>;
|
|
33
|
+
resetSession(channelType: string, channelUserId: string): Promise<void>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
export class InMemoryChannelSessionMapper {
|
|
7
|
+
sessions = new Map();
|
|
8
|
+
logger;
|
|
9
|
+
eventBus;
|
|
10
|
+
createSession = null;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this.logger = opts.logger;
|
|
13
|
+
this.eventBus = opts.eventBus;
|
|
14
|
+
}
|
|
15
|
+
setSessionFactory(factory) {
|
|
16
|
+
this.createSession = factory;
|
|
17
|
+
}
|
|
18
|
+
async findOrCreateSession(channelType, channelUserId, displayName) {
|
|
19
|
+
const key = `${channelType}:${channelUserId}`;
|
|
20
|
+
const existing = this.sessions.get(key);
|
|
21
|
+
if (existing) {
|
|
22
|
+
this.logger.debug('channel_session_found', { channelType, channelUserId, sessionId: existing });
|
|
23
|
+
return { sessionId: existing, isNew: false };
|
|
24
|
+
}
|
|
25
|
+
if (!this.createSession) {
|
|
26
|
+
throw new Error('Channel session mapper: session factory not set. Call setSessionFactory() first.');
|
|
27
|
+
}
|
|
28
|
+
const channelOrigin = {
|
|
29
|
+
channelType,
|
|
30
|
+
channelUserId,
|
|
31
|
+
channelUserDisplay: displayName,
|
|
32
|
+
};
|
|
33
|
+
const { sessionId } = this.createSession(channelOrigin);
|
|
34
|
+
this.sessions.set(key, sessionId);
|
|
35
|
+
this.logger.info('channel_session_created', { channelType, channelUserId, sessionId });
|
|
36
|
+
this.eventBus?.emit({
|
|
37
|
+
type: 'channel_session_created',
|
|
38
|
+
channelType,
|
|
39
|
+
channelUserId,
|
|
40
|
+
sessionId,
|
|
41
|
+
});
|
|
42
|
+
return { sessionId, isNew: true };
|
|
43
|
+
}
|
|
44
|
+
async resetSession(channelType, channelUserId) {
|
|
45
|
+
const key = `${channelType}:${channelUserId}`;
|
|
46
|
+
this.sessions.delete(key);
|
|
47
|
+
this.logger.info('channel_session_reset', { channelType, channelUserId });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=in-memory-session-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-session-mapper.js","sourceRoot":"","sources":["../../../src/channels/in-memory-session-mapper.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH,MAAM,OAAO,4BAA4B;IACtB,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IACrC,MAAM,CAAS;IACf,QAAQ,CAAmD;IACpE,aAAa,GAAgC,IAAI,CAAC;IAE1D,YAAY,IAAyC;QACnD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChC,CAAC;IAED,iBAAiB,CAAC,OAA6B;QAC7C,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,mBAAmB,CACvB,WAAmB,EACnB,aAAqB,EACrB,WAAoB;QAEpB,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,aAAa,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAExC,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAC,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAC,CAAC,CAAC;YAC9F,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAC,CAAC;QAC7C,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACtG,CAAC;QAED,MAAM,aAAa,GAAkB;YACnC,WAAW;YACX,aAAa;YACb,kBAAkB,EAAE,WAAW;SAChC,CAAC;QACF,MAAM,EAAC,SAAS,EAAC,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAElC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAC,WAAW,EAAE,aAAa,EAAE,SAAS,EAAC,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;YAClB,IAAI,EAAE,yBAAyB;YAC/B,WAAW;YACX,aAAa;YACb,SAAS;SACV,CAAC,CAAC;QAEH,OAAO,EAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,WAAmB,EACnB,aAAqB;QAErB,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,aAAa,EAAE,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAC,WAAW,EAAE,aAAa,EAAC,CAAC,CAAC;IAC1E,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import type { ChannelAdapter } from '@amodalai/types';
|
|
7
|
+
import type { Logger } from '../logger.js';
|
|
8
|
+
export interface LoadChannelPluginsOptions {
|
|
9
|
+
/** The `channels` block from amodal.json (env refs already resolved). */
|
|
10
|
+
channelsConfig: Record<string, unknown>;
|
|
11
|
+
/** Absolute path to the repo root (for local channel discovery + node_modules). */
|
|
12
|
+
repoPath: string;
|
|
13
|
+
/** The `packages` array from amodal.json — used to find channel packages. */
|
|
14
|
+
packages?: string[];
|
|
15
|
+
logger: Logger;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load and initialize channel adapters for all configured channels.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadChannelPlugins(opts: LoadChannelPluginsOptions): Promise<Map<string, ChannelAdapter>>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Dynamic loader for channel plugins.
|
|
8
|
+
*
|
|
9
|
+
* Loading order (first match wins):
|
|
10
|
+
* 1. Local repo: `channels/{type}/index.ts` — compiled with esbuild
|
|
11
|
+
* 2. Installed npm package: `@amodalai/channel-{type}`
|
|
12
|
+
*
|
|
13
|
+
* Both sources must export a default `ChannelPlugin`. Local channels
|
|
14
|
+
* let users iterate on custom adapters (e.g. in-app chat widget)
|
|
15
|
+
* without publishing a package.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { pathToFileURL } from 'node:url';
|
|
20
|
+
import { ChannelPluginError, ChannelConfigError } from './errors.js';
|
|
21
|
+
/**
|
|
22
|
+
* Load and initialize channel adapters for all configured channels.
|
|
23
|
+
*/
|
|
24
|
+
export async function loadChannelPlugins(opts) {
|
|
25
|
+
const { channelsConfig, repoPath, logger } = opts;
|
|
26
|
+
const adapters = new Map();
|
|
27
|
+
for (const [channelType, rawConfig] of Object.entries(channelsConfig)) {
|
|
28
|
+
const mod = await importChannelModule(channelType, repoPath, opts.packages ?? [], logger);
|
|
29
|
+
// Validate the default export satisfies ChannelPlugin shape
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- validating shape below
|
|
31
|
+
const plugin = mod.default;
|
|
32
|
+
if (!plugin ||
|
|
33
|
+
typeof plugin.channelType !== 'string' ||
|
|
34
|
+
!plugin.configSchema ||
|
|
35
|
+
typeof plugin.createAdapter !== 'function') {
|
|
36
|
+
throw new ChannelPluginError(`Channel "${channelType}" does not export a valid ChannelPlugin as its default export`, { channelType });
|
|
37
|
+
}
|
|
38
|
+
// Validate config against the plugin's schema
|
|
39
|
+
let validatedConfig;
|
|
40
|
+
try {
|
|
41
|
+
validatedConfig = plugin.configSchema.parse(rawConfig);
|
|
42
|
+
}
|
|
43
|
+
catch (cause) {
|
|
44
|
+
throw new ChannelConfigError(`Invalid config for channel "${channelType}"`, { channelType, cause });
|
|
45
|
+
}
|
|
46
|
+
// Create the adapter
|
|
47
|
+
const adapter = plugin.createAdapter(validatedConfig);
|
|
48
|
+
adapters.set(channelType, adapter);
|
|
49
|
+
}
|
|
50
|
+
return adapters;
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Module resolution: local repo first, then npm
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const LOCAL_ENTRY_FILES = ['index.ts', 'index.js', 'index.mjs'];
|
|
56
|
+
/**
|
|
57
|
+
* Find a channel package from the declared packages list.
|
|
58
|
+
* Matches packages ending with `channel-{type}` (any scope).
|
|
59
|
+
* E.g. channelType "foo" matches "@amodalai/channel-foo" or "@myorg/channel-foo".
|
|
60
|
+
*/
|
|
61
|
+
function findChannelPackage(channelType, packages) {
|
|
62
|
+
const suffix = `channel-${channelType}`;
|
|
63
|
+
return packages.find((pkg) => {
|
|
64
|
+
const shortName = pkg.split('/').pop() ?? pkg;
|
|
65
|
+
return shortName === suffix;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function importChannelModule(channelType, repoPath, packages, logger) {
|
|
69
|
+
// 1. Check local repo: channels/{type}/index.ts
|
|
70
|
+
const localDir = path.join(repoPath, 'channels', channelType);
|
|
71
|
+
const localEntry = LOCAL_ENTRY_FILES
|
|
72
|
+
.map((f) => path.join(localDir, f))
|
|
73
|
+
.find((p) => existsSync(p));
|
|
74
|
+
if (localEntry) {
|
|
75
|
+
return importLocalChannel(channelType, localEntry, logger);
|
|
76
|
+
}
|
|
77
|
+
// 2. Find matching package from the declared packages array
|
|
78
|
+
const packageName = findChannelPackage(channelType, packages);
|
|
79
|
+
if (!packageName) {
|
|
80
|
+
throw new ChannelPluginError(`Channel "${channelType}" not found. Either create channels/${channelType}/index.ts in your repo, or add a channel-${channelType} package to the packages array in amodal.json.`, { channelType });
|
|
81
|
+
}
|
|
82
|
+
// 3. Import from node_modules using the resolved path
|
|
83
|
+
const packageDir = path.join(repoPath, 'node_modules', ...packageName.split('/'));
|
|
84
|
+
const pkgJsonPath = path.join(packageDir, 'package.json');
|
|
85
|
+
if (!existsSync(pkgJsonPath)) {
|
|
86
|
+
throw new ChannelPluginError(`Channel package "${packageName}" declared in amodal.json but not installed. Run: npm install`, { channelType });
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const { readFileSync } = await import('node:fs');
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- parsing external JSON
|
|
91
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
92
|
+
const mainField = String(pkgJson['main'] ?? 'dist/index.js');
|
|
93
|
+
const entryPath = path.resolve(packageDir, mainField);
|
|
94
|
+
if (!entryPath.startsWith(path.resolve(packageDir))) {
|
|
95
|
+
throw new ChannelPluginError(`Channel package "${packageName}" has invalid main field that escapes package directory`, { channelType });
|
|
96
|
+
}
|
|
97
|
+
const moduleUrl = pathToFileURL(entryPath).href;
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- dynamic import returns unknown module shape
|
|
99
|
+
const mod = await import(moduleUrl);
|
|
100
|
+
logger.info('channel_plugin_loaded', { channelType, source: 'package', package: packageName });
|
|
101
|
+
return mod;
|
|
102
|
+
}
|
|
103
|
+
catch (cause) {
|
|
104
|
+
if (cause instanceof ChannelPluginError)
|
|
105
|
+
throw cause;
|
|
106
|
+
throw new ChannelPluginError(`Failed to load channel plugin "${packageName}"`, { channelType, cause });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function importLocalChannel(channelType, entryPath, logger) {
|
|
110
|
+
let importPath = entryPath;
|
|
111
|
+
// Compile .ts to .mjs with esbuild (same pattern as LocalToolExecutor)
|
|
112
|
+
if (entryPath.endsWith('.ts')) {
|
|
113
|
+
const { build } = await import('esbuild');
|
|
114
|
+
const outDir = path.join(path.dirname(entryPath), '.build');
|
|
115
|
+
const outFile = path.join(outDir, `${channelType}.mjs`);
|
|
116
|
+
mkdirSync(outDir, { recursive: true });
|
|
117
|
+
await build({
|
|
118
|
+
entryPoints: [entryPath],
|
|
119
|
+
outfile: outFile,
|
|
120
|
+
bundle: true,
|
|
121
|
+
format: 'esm',
|
|
122
|
+
platform: 'node',
|
|
123
|
+
logLevel: 'warning',
|
|
124
|
+
// Mark @amodalai/* as external so it resolves from the runtime's
|
|
125
|
+
// node_modules, not bundled into the output.
|
|
126
|
+
external: ['@amodalai/*'],
|
|
127
|
+
});
|
|
128
|
+
importPath = outFile;
|
|
129
|
+
}
|
|
130
|
+
const moduleUrl = pathToFileURL(importPath).href;
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- dynamic import returns unknown module shape
|
|
132
|
+
const mod = await import(moduleUrl);
|
|
133
|
+
logger.info('channel_plugin_loaded', { channelType, source: 'local', path: entryPath });
|
|
134
|
+
return mod;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=plugin-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../../../src/channels/plugin-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import { mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { loadChannelPlugins } from './plugin-loader.js';
|
|
10
|
+
import { ChannelPluginError, ChannelConfigError } from './errors.js';
|
|
11
|
+
const mockLogger = {
|
|
12
|
+
info: vi.fn(),
|
|
13
|
+
warn: vi.fn(),
|
|
14
|
+
error: vi.fn(),
|
|
15
|
+
debug: vi.fn(),
|
|
16
|
+
};
|
|
17
|
+
/** Helper — no local channels dir exists at this fake path. */
|
|
18
|
+
const NO_LOCAL = '/tmp/nonexistent-repo-path';
|
|
19
|
+
/**
|
|
20
|
+
* Create a fake npm channel package in a temp directory so that
|
|
21
|
+
* the file-based resolution in plugin-loader can find it.
|
|
22
|
+
*/
|
|
23
|
+
function createFakePackage(repoPath, packageName, pluginModule) {
|
|
24
|
+
const pkgDir = path.join(repoPath, 'node_modules', ...packageName.split('/'));
|
|
25
|
+
const distDir = path.join(pkgDir, 'dist');
|
|
26
|
+
mkdirSync(distDir, { recursive: true });
|
|
27
|
+
writeFileSync(path.join(pkgDir, 'package.json'), JSON.stringify({ name: packageName, main: 'dist/index.mjs' }));
|
|
28
|
+
writeFileSync(path.join(distDir, 'index.mjs'), pluginModule);
|
|
29
|
+
}
|
|
30
|
+
const TEMP_REPO = '/tmp/plugin-loader-test-repo';
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
mkdirSync(TEMP_REPO, { recursive: true });
|
|
33
|
+
vi.clearAllMocks();
|
|
34
|
+
});
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
rmSync(TEMP_REPO, { recursive: true, force: true });
|
|
37
|
+
});
|
|
38
|
+
describe('loadChannelPlugins', () => {
|
|
39
|
+
it('throws ChannelPluginError for missing package (no local, no npm)', async () => {
|
|
40
|
+
await expect(loadChannelPlugins({
|
|
41
|
+
channelsConfig: { 'nonexistent-channel': {} },
|
|
42
|
+
repoPath: NO_LOCAL,
|
|
43
|
+
logger: mockLogger,
|
|
44
|
+
})).rejects.toThrow(ChannelPluginError);
|
|
45
|
+
});
|
|
46
|
+
it('throws ChannelPluginError for invalid plugin export', async () => {
|
|
47
|
+
createFakePackage(TEMP_REPO, '@amodalai/channel-badshape', 'export default {notAPlugin: true};');
|
|
48
|
+
await expect(loadChannelPlugins({
|
|
49
|
+
channelsConfig: { badshape: {} },
|
|
50
|
+
repoPath: TEMP_REPO,
|
|
51
|
+
packages: ['@amodalai/channel-badshape'],
|
|
52
|
+
logger: mockLogger,
|
|
53
|
+
})).rejects.toThrow(ChannelPluginError);
|
|
54
|
+
});
|
|
55
|
+
it('throws ChannelConfigError for invalid config', async () => {
|
|
56
|
+
// Inline config schema that rejects anything without 'required' field
|
|
57
|
+
const pluginCode = `
|
|
58
|
+
export default {
|
|
59
|
+
channelType: 'testvalid',
|
|
60
|
+
configSchema: {
|
|
61
|
+
parse(data) {
|
|
62
|
+
if (!data || typeof data.required !== 'string') throw new Error('missing required field');
|
|
63
|
+
return data;
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
createAdapter: (cfg) => ({channelType: 'testvalid', parseIncoming: async () => null, sendMessage: async () => {}}),
|
|
67
|
+
};
|
|
68
|
+
`;
|
|
69
|
+
createFakePackage(TEMP_REPO, '@amodalai/channel-testvalid', pluginCode);
|
|
70
|
+
await expect(loadChannelPlugins({
|
|
71
|
+
channelsConfig: { testvalid: { wrong: 'field' } },
|
|
72
|
+
repoPath: TEMP_REPO,
|
|
73
|
+
packages: ['@amodalai/channel-testvalid'],
|
|
74
|
+
logger: mockLogger,
|
|
75
|
+
})).rejects.toThrow(ChannelConfigError);
|
|
76
|
+
});
|
|
77
|
+
it('loads a valid npm plugin and returns adapter map', async () => {
|
|
78
|
+
const pluginCode = `
|
|
79
|
+
export default {
|
|
80
|
+
channelType: 'testok',
|
|
81
|
+
configSchema: { parse(data) { return data; } },
|
|
82
|
+
createAdapter: () => ({channelType: 'testok', parseIncoming: async () => null, sendMessage: async () => {}}),
|
|
83
|
+
};
|
|
84
|
+
`;
|
|
85
|
+
createFakePackage(TEMP_REPO, '@amodalai/channel-testok', pluginCode);
|
|
86
|
+
const adapters = await loadChannelPlugins({
|
|
87
|
+
channelsConfig: { testok: { token: 'abc' } },
|
|
88
|
+
repoPath: TEMP_REPO,
|
|
89
|
+
packages: ['@amodalai/channel-testok'],
|
|
90
|
+
logger: mockLogger,
|
|
91
|
+
});
|
|
92
|
+
expect(adapters.size).toBe(1);
|
|
93
|
+
expect(adapters.get('testok')).toBeDefined();
|
|
94
|
+
expect(adapters.get('testok')?.channelType).toBe('testok');
|
|
95
|
+
});
|
|
96
|
+
it('error message mentions both local and npm when channel not found', async () => {
|
|
97
|
+
try {
|
|
98
|
+
await loadChannelPlugins({
|
|
99
|
+
channelsConfig: { missing: {} },
|
|
100
|
+
repoPath: NO_LOCAL,
|
|
101
|
+
logger: mockLogger,
|
|
102
|
+
});
|
|
103
|
+
expect.unreachable('should have thrown');
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
expect(err).toBeInstanceOf(ChannelPluginError);
|
|
107
|
+
const msg = err.message;
|
|
108
|
+
expect(msg).toContain('channels/missing/index.ts');
|
|
109
|
+
expect(msg).toContain('channel-missing');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
//# sourceMappingURL=plugin-loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-loader.test.js","sourceRoot":"","sources":["../../../src/channels/plugin-loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Express router for inbound messaging channel webhooks.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the `createWebhookRouter` pattern from routes/webhooks.ts:
|
|
10
|
+
* rate-limited, dispatches to registered channel adapters, and runs
|
|
11
|
+
* the message through the existing SessionManager.
|
|
12
|
+
*
|
|
13
|
+
* Route: POST /channels/:channelType/webhook
|
|
14
|
+
*/
|
|
15
|
+
import { Router } from 'express';
|
|
16
|
+
import type { ChannelAdapter, ChannelSessionMapper } from '@amodalai/types';
|
|
17
|
+
import type { StandaloneSessionManager } from '../session/manager.js';
|
|
18
|
+
import type { MessageDedupCache } from './dedup-cache.js';
|
|
19
|
+
import type { RuntimeEventBus } from '../events/event-bus.js';
|
|
20
|
+
import type { Logger } from '../logger.js';
|
|
21
|
+
export interface ChannelsRouterOptions {
|
|
22
|
+
adapters: Map<string, ChannelAdapter>;
|
|
23
|
+
sessionMapper: ChannelSessionMapper;
|
|
24
|
+
sessionManager: StandaloneSessionManager;
|
|
25
|
+
dedupCache: MessageDedupCache;
|
|
26
|
+
eventBus: RuntimeEventBus;
|
|
27
|
+
logger: Logger;
|
|
28
|
+
}
|
|
29
|
+
export declare function createChannelsRouter(options: ChannelsRouterOptions): Router;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Express router for inbound messaging channel webhooks.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the `createWebhookRouter` pattern from routes/webhooks.ts:
|
|
10
|
+
* rate-limited, dispatches to registered channel adapters, and runs
|
|
11
|
+
* the message through the existing SessionManager.
|
|
12
|
+
*
|
|
13
|
+
* Route: POST /channels/:channelType/webhook
|
|
14
|
+
*/
|
|
15
|
+
import { Router } from 'express';
|
|
16
|
+
import rateLimit from 'express-rate-limit';
|
|
17
|
+
import { asyncHandler } from '../routes/route-helpers.js';
|
|
18
|
+
const ROUTE_PATH = '/:channelType/webhook';
|
|
19
|
+
const RESET_COMMANDS = new Set(['/reset', '/start', '/new']);
|
|
20
|
+
const PREVIEW_LENGTH = 50;
|
|
21
|
+
const FALLBACK_ERROR_MESSAGE = 'Something went wrong. Please try again.';
|
|
22
|
+
export function createChannelsRouter(options) {
|
|
23
|
+
const { adapters, sessionMapper, sessionManager, dedupCache, eventBus, logger } = options;
|
|
24
|
+
const router = Router();
|
|
25
|
+
const limiter = rateLimit({
|
|
26
|
+
windowMs: 60 * 1000,
|
|
27
|
+
max: 100,
|
|
28
|
+
standardHeaders: true,
|
|
29
|
+
legacyHeaders: false,
|
|
30
|
+
validate: { xForwardedForHeader: false },
|
|
31
|
+
});
|
|
32
|
+
router.post(ROUTE_PATH, limiter, asyncHandler(async (req, res) => {
|
|
33
|
+
const channelType = req.params['channelType'] ?? '';
|
|
34
|
+
const adapter = adapters.get(channelType);
|
|
35
|
+
if (!adapter) {
|
|
36
|
+
res.status(404).json({ error: `Unknown channel type: ${channelType}` });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Build framework-agnostic request for the adapter
|
|
40
|
+
const webhookReq = {
|
|
41
|
+
headers: req.headers,
|
|
42
|
+
body: req.body,
|
|
43
|
+
};
|
|
44
|
+
// Parse and verify the incoming message
|
|
45
|
+
const msg = await adapter.parseIncoming(webhookReq);
|
|
46
|
+
if (!msg) {
|
|
47
|
+
// Rejected (bad signature, unauthorized sender, or non-text update).
|
|
48
|
+
// Always return 200 — platforms retry on non-200.
|
|
49
|
+
eventBus.emit({
|
|
50
|
+
type: 'channel_auth_rejected',
|
|
51
|
+
channelType,
|
|
52
|
+
reason: 'rejected',
|
|
53
|
+
});
|
|
54
|
+
res.status(200).json({ ok: true });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Dedup check (platforms may resend on slow 200s)
|
|
58
|
+
if (dedupCache.isDuplicate(msg.channelType, msg.messageId)) {
|
|
59
|
+
logger.debug('channel_message_duplicate', { channelType, messageId: msg.messageId });
|
|
60
|
+
res.status(200).json({ ok: true });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Handle special reset commands
|
|
64
|
+
if (RESET_COMMANDS.has(msg.text.trim().toLowerCase())) {
|
|
65
|
+
await sessionMapper.resetSession(msg.channelType, msg.channelUserId);
|
|
66
|
+
await adapter.sendMessage({ channelType: msg.channelType, conversationId: msg.conversationId }, 'Session reset. Send a message to start a new conversation.');
|
|
67
|
+
res.status(200).json({ ok: true });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Emit inbound event
|
|
71
|
+
eventBus.emit({
|
|
72
|
+
type: 'channel_message_received',
|
|
73
|
+
channelType: msg.channelType,
|
|
74
|
+
channelUserId: msg.channelUserId,
|
|
75
|
+
sessionId: '', // Will be filled after session lookup
|
|
76
|
+
messagePreview: msg.text.slice(0, PREVIEW_LENGTH),
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
// Find or create session
|
|
80
|
+
let { sessionId } = await sessionMapper.findOrCreateSession(msg.channelType, msg.channelUserId, msg.channelUserDisplay);
|
|
81
|
+
// If the session isn't in memory (evicted or server restarted),
|
|
82
|
+
// reset the stale mapping and create a fresh session.
|
|
83
|
+
if (!sessionManager.get(sessionId)) {
|
|
84
|
+
logger.debug('channel_session_stale', { channelType: msg.channelType, sessionId });
|
|
85
|
+
await sessionMapper.resetSession(msg.channelType, msg.channelUserId);
|
|
86
|
+
const fresh = await sessionMapper.findOrCreateSession(msg.channelType, msg.channelUserId, msg.channelUserDisplay);
|
|
87
|
+
sessionId = fresh.sessionId;
|
|
88
|
+
}
|
|
89
|
+
// Notify the adapter that processing is starting (adapter decides how to show it)
|
|
90
|
+
const cleanup = adapter.startProcessing
|
|
91
|
+
? await adapter.startProcessing(msg.conversationId)
|
|
92
|
+
: null;
|
|
93
|
+
// Run the message through the agent loop, collecting the full reply
|
|
94
|
+
const replyParts = [];
|
|
95
|
+
try {
|
|
96
|
+
const stream = sessionManager.runMessage(sessionId, msg.text);
|
|
97
|
+
for await (const event of stream) {
|
|
98
|
+
if (event.type === 'text_delta' && 'content' in event) {
|
|
99
|
+
replyParts.push(String(event.content));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
try {
|
|
105
|
+
cleanup?.stop();
|
|
106
|
+
}
|
|
107
|
+
catch (stopErr) {
|
|
108
|
+
logger.error('channel_cleanup_stop_failed', {
|
|
109
|
+
channelType: msg.channelType,
|
|
110
|
+
error: stopErr instanceof Error ? stopErr.message : String(stopErr),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const fullReply = replyParts.join('');
|
|
115
|
+
if (fullReply.length > 0) {
|
|
116
|
+
// Let the adapter deliver the response (may edit a placeholder or send fresh)
|
|
117
|
+
let delivered = false;
|
|
118
|
+
if (cleanup) {
|
|
119
|
+
try {
|
|
120
|
+
delivered = await cleanup.finish(fullReply);
|
|
121
|
+
}
|
|
122
|
+
catch (finishErr) {
|
|
123
|
+
logger.error('channel_cleanup_finish_failed', {
|
|
124
|
+
channelType: msg.channelType,
|
|
125
|
+
error: finishErr instanceof Error ? finishErr.message : String(finishErr),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!delivered) {
|
|
130
|
+
await adapter.sendMessage({ channelType: msg.channelType, conversationId: msg.conversationId }, fullReply);
|
|
131
|
+
}
|
|
132
|
+
eventBus.emit({
|
|
133
|
+
type: 'channel_reply_sent',
|
|
134
|
+
channelType: msg.channelType,
|
|
135
|
+
channelUserId: msg.channelUserId,
|
|
136
|
+
sessionId,
|
|
137
|
+
replyPreview: fullReply.slice(0, PREVIEW_LENGTH),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
logger.error('channel_message_failed', {
|
|
143
|
+
channelType: msg.channelType,
|
|
144
|
+
channelUserId: msg.channelUserId,
|
|
145
|
+
messageId: msg.messageId,
|
|
146
|
+
error: err instanceof Error ? err.message : String(err),
|
|
147
|
+
});
|
|
148
|
+
// Send a user-friendly error message
|
|
149
|
+
try {
|
|
150
|
+
await adapter.sendMessage({ channelType: msg.channelType, conversationId: msg.conversationId }, FALLBACK_ERROR_MESSAGE);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// If even the error message fails, just log — can't do more
|
|
154
|
+
logger.error('channel_error_reply_failed', {
|
|
155
|
+
channelType: msg.channelType,
|
|
156
|
+
channelUserId: msg.channelUserId,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Always return 200 to prevent platform retries
|
|
161
|
+
res.status(200).json({ ok: true });
|
|
162
|
+
}));
|
|
163
|
+
return router;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/channels/routes.ts"],"names":[],"mappings":"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"}
|
package/dist/src/config.d.ts
CHANGED
|
@@ -16,8 +16,6 @@ export interface AgentConfig {
|
|
|
16
16
|
readonly version: string;
|
|
17
17
|
/** Agent description */
|
|
18
18
|
readonly description?: string;
|
|
19
|
-
/** Standing instructions for the LLM (userContext from amodal.json) */
|
|
20
|
-
readonly userContext?: string;
|
|
21
19
|
/** Custom base system prompt (overrides default) */
|
|
22
20
|
readonly basePrompt?: string;
|
|
23
21
|
/** Subagent names to disable */
|