openbot 0.4.5 → 0.4.7
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/app/channel-ids.js +3 -0
- package/dist/app/cli.js +1 -1
- package/dist/app/responding-agent.js +32 -0
- package/dist/app/server.js +33 -5
- package/dist/plugins/openbot/context.js +6 -25
- package/dist/plugins/openbot/index.js +2 -1
- package/dist/plugins/openbot/runtime.js +116 -81
- package/dist/plugins/openbot/system-prompt.js +4 -7
- package/dist/plugins/plugin-manager/index.js +3 -45
- package/dist/plugins/storage/index.js +2 -41
- package/dist/plugins/storage/service.js +54 -14
- package/dist/services/plugins/service.js +0 -4
- package/package.json +2 -1
- package/src/app/channel-ids.ts +5 -0
- package/src/app/cli.ts +1 -1
- package/src/app/responding-agent.ts +46 -0
- package/src/app/server.ts +41 -6
- package/src/app/types.ts +7 -10
- package/src/plugins/openbot/context.ts +7 -26
- package/src/plugins/openbot/index.ts +2 -1
- package/src/plugins/openbot/runtime.ts +137 -89
- package/src/plugins/openbot/system-prompt.ts +4 -9
- package/src/plugins/plugin-manager/index.ts +2 -50
- package/src/plugins/storage/index.ts +4 -46
- package/src/plugins/storage/service.ts +78 -14
- package/src/services/plugins/domain.ts +7 -4
- package/src/services/plugins/service.ts +0 -6
- package/dist/plugins/thread-naming/generate-title.js +0 -44
- package/dist/plugins/thread-naming/index.js +0 -103
- package/dist/services/thread-naming.js +0 -81
|
@@ -340,18 +340,16 @@ const isRecord = (value) => !!value && typeof value === 'object' && !Array.isArr
|
|
|
340
340
|
/** Display-oriented fields persisted in a channel's `state.json`. */
|
|
341
341
|
const readChannelStateFileFields = (parsed) => {
|
|
342
342
|
if (!isRecord(parsed)) {
|
|
343
|
-
return {
|
|
343
|
+
return {};
|
|
344
344
|
}
|
|
345
345
|
const name = typeof parsed.name === 'string' && parsed.name.trim() ? parsed.name.trim() : undefined;
|
|
346
346
|
const cwd = typeof parsed.cwd === 'string' ? parsed.cwd : undefined;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
return { name, cwd, participants };
|
|
347
|
+
return { name, cwd };
|
|
348
|
+
};
|
|
349
|
+
const isChannelProvisioned = async (channelId) => {
|
|
350
|
+
const statePath = `${getConversationDir(channelId)}/state.json`;
|
|
351
|
+
const state = await readJsonFile(statePath, {});
|
|
352
|
+
return !!readChannelStateFileFields(state).cwd;
|
|
355
353
|
};
|
|
356
354
|
/**
|
|
357
355
|
* Parse the `plugins:` array from AGENT.md frontmatter. Each entry must have an
|
|
@@ -412,23 +410,23 @@ export const storageService = {
|
|
|
412
410
|
const statePath = path.join(channelDir, 'state.json');
|
|
413
411
|
let cwd;
|
|
414
412
|
let displayName = name;
|
|
415
|
-
let participants = [];
|
|
416
413
|
try {
|
|
417
414
|
const parsed = await readJsonFile(statePath, {});
|
|
418
415
|
const fields = readChannelStateFileFields(parsed);
|
|
419
416
|
cwd = fields.cwd;
|
|
420
417
|
displayName = fields.name ?? name;
|
|
421
|
-
participants = fields.participants;
|
|
422
418
|
}
|
|
423
419
|
catch {
|
|
424
420
|
// ignore
|
|
425
421
|
}
|
|
422
|
+
if (!cwd) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
426
425
|
const channel = {
|
|
427
426
|
id: name,
|
|
428
427
|
name: displayName,
|
|
429
428
|
description: '',
|
|
430
429
|
cwd,
|
|
431
|
-
participants,
|
|
432
430
|
createdAt: stats.birthtime,
|
|
433
431
|
updatedAt: stats.mtime,
|
|
434
432
|
};
|
|
@@ -452,7 +450,9 @@ export const storageService = {
|
|
|
452
450
|
}
|
|
453
451
|
return channel;
|
|
454
452
|
}));
|
|
455
|
-
return channels
|
|
453
|
+
return channels
|
|
454
|
+
.filter((channel) => channel !== null)
|
|
455
|
+
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
456
456
|
},
|
|
457
457
|
createChannel: async ({ channelId, spec, initialState, cwd, }) => {
|
|
458
458
|
const normalizedChannelId = channelId.trim();
|
|
@@ -486,6 +486,44 @@ export const storageService = {
|
|
|
486
486
|
`# ${normalizedChannelId}\n\n`);
|
|
487
487
|
await writeJsonFileAtomically(statePath, finalState);
|
|
488
488
|
},
|
|
489
|
+
ensureChannel: async ({ channelId, spec, initialState, cwd, }) => {
|
|
490
|
+
const normalizedChannelId = channelId.trim();
|
|
491
|
+
if (!normalizedChannelId) {
|
|
492
|
+
throw new Error('channelId is required');
|
|
493
|
+
}
|
|
494
|
+
const channelDir = getConversationDir(normalizedChannelId);
|
|
495
|
+
const specPath = `${channelDir}/SPEC.md`;
|
|
496
|
+
const statePath = `${channelDir}/state.json`;
|
|
497
|
+
const existingState = await readJsonFile(statePath, {});
|
|
498
|
+
const existingFields = readChannelStateFileFields(existingState);
|
|
499
|
+
if (existingFields.cwd) {
|
|
500
|
+
await fs.mkdir(resolvePath(existingFields.cwd), { recursive: true });
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const finalState = {
|
|
504
|
+
...existingState,
|
|
505
|
+
...(initialState || {}),
|
|
506
|
+
};
|
|
507
|
+
const rawCwd = (typeof cwd === 'string' && cwd.trim()) ||
|
|
508
|
+
(typeof finalState.cwd === 'string' && finalState.cwd.trim()) ||
|
|
509
|
+
getDefaultChannelCwd(normalizedChannelId);
|
|
510
|
+
const resolvedCwd = resolvePath(rawCwd);
|
|
511
|
+
finalState.cwd = resolvedCwd;
|
|
512
|
+
await fs.mkdir(resolvedCwd, { recursive: true });
|
|
513
|
+
await fs.mkdir(channelDir, { recursive: true });
|
|
514
|
+
try {
|
|
515
|
+
await fs.access(specPath);
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
if (error?.code === 'ENOENT') {
|
|
519
|
+
await fs.writeFile(specPath, spec?.trim() || `# ${normalizedChannelId}\n\n`);
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
await writeJsonFileAtomically(statePath, finalState);
|
|
526
|
+
},
|
|
489
527
|
deleteChannel: async ({ channelId }) => {
|
|
490
528
|
const normalizedChannelId = channelId.trim();
|
|
491
529
|
if (!normalizedChannelId) {
|
|
@@ -648,7 +686,6 @@ export const storageService = {
|
|
|
648
686
|
spec,
|
|
649
687
|
state,
|
|
650
688
|
cwd,
|
|
651
|
-
participants: diskFields.participants,
|
|
652
689
|
};
|
|
653
690
|
details.threads = await storageService.getThreads({ channelId });
|
|
654
691
|
return details;
|
|
@@ -1030,6 +1067,9 @@ export const storageService = {
|
|
|
1030
1067
|
},
|
|
1031
1068
|
storeEvent: async ({ channelId, threadId, event, }) => {
|
|
1032
1069
|
try {
|
|
1070
|
+
if (!(await isChannelProvisioned(channelId))) {
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1033
1073
|
const threadDir = getConversationDir(channelId, threadId);
|
|
1034
1074
|
if (threadId) {
|
|
1035
1075
|
let exists = false;
|
|
@@ -74,20 +74,16 @@ export function parseMarketplaceRegistryJson(data) {
|
|
|
74
74
|
const id = item.id;
|
|
75
75
|
const name = item.name;
|
|
76
76
|
const description = item.description;
|
|
77
|
-
const participants = item.participants;
|
|
78
77
|
if (typeof id !== 'string' || !id)
|
|
79
78
|
throw new Error(`channels[${i}].id must be a non-empty string`);
|
|
80
79
|
if (typeof name !== 'string')
|
|
81
80
|
throw new Error(`channels[${i}].name must be a string`);
|
|
82
81
|
if (typeof description !== 'string')
|
|
83
82
|
throw new Error(`channels[${i}].description must be a string`);
|
|
84
|
-
if (!Array.isArray(participants))
|
|
85
|
-
throw new Error(`channels[${i}].participants must be an array`);
|
|
86
83
|
const listing = {
|
|
87
84
|
id,
|
|
88
85
|
name,
|
|
89
86
|
description,
|
|
90
|
-
participants: participants.filter((p) => typeof p === 'string'),
|
|
91
87
|
};
|
|
92
88
|
if (typeof item.image === 'string')
|
|
93
89
|
listing.image = item.image;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbot",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@ai-sdk/anthropic": "^3.0.33",
|
|
19
|
+
"@ai-sdk/google": "^3.0.82",
|
|
19
20
|
"@ai-sdk/openai": "^3.0.13",
|
|
20
21
|
"@anthropic-ai/claude-agent-sdk": "^0.2.138",
|
|
21
22
|
"@types/cors": "^2.8.19",
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Default channel when requests omit channelId (general-purpose conversation). */
|
|
2
|
+
export const UNCATEGORIZED_CHANNEL_ID = 'uncategorized';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_UNCATEGORIZED_SPEC =
|
|
5
|
+
'# Uncategorized\n\nGeneral-purpose channel for conversations without a dedicated channel.';
|
package/src/app/cli.ts
CHANGED
|
@@ -4,6 +4,9 @@ import { storageService } from '../plugins/storage/service.js';
|
|
|
4
4
|
/** Thread `state.json` key for the sticky responding agent id. */
|
|
5
5
|
export const THREAD_RESPONDING_AGENT_ID_KEY = 'respondingAgentId';
|
|
6
6
|
|
|
7
|
+
/** Publish events that continue a pending UI interaction rather than a new user turn. */
|
|
8
|
+
export const CONTINUATION_EVENT_TYPES = new Set(['client:ui:widget:response']);
|
|
9
|
+
|
|
7
10
|
export type ResolveRespondingAgentOptions = {
|
|
8
11
|
channelId: string;
|
|
9
12
|
threadId?: string;
|
|
@@ -20,6 +23,14 @@ export type ResolveRespondingAgentResult = {
|
|
|
20
23
|
overridden: boolean;
|
|
21
24
|
};
|
|
22
25
|
|
|
26
|
+
const readMetaAgentId = (meta: unknown): string | undefined => {
|
|
27
|
+
if (!meta || typeof meta !== 'object') return undefined;
|
|
28
|
+
const value = (meta as Record<string, unknown>).agentId;
|
|
29
|
+
if (typeof value !== 'string') return undefined;
|
|
30
|
+
const trimmed = value.trim();
|
|
31
|
+
return trimmed || undefined;
|
|
32
|
+
};
|
|
33
|
+
|
|
23
34
|
const readBoundAgentId = (state: unknown): string | undefined => {
|
|
24
35
|
if (!state || typeof state !== 'object') return undefined;
|
|
25
36
|
const value = (state as Record<string, unknown>)[THREAD_RESPONDING_AGENT_ID_KEY];
|
|
@@ -72,3 +83,38 @@ export async function resolveRespondingAgentId(
|
|
|
72
83
|
|
|
73
84
|
return { agentId: fallback, bound: true, overridden: false };
|
|
74
85
|
}
|
|
86
|
+
|
|
87
|
+
export type ResolvePublishTargetAgentOptions = {
|
|
88
|
+
eventType: string;
|
|
89
|
+
channelId: string;
|
|
90
|
+
threadId?: string;
|
|
91
|
+
requestedAgentId?: string;
|
|
92
|
+
eventMeta?: unknown;
|
|
93
|
+
bindIfUnbound?: boolean;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolves the agent that should handle a publish event.
|
|
98
|
+
* UI continuations route to the widget origin agent; everything else uses sticky thread binding.
|
|
99
|
+
*/
|
|
100
|
+
export async function resolvePublishTargetAgentId(
|
|
101
|
+
options: ResolvePublishTargetAgentOptions,
|
|
102
|
+
): Promise<{ agentId: string } | { error: 'agentId_required' }> {
|
|
103
|
+
const { eventType, channelId, threadId, requestedAgentId, eventMeta, bindIfUnbound } = options;
|
|
104
|
+
|
|
105
|
+
if (CONTINUATION_EVENT_TYPES.has(eventType)) {
|
|
106
|
+
const originAgentId = readMetaAgentId(eventMeta) || requestedAgentId?.trim();
|
|
107
|
+
if (!originAgentId) {
|
|
108
|
+
return { error: 'agentId_required' };
|
|
109
|
+
}
|
|
110
|
+
return { agentId: originAgentId };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const resolved = await resolveRespondingAgentId({
|
|
114
|
+
channelId,
|
|
115
|
+
threadId,
|
|
116
|
+
requestedAgentId,
|
|
117
|
+
bindIfUnbound,
|
|
118
|
+
});
|
|
119
|
+
return { agentId: resolved.agentId };
|
|
120
|
+
}
|
package/src/app/server.ts
CHANGED
|
@@ -21,7 +21,11 @@ import {
|
|
|
21
21
|
} from '../plugins/storage/files.js';
|
|
22
22
|
import { ensureEventId, openBotEventFromQuery } from './utils.js';
|
|
23
23
|
import { abortRegistry, abortKey } from '../services/abort.js';
|
|
24
|
-
import { resolveRespondingAgentId } from './responding-agent.js';
|
|
24
|
+
import { resolvePublishTargetAgentId, resolveRespondingAgentId } from './responding-agent.js';
|
|
25
|
+
import {
|
|
26
|
+
DEFAULT_UNCATEGORIZED_SPEC,
|
|
27
|
+
UNCATEGORIZED_CHANNEL_ID,
|
|
28
|
+
} from './channel-ids.js';
|
|
25
29
|
|
|
26
30
|
type Bucket = { channelId: string; threadId?: string; activeCount: number; agentIds: Set<string> };
|
|
27
31
|
|
|
@@ -65,9 +69,18 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
65
69
|
storageService.getAgents().catch((err) => console.warn('[server] Failed to pre-warm agents cache', err));
|
|
66
70
|
storageService.getPlugins().catch((err) => console.warn('[server] Failed to pre-warm plugins cache', err));
|
|
67
71
|
|
|
72
|
+
const getRawChannelId = (req: express.Request): string | undefined => {
|
|
73
|
+
const raw =
|
|
74
|
+
req.get('x-openbot-channel-id') ||
|
|
75
|
+
req.query.channelId ||
|
|
76
|
+
(req.body && req.body.channelId);
|
|
77
|
+
if (typeof raw !== 'string') return undefined;
|
|
78
|
+
const trimmed = raw.trim();
|
|
79
|
+
return trimmed || undefined;
|
|
80
|
+
};
|
|
81
|
+
|
|
68
82
|
const getContext = (req: express.Request) => {
|
|
69
|
-
const
|
|
70
|
-
req.get('x-openbot-channel-id') || req.query.channelId || (req.body && req.body.channelId);
|
|
83
|
+
const rawChannelId = getRawChannelId(req);
|
|
71
84
|
const threadId =
|
|
72
85
|
req.get('x-openbot-thread-id') || req.query.threadId || (req.body && req.body.threadId);
|
|
73
86
|
const agentId =
|
|
@@ -83,7 +96,8 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
83
96
|
(req.body && req.body.responseType);
|
|
84
97
|
|
|
85
98
|
return {
|
|
86
|
-
channelId: (
|
|
99
|
+
channelId: (rawChannelId || UNCATEGORIZED_CHANNEL_ID) as string,
|
|
100
|
+
rawChannelId,
|
|
87
101
|
threadId: threadId as string | undefined,
|
|
88
102
|
agentId: agentId as string | undefined,
|
|
89
103
|
runId: runId as string,
|
|
@@ -532,17 +546,38 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
532
546
|
try {
|
|
533
547
|
ensureEventId(event);
|
|
534
548
|
|
|
549
|
+
const isUserConversationStart =
|
|
550
|
+
event.type === 'agent:invoke' &&
|
|
551
|
+
event.data?.role === 'user' &&
|
|
552
|
+
typeof event.data.content === 'string' &&
|
|
553
|
+
event.data.content.trim().length > 0;
|
|
554
|
+
|
|
555
|
+
if (isUserConversationStart && channelId === UNCATEGORIZED_CHANNEL_ID) {
|
|
556
|
+
await storageService.ensureChannel({
|
|
557
|
+
channelId: UNCATEGORIZED_CHANNEL_ID,
|
|
558
|
+
spec: DEFAULT_UNCATEGORIZED_SPEC,
|
|
559
|
+
initialState: { name: 'Uncategorized' },
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
535
563
|
const bindIfUnbound = event.type === 'agent:invoke';
|
|
536
|
-
const
|
|
564
|
+
const target = await resolvePublishTargetAgentId({
|
|
565
|
+
eventType: event.type,
|
|
537
566
|
channelId,
|
|
538
567
|
threadId,
|
|
539
568
|
requestedAgentId: agentId,
|
|
569
|
+
eventMeta: event.meta,
|
|
540
570
|
bindIfUnbound,
|
|
541
571
|
});
|
|
542
572
|
|
|
573
|
+
if ('error' in target) {
|
|
574
|
+
res.status(400).json({ error: 'agentId is required for widget response' });
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
|
|
543
578
|
await runAgent({
|
|
544
579
|
runId,
|
|
545
|
-
agentId:
|
|
580
|
+
agentId: target.agentId,
|
|
546
581
|
event,
|
|
547
582
|
channelId,
|
|
548
583
|
threadId,
|
package/src/app/types.ts
CHANGED
|
@@ -301,8 +301,6 @@ export type PatchChannelDetailsEvent = BaseEvent & {
|
|
|
301
301
|
state?: Record<string, unknown>;
|
|
302
302
|
spec?: string;
|
|
303
303
|
cwd?: string;
|
|
304
|
-
/** When set, replaces `state.json` `participants` (merged after `state` if both are sent). */
|
|
305
|
-
participants?: string[];
|
|
306
304
|
};
|
|
307
305
|
};
|
|
308
306
|
|
|
@@ -310,7 +308,7 @@ export type PatchChannelDetailsResultEvent = BaseEvent & {
|
|
|
310
308
|
type: 'action:patch_channel_details:result';
|
|
311
309
|
data: {
|
|
312
310
|
success: boolean;
|
|
313
|
-
updatedFields: ('state' | 'spec' | 'cwd'
|
|
311
|
+
updatedFields: ('state' | 'spec' | 'cwd')[];
|
|
314
312
|
};
|
|
315
313
|
};
|
|
316
314
|
|
|
@@ -569,8 +567,6 @@ export type CreateChannelEvent = BaseEvent & {
|
|
|
569
567
|
spec?: string;
|
|
570
568
|
initialState?: Record<string, unknown>;
|
|
571
569
|
cwd?: string;
|
|
572
|
-
/** Initial channel agent ids; written into `state.json` (overrides `initialState.participants` if both are set). */
|
|
573
|
-
participants?: string[];
|
|
574
570
|
};
|
|
575
571
|
meta?: {
|
|
576
572
|
toolCallId?: string;
|
|
@@ -594,8 +590,6 @@ export type UpdateChannelEvent = BaseEvent & {
|
|
|
594
590
|
channelId?: string;
|
|
595
591
|
name?: string;
|
|
596
592
|
cwd?: string;
|
|
597
|
-
/** Replaces the channel participant list when provided. */
|
|
598
|
-
participants?: string[];
|
|
599
593
|
};
|
|
600
594
|
};
|
|
601
595
|
|
|
@@ -655,7 +649,7 @@ export type UIWidgetAction = {
|
|
|
655
649
|
export type UIWidgetField = {
|
|
656
650
|
id: string;
|
|
657
651
|
label: string;
|
|
658
|
-
type: 'text' | 'textarea' | 'number' | 'boolean' | 'select' | 'multiselect' | 'date';
|
|
652
|
+
type: 'text' | 'textarea' | 'number' | 'boolean' | 'select' | 'multiselect' | 'date' | 'password';
|
|
659
653
|
description?: string;
|
|
660
654
|
placeholder?: string;
|
|
661
655
|
required?: boolean;
|
|
@@ -736,6 +730,11 @@ export type UIWidgetResponseEvent = BaseEvent & {
|
|
|
736
730
|
values?: Record<string, unknown>;
|
|
737
731
|
metadata?: Record<string, unknown>;
|
|
738
732
|
};
|
|
733
|
+
meta?: {
|
|
734
|
+
agentId?: string;
|
|
735
|
+
threadId?: string;
|
|
736
|
+
[key: string]: unknown;
|
|
737
|
+
};
|
|
739
738
|
};
|
|
740
739
|
|
|
741
740
|
export type BashEvent = BaseEvent & {
|
|
@@ -851,7 +850,6 @@ export type ListMarketplaceRegistryResultEvent = BaseEvent & {
|
|
|
851
850
|
image?: string;
|
|
852
851
|
spec?: string;
|
|
853
852
|
initialState?: Record<string, unknown>;
|
|
854
|
-
participants: string[];
|
|
855
853
|
starterPrompts?: Array<{ label: string; prompt: string }>;
|
|
856
854
|
}>;
|
|
857
855
|
error?: string;
|
|
@@ -863,7 +861,6 @@ export type InstallChannelEvent = BaseEvent & {
|
|
|
863
861
|
data: {
|
|
864
862
|
channelId: string;
|
|
865
863
|
name?: string;
|
|
866
|
-
participants?: string[];
|
|
867
864
|
initialState?: Record<string, unknown>;
|
|
868
865
|
};
|
|
869
866
|
};
|
|
@@ -27,20 +27,11 @@ export const getContextBudgetForModel = (modelString: string): number => {
|
|
|
27
27
|
/** Built-in orchestrator agent id. */
|
|
28
28
|
export const ORCHESTRATOR_AGENT_ID = 'system';
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* Check if a channel is a solo DM (only the agent is present).
|
|
32
|
-
*/
|
|
33
|
-
export function isDmSoloChannel(participants: string[], agentId: string): boolean {
|
|
34
|
-
return participants.length === 0 || (participants.length === 1 && participants[0] === agentId);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
30
|
/**
|
|
38
31
|
* Simplified context builder for MVP.
|
|
39
32
|
*/
|
|
40
33
|
export async function buildContext(state: OpenBotState, storage?: Storage): Promise<string> {
|
|
41
34
|
const { channelId, threadId, channelDetails, agentId, threadDetails, agentDetails } = state;
|
|
42
|
-
const participants = channelDetails?.participants || [];
|
|
43
|
-
const isDm = isDmSoloChannel(participants, agentId);
|
|
44
35
|
|
|
45
36
|
const sections: string[] = [];
|
|
46
37
|
|
|
@@ -54,23 +45,13 @@ export async function buildContext(state: OpenBotState, storage?: Storage): Prom
|
|
|
54
45
|
|
|
55
46
|
// 2. Environment
|
|
56
47
|
let env = '## ENVIRONMENT\n';
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
if (threadId) {
|
|
66
|
-
env += `- Thread: ${threadDetails?.name || threadId}\n`;
|
|
67
|
-
}
|
|
68
|
-
const peerIds = participants.filter((id: string) => id !== agentId);
|
|
69
|
-
const participantLabels = peerIds.map((id) => {
|
|
70
|
-
const agent = allAgents.find((a) => a.id === id);
|
|
71
|
-
return agent ? `${agent.name} (${id})` : id;
|
|
72
|
-
});
|
|
73
|
-
env += `- Participants: ${participantLabels.length > 0 ? participantLabels.join(', ') : 'None'}\n`;
|
|
48
|
+
const channelName = channelDetails?.name || channelId;
|
|
49
|
+
env += `- Mode: Channel (#${channelName})\n`;
|
|
50
|
+
if (channelDetails?.cwd) {
|
|
51
|
+
env += `- Workspace: ${channelDetails.cwd}\n`;
|
|
52
|
+
}
|
|
53
|
+
if (threadId) {
|
|
54
|
+
env += `- Thread: ${threadDetails?.name || threadId}\n`;
|
|
74
55
|
}
|
|
75
56
|
sections.push(env);
|
|
76
57
|
|
|
@@ -49,7 +49,8 @@ export const openbotPlugin: Plugin = {
|
|
|
49
49
|
...memoryPlugin.toolDefinitions,
|
|
50
50
|
...storagePlugin.toolDefinitions,
|
|
51
51
|
...delegationPlugin.toolDefinitions,
|
|
52
|
-
|
|
52
|
+
// this is the capability to render UI widgets to the user. We dont need it for now.
|
|
53
|
+
// ...uiPlugin.toolDefinitions,
|
|
53
54
|
},
|
|
54
55
|
factory: (context) => (builder) => {
|
|
55
56
|
const { config, storage, tools, abortSignal } = context;
|