@bike4mind/cli 0.2.58 → 0.2.59-feat-cli-tavern-integration.21571
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/{chunk-WPK7K4BM.js → chunk-BPUFVNEJ.js} +27 -6
- package/dist/{chunk-XZLLBLTF.js → chunk-PEG5MIUM.js} +12 -12
- package/dist/{chunk-RB5GFKSM.js → chunk-U52SND4Y.js} +3 -0
- package/dist/{chunk-G2LYCVZJ.js → chunk-Y4WOJJM3.js} +8 -1
- package/dist/commands/doctorCommand.js +1 -1
- package/dist/commands/headlessCommand.js +2 -2
- package/dist/commands/mcpCommand.js +1 -1
- package/dist/commands/updateCommand.js +1 -1
- package/dist/index.js +1075 -18
- package/dist/{store-X5LEOSGZ.js → store-CAB6BV3P.js} +1 -1
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
WebSocketToolExecutor,
|
|
23
23
|
buildCoreSystemPrompt,
|
|
24
24
|
buildSkillsPromptSection,
|
|
25
|
+
clearFeatureModuleTools,
|
|
25
26
|
createAgentDelegateTool,
|
|
26
27
|
createBackgroundAgentTools,
|
|
27
28
|
createFindDefinitionTool,
|
|
@@ -41,12 +42,13 @@ import {
|
|
|
41
42
|
mergeCommands,
|
|
42
43
|
parseAgentConfig,
|
|
43
44
|
processFileReferences,
|
|
45
|
+
registerFeatureModuleTools,
|
|
44
46
|
searchCommands,
|
|
45
47
|
searchFiles,
|
|
46
48
|
setWebSocketToolExecutor,
|
|
47
49
|
substituteArguments,
|
|
48
50
|
warmFileCache
|
|
49
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-BPUFVNEJ.js";
|
|
50
52
|
import "./chunk-BDQBOLYG.js";
|
|
51
53
|
import "./chunk-5TQE3IBF.js";
|
|
52
54
|
import "./chunk-GQGOWACU.js";
|
|
@@ -60,15 +62,15 @@ import "./chunk-BPFEGDC7.js";
|
|
|
60
62
|
import {
|
|
61
63
|
ConfigStore,
|
|
62
64
|
logger
|
|
63
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-U52SND4Y.js";
|
|
64
66
|
import {
|
|
65
67
|
checkForUpdate,
|
|
66
68
|
package_default
|
|
67
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-PEG5MIUM.js";
|
|
68
70
|
import {
|
|
69
71
|
selectActiveBackgroundAgents,
|
|
70
72
|
useCliStore
|
|
71
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-Y4WOJJM3.js";
|
|
72
74
|
import {
|
|
73
75
|
CREDIT_DEDUCT_TRANSACTION_TYPES,
|
|
74
76
|
ChatModels,
|
|
@@ -1422,6 +1424,19 @@ function buildConfigItems(availableModels) {
|
|
|
1422
1424
|
enableDynamicAgentCreation: value
|
|
1423
1425
|
}
|
|
1424
1426
|
})
|
|
1427
|
+
},
|
|
1428
|
+
{
|
|
1429
|
+
key: "featuresTavern",
|
|
1430
|
+
label: "Tavern",
|
|
1431
|
+
type: "boolean",
|
|
1432
|
+
getValue: (config) => config.features?.tavern ?? false,
|
|
1433
|
+
setValue: (config, value) => ({
|
|
1434
|
+
...config,
|
|
1435
|
+
features: {
|
|
1436
|
+
...config.features,
|
|
1437
|
+
tavern: value
|
|
1438
|
+
}
|
|
1439
|
+
})
|
|
1425
1440
|
}
|
|
1426
1441
|
);
|
|
1427
1442
|
return items;
|
|
@@ -1433,8 +1448,15 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1433
1448
|
const [isSaving, setIsSaving] = useState7(false);
|
|
1434
1449
|
const configItems = useMemo3(() => buildConfigItems(availableModels), [availableModels]);
|
|
1435
1450
|
const hasChanges = useMemo3(() => {
|
|
1436
|
-
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
|
|
1437
|
-
}, [
|
|
1451
|
+
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel || JSON.stringify(config.features) !== JSON.stringify(editedConfig.features);
|
|
1452
|
+
}, [
|
|
1453
|
+
config.preferences,
|
|
1454
|
+
editedConfig.preferences,
|
|
1455
|
+
config.defaultModel,
|
|
1456
|
+
editedConfig.defaultModel,
|
|
1457
|
+
config.features,
|
|
1458
|
+
editedConfig.features
|
|
1459
|
+
]);
|
|
1438
1460
|
const handleSaveAndClose = async () => {
|
|
1439
1461
|
if (hasChanges) {
|
|
1440
1462
|
try {
|
|
@@ -2982,6 +3004,942 @@ Unlike agent_delegate (which uses pre-defined agents), this tool lets you compos
|
|
|
2982
3004
|
};
|
|
2983
3005
|
}
|
|
2984
3006
|
|
|
3007
|
+
// src/features/FeatureModuleRegistry.ts
|
|
3008
|
+
var FeatureModuleRegistry = class {
|
|
3009
|
+
constructor() {
|
|
3010
|
+
this.modules = [];
|
|
3011
|
+
}
|
|
3012
|
+
/** Register a feature module */
|
|
3013
|
+
register(module) {
|
|
3014
|
+
if (this.modules.some((m) => m.name === module.name)) {
|
|
3015
|
+
throw new Error(`Feature module '${module.name}' is already registered`);
|
|
3016
|
+
}
|
|
3017
|
+
this.modules.push(module);
|
|
3018
|
+
}
|
|
3019
|
+
/** Collect all tools from all registered modules */
|
|
3020
|
+
getAllTools() {
|
|
3021
|
+
return this.modules.flatMap((m) => m.getTools());
|
|
3022
|
+
}
|
|
3023
|
+
/** Get all tool names from all registered modules */
|
|
3024
|
+
getAllToolNames() {
|
|
3025
|
+
return this.getAllTools().map((t) => t.toolSchema.name);
|
|
3026
|
+
}
|
|
3027
|
+
/** Build combined system prompt section from all modules */
|
|
3028
|
+
getSystemPromptSections() {
|
|
3029
|
+
const sections = this.modules.map((m) => m.getSystemPromptSection()).filter((s) => s.length > 0);
|
|
3030
|
+
return sections.length > 0 ? "\n\n" + sections.join("\n\n") : "";
|
|
3031
|
+
}
|
|
3032
|
+
/** Register all WS handlers from all modules */
|
|
3033
|
+
registerAllWsHandlers(wsManager) {
|
|
3034
|
+
for (const module of this.modules) {
|
|
3035
|
+
module.registerWsHandlers?.(wsManager);
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
/** Collect all slash commands from all registered modules */
|
|
3039
|
+
getAllCommands() {
|
|
3040
|
+
return this.modules.flatMap((m) => m.getCommands?.() ?? []);
|
|
3041
|
+
}
|
|
3042
|
+
/** Try to execute a slash command. Returns true if handled. */
|
|
3043
|
+
executeCommand(name, args) {
|
|
3044
|
+
for (const module of this.modules) {
|
|
3045
|
+
const commands = module.getCommands?.() ?? [];
|
|
3046
|
+
const command = commands.find((c) => c.name === name);
|
|
3047
|
+
if (command) {
|
|
3048
|
+
command.execute(args);
|
|
3049
|
+
return true;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
return false;
|
|
3053
|
+
}
|
|
3054
|
+
/** Cleanup all modules */
|
|
3055
|
+
disposeAll() {
|
|
3056
|
+
for (const module of this.modules) {
|
|
3057
|
+
module.dispose?.();
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
/** Get names of all registered modules */
|
|
3061
|
+
getModuleNames() {
|
|
3062
|
+
return this.modules.map((m) => m.name);
|
|
3063
|
+
}
|
|
3064
|
+
/** Check if any modules are registered */
|
|
3065
|
+
get hasModules() {
|
|
3066
|
+
return this.modules.length > 0;
|
|
3067
|
+
}
|
|
3068
|
+
};
|
|
3069
|
+
|
|
3070
|
+
// src/features/tavern/TavernService.ts
|
|
3071
|
+
var TavernService = class {
|
|
3072
|
+
constructor(apiClient) {
|
|
3073
|
+
this.apiClient = apiClient;
|
|
3074
|
+
}
|
|
3075
|
+
async listAgents() {
|
|
3076
|
+
return this.apiClient.get("/api/agents?limit=100");
|
|
3077
|
+
}
|
|
3078
|
+
async createAgent(request) {
|
|
3079
|
+
return this.apiClient.post("/api/agents", request);
|
|
3080
|
+
}
|
|
3081
|
+
async updateAgent(agentId, request) {
|
|
3082
|
+
return this.apiClient.put(`/api/agents/${encodeURIComponent(agentId)}`, request);
|
|
3083
|
+
}
|
|
3084
|
+
async deleteAgent(agentId) {
|
|
3085
|
+
await this.apiClient.delete(`/api/agents/${encodeURIComponent(agentId)}`);
|
|
3086
|
+
}
|
|
3087
|
+
async mentionAgent(agentName, message, config) {
|
|
3088
|
+
return this.apiClient.post("/api/tavern/mention", {
|
|
3089
|
+
agentName,
|
|
3090
|
+
message,
|
|
3091
|
+
config
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3094
|
+
async listQuests() {
|
|
3095
|
+
return this.apiClient.get("/api/tavern/quests");
|
|
3096
|
+
}
|
|
3097
|
+
async postQuest(request) {
|
|
3098
|
+
return this.apiClient.post("/api/tavern/quests", request);
|
|
3099
|
+
}
|
|
3100
|
+
async deleteQuest(questId) {
|
|
3101
|
+
await this.apiClient.delete(`/api/tavern/quests`, { data: { questId } });
|
|
3102
|
+
}
|
|
3103
|
+
async getAgentNotebook(agentId, limit = 50) {
|
|
3104
|
+
return this.apiClient.get(
|
|
3105
|
+
`/api/tavern/agent-notebook?agentId=${encodeURIComponent(agentId)}&limit=${limit}`
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
async listGates() {
|
|
3109
|
+
return this.apiClient.get("/api/tavern/gates");
|
|
3110
|
+
}
|
|
3111
|
+
async resolveGate(gateId, resolution) {
|
|
3112
|
+
return this.apiClient.post("/api/tavern/gate-resolve", {
|
|
3113
|
+
gateId,
|
|
3114
|
+
resolution
|
|
3115
|
+
});
|
|
3116
|
+
}
|
|
3117
|
+
async toggleHeartbeats(enabled) {
|
|
3118
|
+
return this.apiClient.post("/api/tavern/toggle-heartbeats", { enabled });
|
|
3119
|
+
}
|
|
3120
|
+
async triggerHeartbeat(config) {
|
|
3121
|
+
return this.apiClient.post("/api/tavern/trigger-heartbeat", { config });
|
|
3122
|
+
}
|
|
3123
|
+
async abortHeartbeats() {
|
|
3124
|
+
await this.apiClient.post("/api/tavern/abort-heartbeats", { abort: true });
|
|
3125
|
+
}
|
|
3126
|
+
};
|
|
3127
|
+
|
|
3128
|
+
// src/features/tavern/types.ts
|
|
3129
|
+
import { z } from "zod";
|
|
3130
|
+
var HeartbeatLogEntrySchema = z.object({
|
|
3131
|
+
id: z.string(),
|
|
3132
|
+
agentId: z.string(),
|
|
3133
|
+
agentName: z.string(),
|
|
3134
|
+
action: z.enum([
|
|
3135
|
+
"idle",
|
|
3136
|
+
"speech",
|
|
3137
|
+
"thought",
|
|
3138
|
+
"memory",
|
|
3139
|
+
"move",
|
|
3140
|
+
"reply",
|
|
3141
|
+
"post_quest",
|
|
3142
|
+
"claim_quest",
|
|
3143
|
+
"complete_quest",
|
|
3144
|
+
"tool_use",
|
|
3145
|
+
"email",
|
|
3146
|
+
"move_decoration",
|
|
3147
|
+
"gate_paused",
|
|
3148
|
+
"gate_timed",
|
|
3149
|
+
"gate_proceed",
|
|
3150
|
+
"yolo_override",
|
|
3151
|
+
"intent",
|
|
3152
|
+
"report",
|
|
3153
|
+
"credits"
|
|
3154
|
+
]),
|
|
3155
|
+
text: z.string().optional(),
|
|
3156
|
+
toolOutput: z.string().optional(),
|
|
3157
|
+
targetAgentName: z.string().optional(),
|
|
3158
|
+
threadId: z.string().optional(),
|
|
3159
|
+
timestamp: z.string(),
|
|
3160
|
+
burstId: z.string().optional(),
|
|
3161
|
+
stepIndex: z.number().optional(),
|
|
3162
|
+
totalSteps: z.number().optional(),
|
|
3163
|
+
confidence: z.number().optional(),
|
|
3164
|
+
confidenceSource: z.string().optional(),
|
|
3165
|
+
creditsUsed: z.number().optional()
|
|
3166
|
+
});
|
|
3167
|
+
var CreateAgentRequestSchema = z.object({
|
|
3168
|
+
name: z.string(),
|
|
3169
|
+
description: z.string().optional(),
|
|
3170
|
+
systemPrompt: z.string().optional(),
|
|
3171
|
+
personality: z.object({
|
|
3172
|
+
majorMotivation: z.string().optional(),
|
|
3173
|
+
minorMotivation: z.string().optional(),
|
|
3174
|
+
flaw: z.string().optional(),
|
|
3175
|
+
quirk: z.string().optional(),
|
|
3176
|
+
description: z.string().optional(),
|
|
3177
|
+
personalMission: z.string().optional(),
|
|
3178
|
+
activeProject: z.string().optional(),
|
|
3179
|
+
communicationPattern: z.string().optional(),
|
|
3180
|
+
humorStyle: z.string().optional(),
|
|
3181
|
+
backstoryElement: z.string().optional(),
|
|
3182
|
+
energyLevel: z.string().optional(),
|
|
3183
|
+
coreValues: z.string().optional()
|
|
3184
|
+
}).optional()
|
|
3185
|
+
});
|
|
3186
|
+
var CreateAgentResponseSchema = z.object({
|
|
3187
|
+
_id: z.string(),
|
|
3188
|
+
name: z.string(),
|
|
3189
|
+
description: z.string().optional()
|
|
3190
|
+
});
|
|
3191
|
+
var UpdateAgentRequestSchema = CreateAgentRequestSchema.partial().extend({
|
|
3192
|
+
heartbeatConfig: z.object({
|
|
3193
|
+
enabled: z.boolean().optional(),
|
|
3194
|
+
intervalMinutes: z.number().optional()
|
|
3195
|
+
}).optional()
|
|
3196
|
+
});
|
|
3197
|
+
var AgentSummarySchema = z.object({
|
|
3198
|
+
_id: z.string(),
|
|
3199
|
+
name: z.string(),
|
|
3200
|
+
description: z.string().optional(),
|
|
3201
|
+
heartbeatConfig: z.object({
|
|
3202
|
+
enabled: z.boolean().optional()
|
|
3203
|
+
}).optional()
|
|
3204
|
+
});
|
|
3205
|
+
var AgentListResponseSchema = z.object({
|
|
3206
|
+
data: z.array(AgentSummarySchema),
|
|
3207
|
+
total: z.number().optional()
|
|
3208
|
+
});
|
|
3209
|
+
var MentionRequestSchema = z.object({
|
|
3210
|
+
agentName: z.string().optional(),
|
|
3211
|
+
message: z.string(),
|
|
3212
|
+
config: z.record(z.string(), z.unknown()).optional()
|
|
3213
|
+
});
|
|
3214
|
+
var DirectedMentionResponseSchema = z.object({
|
|
3215
|
+
success: z.boolean(),
|
|
3216
|
+
agentName: z.string(),
|
|
3217
|
+
agentId: z.string(),
|
|
3218
|
+
warning: z.string().optional()
|
|
3219
|
+
});
|
|
3220
|
+
var AmbientMentionResponseSchema = z.object({
|
|
3221
|
+
success: z.boolean(),
|
|
3222
|
+
mode: z.literal("ambient"),
|
|
3223
|
+
agentCount: z.number(),
|
|
3224
|
+
results: z.array(
|
|
3225
|
+
z.object({
|
|
3226
|
+
agentName: z.string(),
|
|
3227
|
+
status: z.string()
|
|
3228
|
+
})
|
|
3229
|
+
)
|
|
3230
|
+
});
|
|
3231
|
+
var MentionResponseSchema = z.union([DirectedMentionResponseSchema, AmbientMentionResponseSchema]);
|
|
3232
|
+
var TavernQuestSchema = z.object({
|
|
3233
|
+
_id: z.string(),
|
|
3234
|
+
title: z.string(),
|
|
3235
|
+
description: z.string().optional(),
|
|
3236
|
+
status: z.string(),
|
|
3237
|
+
postedBy: z.string(),
|
|
3238
|
+
claimedBy: z.string().optional(),
|
|
3239
|
+
difficulty: z.string().optional(),
|
|
3240
|
+
createdAt: z.string().optional(),
|
|
3241
|
+
updatedAt: z.string().optional()
|
|
3242
|
+
});
|
|
3243
|
+
var QuestListResponseSchema = z.object({
|
|
3244
|
+
quests: z.array(TavernQuestSchema)
|
|
3245
|
+
});
|
|
3246
|
+
var CreateQuestRequestSchema = z.object({
|
|
3247
|
+
title: z.string(),
|
|
3248
|
+
description: z.string().optional(),
|
|
3249
|
+
agentId: z.string(),
|
|
3250
|
+
agentName: z.string(),
|
|
3251
|
+
difficulty: z.enum(["easy", "medium", "hard", "epic"]).optional()
|
|
3252
|
+
});
|
|
3253
|
+
var QuestResponseSchema = z.object({
|
|
3254
|
+
quest: TavernQuestSchema
|
|
3255
|
+
});
|
|
3256
|
+
var NotebookEntrySchema = z.object({
|
|
3257
|
+
_id: z.string(),
|
|
3258
|
+
title: z.string().optional(),
|
|
3259
|
+
content: z.string().optional(),
|
|
3260
|
+
createdAt: z.string().optional()
|
|
3261
|
+
});
|
|
3262
|
+
var NotebookResponseSchema = z.object({
|
|
3263
|
+
sessionId: z.string().nullable(),
|
|
3264
|
+
entries: z.array(NotebookEntrySchema)
|
|
3265
|
+
});
|
|
3266
|
+
var TimedGateSchema = z.object({
|
|
3267
|
+
gateId: z.string(),
|
|
3268
|
+
agentId: z.string(),
|
|
3269
|
+
agentName: z.string(),
|
|
3270
|
+
userId: z.string(),
|
|
3271
|
+
confidence: z.number(),
|
|
3272
|
+
reason: z.string(),
|
|
3273
|
+
createdAt: z.number(),
|
|
3274
|
+
expiresAt: z.number(),
|
|
3275
|
+
delayMs: z.number(),
|
|
3276
|
+
status: z.enum(["pending", "approved", "rejected", "expired", "auto_proceeded"]),
|
|
3277
|
+
resolvedBy: z.enum(["human", "timer"]).optional(),
|
|
3278
|
+
resolvedAt: z.number().optional(),
|
|
3279
|
+
burstId: z.string(),
|
|
3280
|
+
iteration: z.number()
|
|
3281
|
+
});
|
|
3282
|
+
var GateListResponseSchema = z.object({
|
|
3283
|
+
gates: z.array(TimedGateSchema)
|
|
3284
|
+
});
|
|
3285
|
+
var GateResolveRequestSchema = z.object({
|
|
3286
|
+
gateId: z.string(),
|
|
3287
|
+
resolution: z.enum(["approve", "reject"])
|
|
3288
|
+
});
|
|
3289
|
+
var GateResolveResponseSchema = z.object({
|
|
3290
|
+
success: z.boolean(),
|
|
3291
|
+
gate: TimedGateSchema
|
|
3292
|
+
});
|
|
3293
|
+
var HeartbeatToggleResponseSchema = z.object({
|
|
3294
|
+
success: z.boolean(),
|
|
3295
|
+
enabled: z.boolean(),
|
|
3296
|
+
agentCount: z.number()
|
|
3297
|
+
});
|
|
3298
|
+
var TriggerHeartbeatResponseSchema = z.object({
|
|
3299
|
+
triggered: z.number(),
|
|
3300
|
+
results: z.array(
|
|
3301
|
+
z.object({
|
|
3302
|
+
agentId: z.string(),
|
|
3303
|
+
agentName: z.string(),
|
|
3304
|
+
status: z.string(),
|
|
3305
|
+
error: z.string().optional()
|
|
3306
|
+
})
|
|
3307
|
+
)
|
|
3308
|
+
});
|
|
3309
|
+
|
|
3310
|
+
// src/features/tavern/TavernActivityStream.ts
|
|
3311
|
+
var TavernActivityStream = class {
|
|
3312
|
+
constructor(onLogEntry) {
|
|
3313
|
+
this.onLogEntry = onLogEntry;
|
|
3314
|
+
this.wsManager = null;
|
|
3315
|
+
}
|
|
3316
|
+
/** Register the WS handler for tavern_heartbeat_log events */
|
|
3317
|
+
registerHandlers(wsManager) {
|
|
3318
|
+
this.dispose();
|
|
3319
|
+
this.wsManager = wsManager;
|
|
3320
|
+
wsManager.onAction("tavern_heartbeat_log", (message) => {
|
|
3321
|
+
const parsed = message;
|
|
3322
|
+
if (!parsed.entry) return;
|
|
3323
|
+
const result = HeartbeatLogEntrySchema.safeParse(parsed.entry);
|
|
3324
|
+
if (result.success) {
|
|
3325
|
+
this.onLogEntry(result.data);
|
|
3326
|
+
}
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3329
|
+
/** Unsubscribe from WS events */
|
|
3330
|
+
dispose() {
|
|
3331
|
+
if (this.wsManager) {
|
|
3332
|
+
this.wsManager.offAction("tavern_heartbeat_log");
|
|
3333
|
+
this.wsManager = null;
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
};
|
|
3337
|
+
|
|
3338
|
+
// src/features/tavern/tavernTools.ts
|
|
3339
|
+
function createTavernTools(service) {
|
|
3340
|
+
return [
|
|
3341
|
+
createListAgentsTool(service),
|
|
3342
|
+
createCreateAgentTool(service),
|
|
3343
|
+
createEditAgentTool(service),
|
|
3344
|
+
createDeleteAgentTool(service),
|
|
3345
|
+
createMentionTool(service),
|
|
3346
|
+
createListQuestsTool(service),
|
|
3347
|
+
createPostQuestTool(service),
|
|
3348
|
+
createDeleteQuestTool(service),
|
|
3349
|
+
createReadNotebookTool(service),
|
|
3350
|
+
createListGatesTool(service),
|
|
3351
|
+
createResolveGateTool(service),
|
|
3352
|
+
createToggleHeartbeatsTool(service),
|
|
3353
|
+
createTriggerHeartbeatTool(service),
|
|
3354
|
+
createAbortHeartbeatsTool(service),
|
|
3355
|
+
createStatusTool(service)
|
|
3356
|
+
];
|
|
3357
|
+
}
|
|
3358
|
+
function createListAgentsTool(service) {
|
|
3359
|
+
return {
|
|
3360
|
+
toolSchema: {
|
|
3361
|
+
name: "tavern_list_agents",
|
|
3362
|
+
description: "List all Tavern agents with their IDs, names, descriptions, and heartbeat status. Use this FIRST to discover agent IDs before using tools that require an agent_id (like tavern_read_notebook or tavern_post_quest).",
|
|
3363
|
+
parameters: {
|
|
3364
|
+
type: "object",
|
|
3365
|
+
properties: {}
|
|
3366
|
+
}
|
|
3367
|
+
},
|
|
3368
|
+
toolFn: async () => {
|
|
3369
|
+
const result = await service.listAgents();
|
|
3370
|
+
return JSON.stringify(result);
|
|
3371
|
+
}
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
function createCreateAgentTool(service) {
|
|
3375
|
+
return {
|
|
3376
|
+
toolSchema: {
|
|
3377
|
+
name: "tavern_create_agent",
|
|
3378
|
+
description: "Create a new Tavern agent with a personality. The agent will be created without heartbeats enabled \u2014 use tavern_toggle_heartbeats after creation to activate autonomous behavior. Personality fields shape how the agent thinks and acts during heartbeats.",
|
|
3379
|
+
parameters: {
|
|
3380
|
+
type: "object",
|
|
3381
|
+
properties: {
|
|
3382
|
+
name: {
|
|
3383
|
+
type: "string",
|
|
3384
|
+
description: 'The agent name (e.g. "Spock", "Luna", "Chef Gordon")'
|
|
3385
|
+
},
|
|
3386
|
+
description: {
|
|
3387
|
+
type: "string",
|
|
3388
|
+
description: "A short description of the agent"
|
|
3389
|
+
},
|
|
3390
|
+
system_prompt: {
|
|
3391
|
+
type: "string",
|
|
3392
|
+
description: "System prompt that defines the agent's core behavior and knowledge"
|
|
3393
|
+
},
|
|
3394
|
+
major_motivation: {
|
|
3395
|
+
type: "string",
|
|
3396
|
+
description: 'What primarily drives this agent (e.g. "Exploring the unknown")'
|
|
3397
|
+
},
|
|
3398
|
+
minor_motivation: {
|
|
3399
|
+
type: "string",
|
|
3400
|
+
description: 'Secondary drive (e.g. "Collecting rare artifacts")'
|
|
3401
|
+
},
|
|
3402
|
+
flaw: {
|
|
3403
|
+
type: "string",
|
|
3404
|
+
description: 'A character flaw that creates interesting behavior (e.g. "Overthinks simple problems")'
|
|
3405
|
+
},
|
|
3406
|
+
quirk: {
|
|
3407
|
+
type: "string",
|
|
3408
|
+
description: 'A distinctive behavioral quirk (e.g. "Speaks in nautical metaphors")'
|
|
3409
|
+
},
|
|
3410
|
+
personality_description: {
|
|
3411
|
+
type: "string",
|
|
3412
|
+
description: "Overall personality summary"
|
|
3413
|
+
},
|
|
3414
|
+
personal_mission: {
|
|
3415
|
+
type: "string",
|
|
3416
|
+
description: `The agent's purpose in the tavern (e.g. "Map every corner of the digital realm")`
|
|
3417
|
+
},
|
|
3418
|
+
active_project: {
|
|
3419
|
+
type: "string",
|
|
3420
|
+
description: "What the agent is currently working on"
|
|
3421
|
+
},
|
|
3422
|
+
communication_pattern: {
|
|
3423
|
+
type: "string",
|
|
3424
|
+
description: 'How the agent communicates (e.g. "Formal and precise", "Casual and witty")'
|
|
3425
|
+
},
|
|
3426
|
+
humor_style: {
|
|
3427
|
+
type: "string",
|
|
3428
|
+
description: `The agent's sense of humor (e.g. "Dry wit", "Puns and wordplay")`
|
|
3429
|
+
},
|
|
3430
|
+
backstory_element: {
|
|
3431
|
+
type: "string",
|
|
3432
|
+
description: "A backstory detail that influences behavior"
|
|
3433
|
+
},
|
|
3434
|
+
energy_level: {
|
|
3435
|
+
type: "string",
|
|
3436
|
+
description: 'Default energy level (e.g. "High energy morning person", "Calm and measured")'
|
|
3437
|
+
},
|
|
3438
|
+
core_values: {
|
|
3439
|
+
type: "string",
|
|
3440
|
+
description: 'What the agent values most (e.g. "Truth and transparency")'
|
|
3441
|
+
}
|
|
3442
|
+
},
|
|
3443
|
+
required: ["name"]
|
|
3444
|
+
}
|
|
3445
|
+
},
|
|
3446
|
+
toolFn: async (params) => {
|
|
3447
|
+
const raw = params;
|
|
3448
|
+
const request = CreateAgentRequestSchema.parse({
|
|
3449
|
+
name: raw.name,
|
|
3450
|
+
description: raw.description,
|
|
3451
|
+
systemPrompt: raw.system_prompt,
|
|
3452
|
+
personality: {
|
|
3453
|
+
majorMotivation: raw.major_motivation,
|
|
3454
|
+
minorMotivation: raw.minor_motivation,
|
|
3455
|
+
flaw: raw.flaw,
|
|
3456
|
+
quirk: raw.quirk,
|
|
3457
|
+
description: raw.personality_description,
|
|
3458
|
+
personalMission: raw.personal_mission,
|
|
3459
|
+
activeProject: raw.active_project,
|
|
3460
|
+
communicationPattern: raw.communication_pattern,
|
|
3461
|
+
humorStyle: raw.humor_style,
|
|
3462
|
+
backstoryElement: raw.backstory_element,
|
|
3463
|
+
energyLevel: raw.energy_level,
|
|
3464
|
+
coreValues: raw.core_values
|
|
3465
|
+
}
|
|
3466
|
+
});
|
|
3467
|
+
const result = await service.createAgent(request);
|
|
3468
|
+
return JSON.stringify(result);
|
|
3469
|
+
}
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
function createEditAgentTool(service) {
|
|
3473
|
+
return {
|
|
3474
|
+
toolSchema: {
|
|
3475
|
+
name: "tavern_edit_agent",
|
|
3476
|
+
description: "Update an existing Tavern agent. Can change personality, system prompt, heartbeat config, or any other field. Use this to enable/disable heartbeats for a SINGLE agent (set heartbeat_enabled), or to update personality traits. Only provide fields you want to change \u2014 unspecified fields remain unchanged.",
|
|
3477
|
+
parameters: {
|
|
3478
|
+
type: "object",
|
|
3479
|
+
properties: {
|
|
3480
|
+
agent_id: {
|
|
3481
|
+
type: "string",
|
|
3482
|
+
description: "The MongoDB ObjectId of the agent (get from tavern_list_agents)"
|
|
3483
|
+
},
|
|
3484
|
+
name: { type: "string", description: "New agent name" },
|
|
3485
|
+
description: { type: "string", description: "New description" },
|
|
3486
|
+
system_prompt: { type: "string", description: "New system prompt" },
|
|
3487
|
+
heartbeat_enabled: {
|
|
3488
|
+
type: "boolean",
|
|
3489
|
+
description: "Enable or disable heartbeats for THIS specific agent"
|
|
3490
|
+
},
|
|
3491
|
+
heartbeat_interval_minutes: {
|
|
3492
|
+
type: "number",
|
|
3493
|
+
description: "Heartbeat interval in minutes (default: 3)"
|
|
3494
|
+
},
|
|
3495
|
+
major_motivation: { type: "string", description: "What primarily drives this agent" },
|
|
3496
|
+
minor_motivation: { type: "string", description: "Secondary drive" },
|
|
3497
|
+
flaw: { type: "string", description: "Character flaw" },
|
|
3498
|
+
quirk: { type: "string", description: "Distinctive quirk" },
|
|
3499
|
+
personal_mission: { type: "string", description: "Agent's purpose in the tavern" },
|
|
3500
|
+
active_project: { type: "string", description: "What the agent is currently working on" },
|
|
3501
|
+
communication_pattern: { type: "string", description: "How the agent communicates" },
|
|
3502
|
+
humor_style: { type: "string", description: "Agent's sense of humor" }
|
|
3503
|
+
},
|
|
3504
|
+
required: ["agent_id"]
|
|
3505
|
+
}
|
|
3506
|
+
},
|
|
3507
|
+
toolFn: async (params) => {
|
|
3508
|
+
const raw = params;
|
|
3509
|
+
const agentId = raw.agent_id;
|
|
3510
|
+
const payload = {};
|
|
3511
|
+
if (raw.name !== void 0) payload.name = raw.name;
|
|
3512
|
+
if (raw.description !== void 0) payload.description = raw.description;
|
|
3513
|
+
if (raw.system_prompt !== void 0) payload.systemPrompt = raw.system_prompt;
|
|
3514
|
+
if (raw.heartbeat_enabled !== void 0 || raw.heartbeat_interval_minutes !== void 0) {
|
|
3515
|
+
const hb = {};
|
|
3516
|
+
if (raw.heartbeat_enabled !== void 0) hb.enabled = raw.heartbeat_enabled;
|
|
3517
|
+
if (raw.heartbeat_interval_minutes !== void 0) hb.intervalMinutes = raw.heartbeat_interval_minutes;
|
|
3518
|
+
payload.heartbeatConfig = hb;
|
|
3519
|
+
}
|
|
3520
|
+
const personality = {};
|
|
3521
|
+
if (raw.major_motivation !== void 0) personality.majorMotivation = raw.major_motivation;
|
|
3522
|
+
if (raw.minor_motivation !== void 0) personality.minorMotivation = raw.minor_motivation;
|
|
3523
|
+
if (raw.flaw !== void 0) personality.flaw = raw.flaw;
|
|
3524
|
+
if (raw.quirk !== void 0) personality.quirk = raw.quirk;
|
|
3525
|
+
if (raw.personal_mission !== void 0) personality.personalMission = raw.personal_mission;
|
|
3526
|
+
if (raw.active_project !== void 0) personality.activeProject = raw.active_project;
|
|
3527
|
+
if (raw.communication_pattern !== void 0) personality.communicationPattern = raw.communication_pattern;
|
|
3528
|
+
if (raw.humor_style !== void 0) personality.humorStyle = raw.humor_style;
|
|
3529
|
+
if (Object.keys(personality).length > 0) payload.personality = personality;
|
|
3530
|
+
const request = UpdateAgentRequestSchema.parse(payload);
|
|
3531
|
+
const result = await service.updateAgent(agentId, request);
|
|
3532
|
+
return JSON.stringify(result);
|
|
3533
|
+
}
|
|
3534
|
+
};
|
|
3535
|
+
}
|
|
3536
|
+
function createDeleteAgentTool(service) {
|
|
3537
|
+
return {
|
|
3538
|
+
toolSchema: {
|
|
3539
|
+
name: "tavern_delete_agent",
|
|
3540
|
+
description: "Permanently delete a Tavern agent. This is irreversible. IMPORTANT: agent_id must be a MongoDB ObjectId from tavern_list_agents.",
|
|
3541
|
+
parameters: {
|
|
3542
|
+
type: "object",
|
|
3543
|
+
properties: {
|
|
3544
|
+
agent_id: {
|
|
3545
|
+
type: "string",
|
|
3546
|
+
description: "The MongoDB ObjectId of the agent to delete"
|
|
3547
|
+
}
|
|
3548
|
+
},
|
|
3549
|
+
required: ["agent_id"]
|
|
3550
|
+
}
|
|
3551
|
+
},
|
|
3552
|
+
toolFn: async (params) => {
|
|
3553
|
+
const { agent_id } = params;
|
|
3554
|
+
await service.deleteAgent(agent_id);
|
|
3555
|
+
return JSON.stringify({ success: true, message: `Agent ${agent_id} deleted` });
|
|
3556
|
+
}
|
|
3557
|
+
};
|
|
3558
|
+
}
|
|
3559
|
+
function createMentionTool(service) {
|
|
3560
|
+
return {
|
|
3561
|
+
toolSchema: {
|
|
3562
|
+
name: "tavern_mention",
|
|
3563
|
+
description: "Send a message to a specific Tavern agent by name, or broadcast an ambient message to all agents if no agent_name is provided. Use this to talk to agents, ask them questions, give them instructions, or announce something to the whole tavern.",
|
|
3564
|
+
parameters: {
|
|
3565
|
+
type: "object",
|
|
3566
|
+
properties: {
|
|
3567
|
+
agent_name: {
|
|
3568
|
+
type: "string",
|
|
3569
|
+
description: "Name of the agent to mention (omit for ambient broadcast to all agents)"
|
|
3570
|
+
},
|
|
3571
|
+
message: {
|
|
3572
|
+
type: "string",
|
|
3573
|
+
description: "The message to send to the agent(s)"
|
|
3574
|
+
}
|
|
3575
|
+
},
|
|
3576
|
+
required: ["message"]
|
|
3577
|
+
}
|
|
3578
|
+
},
|
|
3579
|
+
toolFn: async (params) => {
|
|
3580
|
+
const { agent_name, message } = params;
|
|
3581
|
+
const result = await service.mentionAgent(agent_name, message);
|
|
3582
|
+
return JSON.stringify(result);
|
|
3583
|
+
}
|
|
3584
|
+
};
|
|
3585
|
+
}
|
|
3586
|
+
function createListQuestsTool(service) {
|
|
3587
|
+
return {
|
|
3588
|
+
toolSchema: {
|
|
3589
|
+
name: "tavern_list_quests",
|
|
3590
|
+
description: "List all quests on the Tavern quest board. Shows quest title, status, who posted it, and who claimed it.",
|
|
3591
|
+
parameters: {
|
|
3592
|
+
type: "object",
|
|
3593
|
+
properties: {}
|
|
3594
|
+
}
|
|
3595
|
+
},
|
|
3596
|
+
toolFn: async () => {
|
|
3597
|
+
const result = await service.listQuests();
|
|
3598
|
+
return JSON.stringify(result);
|
|
3599
|
+
}
|
|
3600
|
+
};
|
|
3601
|
+
}
|
|
3602
|
+
function createPostQuestTool(service) {
|
|
3603
|
+
return {
|
|
3604
|
+
toolSchema: {
|
|
3605
|
+
name: "tavern_post_quest",
|
|
3606
|
+
description: "Post a new quest to the Tavern quest board for agents to discover and claim.",
|
|
3607
|
+
parameters: {
|
|
3608
|
+
type: "object",
|
|
3609
|
+
properties: {
|
|
3610
|
+
title: {
|
|
3611
|
+
type: "string",
|
|
3612
|
+
description: "Quest title"
|
|
3613
|
+
},
|
|
3614
|
+
description: {
|
|
3615
|
+
type: "string",
|
|
3616
|
+
description: "Detailed quest description"
|
|
3617
|
+
},
|
|
3618
|
+
agent_id: {
|
|
3619
|
+
type: "string",
|
|
3620
|
+
description: "ID of the agent posting the quest"
|
|
3621
|
+
},
|
|
3622
|
+
agent_name: {
|
|
3623
|
+
type: "string",
|
|
3624
|
+
description: "Name of the agent posting the quest"
|
|
3625
|
+
},
|
|
3626
|
+
difficulty: {
|
|
3627
|
+
type: "string",
|
|
3628
|
+
description: "Quest difficulty level",
|
|
3629
|
+
enum: ["easy", "medium", "hard", "epic"]
|
|
3630
|
+
}
|
|
3631
|
+
},
|
|
3632
|
+
required: ["title", "agent_id", "agent_name"]
|
|
3633
|
+
}
|
|
3634
|
+
},
|
|
3635
|
+
toolFn: async (params) => {
|
|
3636
|
+
const raw = params;
|
|
3637
|
+
const request = CreateQuestRequestSchema.parse({
|
|
3638
|
+
title: raw.title,
|
|
3639
|
+
description: raw.description,
|
|
3640
|
+
agentId: raw.agent_id,
|
|
3641
|
+
agentName: raw.agent_name,
|
|
3642
|
+
difficulty: raw.difficulty
|
|
3643
|
+
});
|
|
3644
|
+
const result = await service.postQuest(request);
|
|
3645
|
+
return JSON.stringify(result);
|
|
3646
|
+
}
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3649
|
+
function createDeleteQuestTool(service) {
|
|
3650
|
+
return {
|
|
3651
|
+
toolSchema: {
|
|
3652
|
+
name: "tavern_delete_quest",
|
|
3653
|
+
description: "Remove a quest from the Tavern quest board by its ID.",
|
|
3654
|
+
parameters: {
|
|
3655
|
+
type: "object",
|
|
3656
|
+
properties: {
|
|
3657
|
+
quest_id: {
|
|
3658
|
+
type: "string",
|
|
3659
|
+
description: "The ID of the quest to delete"
|
|
3660
|
+
}
|
|
3661
|
+
},
|
|
3662
|
+
required: ["quest_id"]
|
|
3663
|
+
}
|
|
3664
|
+
},
|
|
3665
|
+
toolFn: async (params) => {
|
|
3666
|
+
const { quest_id } = params;
|
|
3667
|
+
await service.deleteQuest(quest_id);
|
|
3668
|
+
return JSON.stringify({ success: true });
|
|
3669
|
+
}
|
|
3670
|
+
};
|
|
3671
|
+
}
|
|
3672
|
+
function createReadNotebookTool(service) {
|
|
3673
|
+
return {
|
|
3674
|
+
toolSchema: {
|
|
3675
|
+
name: "tavern_read_notebook",
|
|
3676
|
+
description: `Read a Tavern agent's activity notebook/history. Shows their recent actions, thoughts, conversations, and quest progress. IMPORTANT: agent_id must be a MongoDB ObjectId (e.g. "6540b58d1f703ade3ea1e82b"), NOT the agent name. Use tavern_list_agents first to get the correct ID.`,
|
|
3677
|
+
parameters: {
|
|
3678
|
+
type: "object",
|
|
3679
|
+
properties: {
|
|
3680
|
+
agent_id: {
|
|
3681
|
+
type: "string",
|
|
3682
|
+
description: "The MongoDB ObjectId of the agent (get this from tavern_list_agents, NOT the agent name)"
|
|
3683
|
+
},
|
|
3684
|
+
limit: {
|
|
3685
|
+
type: "number",
|
|
3686
|
+
description: "Maximum number of entries to return (default: 50)"
|
|
3687
|
+
}
|
|
3688
|
+
},
|
|
3689
|
+
required: ["agent_id"]
|
|
3690
|
+
}
|
|
3691
|
+
},
|
|
3692
|
+
toolFn: async (params) => {
|
|
3693
|
+
const { agent_id, limit } = params;
|
|
3694
|
+
const result = await service.getAgentNotebook(agent_id, limit);
|
|
3695
|
+
return JSON.stringify(result);
|
|
3696
|
+
}
|
|
3697
|
+
};
|
|
3698
|
+
}
|
|
3699
|
+
function createListGatesTool(service) {
|
|
3700
|
+
return {
|
|
3701
|
+
toolSchema: {
|
|
3702
|
+
name: "tavern_list_gates",
|
|
3703
|
+
description: "List all pending confidence gates in the Tavern. Gates are pause points where agents need human approval to proceed with low-confidence actions.",
|
|
3704
|
+
parameters: {
|
|
3705
|
+
type: "object",
|
|
3706
|
+
properties: {}
|
|
3707
|
+
}
|
|
3708
|
+
},
|
|
3709
|
+
toolFn: async () => {
|
|
3710
|
+
const result = await service.listGates();
|
|
3711
|
+
return JSON.stringify(result);
|
|
3712
|
+
}
|
|
3713
|
+
};
|
|
3714
|
+
}
|
|
3715
|
+
function createResolveGateTool(service) {
|
|
3716
|
+
return {
|
|
3717
|
+
toolSchema: {
|
|
3718
|
+
name: "tavern_resolve_gate",
|
|
3719
|
+
description: "Approve or reject a pending confidence gate. This lets an agent proceed or stops its current action.",
|
|
3720
|
+
parameters: {
|
|
3721
|
+
type: "object",
|
|
3722
|
+
properties: {
|
|
3723
|
+
gate_id: {
|
|
3724
|
+
type: "string",
|
|
3725
|
+
description: "The ID of the gate to resolve"
|
|
3726
|
+
},
|
|
3727
|
+
resolution: {
|
|
3728
|
+
type: "string",
|
|
3729
|
+
description: "Whether to approve or reject the gate",
|
|
3730
|
+
enum: ["approve", "reject"]
|
|
3731
|
+
}
|
|
3732
|
+
},
|
|
3733
|
+
required: ["gate_id", "resolution"]
|
|
3734
|
+
}
|
|
3735
|
+
},
|
|
3736
|
+
toolFn: async (params) => {
|
|
3737
|
+
const { gate_id, resolution } = params;
|
|
3738
|
+
const result = await service.resolveGate(gate_id, resolution);
|
|
3739
|
+
return JSON.stringify(result);
|
|
3740
|
+
}
|
|
3741
|
+
};
|
|
3742
|
+
}
|
|
3743
|
+
function createToggleHeartbeatsTool(service) {
|
|
3744
|
+
return {
|
|
3745
|
+
toolSchema: {
|
|
3746
|
+
name: "tavern_toggle_heartbeats",
|
|
3747
|
+
description: "Enable or disable background heartbeats for all Tavern agents. When enabled, agents autonomously think, act, and interact on a schedule.",
|
|
3748
|
+
parameters: {
|
|
3749
|
+
type: "object",
|
|
3750
|
+
properties: {
|
|
3751
|
+
enabled: {
|
|
3752
|
+
type: "boolean",
|
|
3753
|
+
description: "true to enable heartbeats, false to disable"
|
|
3754
|
+
}
|
|
3755
|
+
},
|
|
3756
|
+
required: ["enabled"]
|
|
3757
|
+
}
|
|
3758
|
+
},
|
|
3759
|
+
toolFn: async (params) => {
|
|
3760
|
+
const { enabled } = params;
|
|
3761
|
+
const result = await service.toggleHeartbeats(enabled);
|
|
3762
|
+
return JSON.stringify(result);
|
|
3763
|
+
}
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
function createTriggerHeartbeatTool(service) {
|
|
3767
|
+
return {
|
|
3768
|
+
toolSchema: {
|
|
3769
|
+
name: "tavern_trigger_heartbeat",
|
|
3770
|
+
description: "Manually trigger a heartbeat cycle for all Tavern agents. Useful for testing or forcing immediate agent activity.",
|
|
3771
|
+
parameters: {
|
|
3772
|
+
type: "object",
|
|
3773
|
+
properties: {
|
|
3774
|
+
config: {
|
|
3775
|
+
type: "object",
|
|
3776
|
+
description: 'Optional configuration overrides for the heartbeat. Known keys: preferredModelId (string \u2014 model ID to use), costMode ("low" | "normal" | "high")',
|
|
3777
|
+
additionalProperties: true
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
},
|
|
3782
|
+
toolFn: async (params) => {
|
|
3783
|
+
const { config } = params ?? {};
|
|
3784
|
+
const result = await service.triggerHeartbeat(config);
|
|
3785
|
+
return JSON.stringify(result);
|
|
3786
|
+
}
|
|
3787
|
+
};
|
|
3788
|
+
}
|
|
3789
|
+
function createAbortHeartbeatsTool(service) {
|
|
3790
|
+
return {
|
|
3791
|
+
toolSchema: {
|
|
3792
|
+
name: "tavern_abort_heartbeats",
|
|
3793
|
+
description: "Emergency stop \u2014 abort all in-flight Tavern agent heartbeats immediately.",
|
|
3794
|
+
parameters: {
|
|
3795
|
+
type: "object",
|
|
3796
|
+
properties: {}
|
|
3797
|
+
}
|
|
3798
|
+
},
|
|
3799
|
+
toolFn: async () => {
|
|
3800
|
+
await service.abortHeartbeats();
|
|
3801
|
+
return JSON.stringify({ success: true, message: "All in-flight heartbeats aborted" });
|
|
3802
|
+
}
|
|
3803
|
+
};
|
|
3804
|
+
}
|
|
3805
|
+
function createStatusTool(service) {
|
|
3806
|
+
return {
|
|
3807
|
+
toolSchema: {
|
|
3808
|
+
name: "tavern_status",
|
|
3809
|
+
description: "Get a quick overview of the Tavern: agent count, heartbeat status, active quests, and pending gates. Use this for situational awareness before taking action.",
|
|
3810
|
+
parameters: {
|
|
3811
|
+
type: "object",
|
|
3812
|
+
properties: {}
|
|
3813
|
+
}
|
|
3814
|
+
},
|
|
3815
|
+
toolFn: async () => {
|
|
3816
|
+
const [agents, quests, gates] = await Promise.all([
|
|
3817
|
+
service.listAgents(),
|
|
3818
|
+
service.listQuests(),
|
|
3819
|
+
service.listGates()
|
|
3820
|
+
]);
|
|
3821
|
+
const agentList = agents.data ?? [];
|
|
3822
|
+
const heartbeatEnabled = agentList.filter((a) => a.heartbeatConfig?.enabled);
|
|
3823
|
+
return JSON.stringify({
|
|
3824
|
+
agents: {
|
|
3825
|
+
total: agentList.length,
|
|
3826
|
+
withHeartbeats: heartbeatEnabled.length,
|
|
3827
|
+
names: agentList.map((a) => ({ name: a.name, heartbeat: a.heartbeatConfig?.enabled ?? false }))
|
|
3828
|
+
},
|
|
3829
|
+
quests: {
|
|
3830
|
+
total: quests.quests.length,
|
|
3831
|
+
byStatus: quests.quests.reduce(
|
|
3832
|
+
(acc, q) => {
|
|
3833
|
+
acc[q.status] = (acc[q.status] ?? 0) + 1;
|
|
3834
|
+
return acc;
|
|
3835
|
+
},
|
|
3836
|
+
{}
|
|
3837
|
+
)
|
|
3838
|
+
},
|
|
3839
|
+
gates: {
|
|
3840
|
+
pending: gates.gates.length
|
|
3841
|
+
}
|
|
3842
|
+
});
|
|
3843
|
+
}
|
|
3844
|
+
};
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3847
|
+
// src/features/tavern/TavernModule.ts
|
|
3848
|
+
var ACTION_ICONS = {
|
|
3849
|
+
speech: "\u{1F4AC}",
|
|
3850
|
+
thought: "\u{1F4AD}",
|
|
3851
|
+
memory: "\u{1F9E0}",
|
|
3852
|
+
move: "\u{1F6B6}",
|
|
3853
|
+
reply: "\u{1F4E9}",
|
|
3854
|
+
post_quest: "\u{1F4DC}",
|
|
3855
|
+
claim_quest: "\u2694\uFE0F",
|
|
3856
|
+
complete_quest: "\u2705",
|
|
3857
|
+
tool_use: "\u{1F527}",
|
|
3858
|
+
email: "\u{1F4E7}",
|
|
3859
|
+
gate_paused: "\u23F8\uFE0F",
|
|
3860
|
+
gate_timed: "\u23F3",
|
|
3861
|
+
gate_proceed: "\u25B6\uFE0F",
|
|
3862
|
+
idle: "\u{1F4A4}",
|
|
3863
|
+
intent: "\u{1F3AF}",
|
|
3864
|
+
report: "\u{1F4CB}",
|
|
3865
|
+
credits: "\u{1FA99}",
|
|
3866
|
+
move_decoration: "\u{1F3A8}",
|
|
3867
|
+
yolo_override: "\u26A1"
|
|
3868
|
+
};
|
|
3869
|
+
var TavernModule = class {
|
|
3870
|
+
constructor(apiClient, onLogEntry, getActivityLog) {
|
|
3871
|
+
this.name = "tavern";
|
|
3872
|
+
this.description = "Interact with autonomous AI agents in the B4M Tavern";
|
|
3873
|
+
this.service = new TavernService(apiClient);
|
|
3874
|
+
this.activityStream = new TavernActivityStream(onLogEntry);
|
|
3875
|
+
this.getActivityLog = getActivityLog;
|
|
3876
|
+
}
|
|
3877
|
+
getTools() {
|
|
3878
|
+
return createTavernTools(this.service);
|
|
3879
|
+
}
|
|
3880
|
+
getSystemPromptSection() {
|
|
3881
|
+
return `## Tavern Integration
|
|
3882
|
+
You can interact with autonomous AI agents in the B4M Tavern using tavern_* tools.
|
|
3883
|
+
|
|
3884
|
+
IMPORTANT: Many tools require agent IDs (MongoDB ObjectIds like "6540b58d1f703ade3ea1e82b"). Always use tavern_list_agents FIRST to discover agent names and their IDs before using tools that need an agent_id.
|
|
3885
|
+
|
|
3886
|
+
Available actions:
|
|
3887
|
+
- **tavern_list_agents**: List all agents with their IDs, names, and status \u2014 USE THIS FIRST
|
|
3888
|
+
- **tavern_create_agent**: Create a new agent with a personality (heartbeats disabled by default)
|
|
3889
|
+
- **tavern_edit_agent**: Update an agent's personality, system prompt, or heartbeat config (per-agent toggle)
|
|
3890
|
+
- **tavern_delete_agent**: Permanently delete an agent
|
|
3891
|
+
- **tavern_mention**: Talk to a specific agent by name or broadcast to all agents
|
|
3892
|
+
- **tavern_list_quests**: View the quest board
|
|
3893
|
+
- **tavern_post_quest**: Post a new quest for agents to claim
|
|
3894
|
+
- **tavern_delete_quest**: Remove a quest from the board
|
|
3895
|
+
- **tavern_read_notebook**: Read an agent's activity history (requires agent ID from tavern_list_agents)
|
|
3896
|
+
- **tavern_list_gates**: See pending confidence gates awaiting human approval
|
|
3897
|
+
- **tavern_resolve_gate**: Approve or reject a confidence gate
|
|
3898
|
+
- **tavern_toggle_heartbeats**: Enable/disable agent background heartbeats
|
|
3899
|
+
- **tavern_trigger_heartbeat**: Manually trigger a heartbeat cycle
|
|
3900
|
+
- **tavern_abort_heartbeats**: Emergency stop all in-flight heartbeats
|
|
3901
|
+
- **tavern_status**: Quick overview of agents, quests, and gates \u2014 good for situational awareness
|
|
3902
|
+
|
|
3903
|
+
When the user mentions talking to agents, checking the quest board, or managing the tavern, use these tools.
|
|
3904
|
+
Agents have personalities, moods, quests, and memories \u2014 they are autonomous entities, not chatbots.`;
|
|
3905
|
+
}
|
|
3906
|
+
getCommands() {
|
|
3907
|
+
return [
|
|
3908
|
+
{
|
|
3909
|
+
name: "tavern",
|
|
3910
|
+
description: "Show recent Tavern agent activity stream",
|
|
3911
|
+
execute: () => {
|
|
3912
|
+
const activityLog = this.getActivityLog();
|
|
3913
|
+
if (activityLog.length === 0) {
|
|
3914
|
+
console.log("\nTavern Activity: No activity yet.");
|
|
3915
|
+
console.log(" Agents broadcast activity during heartbeats.");
|
|
3916
|
+
console.log(' Try: "trigger a heartbeat cycle" to generate activity.\n');
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3919
|
+
const recentEntries = activityLog.slice(-20);
|
|
3920
|
+
console.log(`
|
|
3921
|
+
Tavern Activity (last ${recentEntries.length} of ${activityLog.length} entries):
|
|
3922
|
+
`);
|
|
3923
|
+
for (const entry of recentEntries) {
|
|
3924
|
+
const time = new Date(entry.timestamp).toLocaleTimeString();
|
|
3925
|
+
const icon = ACTION_ICONS[entry.action] ?? "\xB7";
|
|
3926
|
+
const target = entry.targetAgentName ? ` \u2192 ${entry.targetAgentName}` : "";
|
|
3927
|
+
const text = entry.text ? `: ${entry.text.slice(0, 120)}${entry.text.length > 120 ? "..." : ""}` : "";
|
|
3928
|
+
console.log(` ${time} ${icon} ${entry.agentName}${target} [${entry.action}]${text}`);
|
|
3929
|
+
}
|
|
3930
|
+
console.log("");
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
];
|
|
3934
|
+
}
|
|
3935
|
+
registerWsHandlers(wsManager) {
|
|
3936
|
+
this.activityStream.registerHandlers(wsManager);
|
|
3937
|
+
}
|
|
3938
|
+
dispose() {
|
|
3939
|
+
this.activityStream.dispose();
|
|
3940
|
+
}
|
|
3941
|
+
};
|
|
3942
|
+
|
|
2985
3943
|
// src/index.tsx
|
|
2986
3944
|
process.removeAllListeners("warning");
|
|
2987
3945
|
process.on("warning", (warning) => {
|
|
@@ -3030,7 +3988,8 @@ function CliApp() {
|
|
|
3030
3988
|
sandboxOrchestrator: null,
|
|
3031
3989
|
wsManager: null,
|
|
3032
3990
|
checkpointStore: null,
|
|
3033
|
-
additionalDirectories: []
|
|
3991
|
+
additionalDirectories: [],
|
|
3992
|
+
featureRegistry: null
|
|
3034
3993
|
});
|
|
3035
3994
|
const [isInitialized, setIsInitialized] = useState12(false);
|
|
3036
3995
|
const [initError, setInitError] = useState12(null);
|
|
@@ -3060,6 +4019,9 @@ function CliApp() {
|
|
|
3060
4019
|
})
|
|
3061
4020
|
);
|
|
3062
4021
|
}
|
|
4022
|
+
if (state.featureRegistry) {
|
|
4023
|
+
state.featureRegistry.disposeAll();
|
|
4024
|
+
}
|
|
3063
4025
|
if (state.wsManager) {
|
|
3064
4026
|
state.wsManager.disconnect();
|
|
3065
4027
|
setWebSocketToolExecutor(null);
|
|
@@ -3082,7 +4044,15 @@ function CliApp() {
|
|
|
3082
4044
|
setTimeout(() => {
|
|
3083
4045
|
process.exit(0);
|
|
3084
4046
|
}, 100);
|
|
3085
|
-
}, [
|
|
4047
|
+
}, [
|
|
4048
|
+
state.session,
|
|
4049
|
+
state.sessionStore,
|
|
4050
|
+
state.mcpManager,
|
|
4051
|
+
state.agent,
|
|
4052
|
+
state.imageStore,
|
|
4053
|
+
state.wsManager,
|
|
4054
|
+
state.featureRegistry
|
|
4055
|
+
]);
|
|
3086
4056
|
useInput10((input, key) => {
|
|
3087
4057
|
if (key.escape) {
|
|
3088
4058
|
const store = useCliStore.getState();
|
|
@@ -3549,6 +4519,23 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3549
4519
|
}) : null;
|
|
3550
4520
|
const findDefinitionTool = createFindDefinitionTool();
|
|
3551
4521
|
const getFileStructureTool = createGetFileStructureTool();
|
|
4522
|
+
const featureRegistry = new FeatureModuleRegistry();
|
|
4523
|
+
if (config.features?.tavern) {
|
|
4524
|
+
featureRegistry.register(
|
|
4525
|
+
new TavernModule(
|
|
4526
|
+
apiClient,
|
|
4527
|
+
(entry) => useCliStore.getState().addTavernLogEntry(entry),
|
|
4528
|
+
() => useCliStore.getState().tavernActivityLog
|
|
4529
|
+
)
|
|
4530
|
+
);
|
|
4531
|
+
}
|
|
4532
|
+
const featureModuleToolNames = featureRegistry.getAllToolNames();
|
|
4533
|
+
if (featureModuleToolNames.length > 0) {
|
|
4534
|
+
registerFeatureModuleTools(featureModuleToolNames);
|
|
4535
|
+
}
|
|
4536
|
+
if (wsManager && featureRegistry.hasModules) {
|
|
4537
|
+
featureRegistry.registerAllWsHandlers(wsManager);
|
|
4538
|
+
}
|
|
3552
4539
|
const cliTools = [
|
|
3553
4540
|
agentDelegateTool,
|
|
3554
4541
|
...backgroundTools,
|
|
@@ -3562,7 +4549,8 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3562
4549
|
if (dynamicAgentTool) {
|
|
3563
4550
|
cliTools.push(dynamicAgentTool);
|
|
3564
4551
|
}
|
|
3565
|
-
const
|
|
4552
|
+
const featureTools = featureRegistry.getAllTools();
|
|
4553
|
+
const allTools = [...b4mTools, ...mcpTools, ...cliTools, ...featureTools];
|
|
3566
4554
|
startupLog.push(`\u{1F4C2} Working directory: ${process.cwd()}`);
|
|
3567
4555
|
if (additionalDirectories.length > 0) {
|
|
3568
4556
|
startupLog.push(`\u{1F4C1} Additional directories: ${additionalDirectories.length}`);
|
|
@@ -3578,8 +4566,12 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3578
4566
|
if (dynamicAgentTool) {
|
|
3579
4567
|
startupLog.push(`\u{1F9EA} Dynamic agent creation enabled (experimental)`);
|
|
3580
4568
|
}
|
|
4569
|
+
if (featureRegistry.hasModules) {
|
|
4570
|
+
const moduleNames = featureRegistry.getModuleNames().join(", ");
|
|
4571
|
+
startupLog.push(`\u{1F3F0} Feature modules: ${moduleNames} (${featureTools.length} tools)`);
|
|
4572
|
+
}
|
|
3581
4573
|
logger.debug(
|
|
3582
|
-
`Total tools available to agent: ${allTools.length} (${b4mTools.length} B4M + ${mcpTools.length} MCP + ${cliTools.length} CLI)`
|
|
4574
|
+
`Total tools available to agent: ${allTools.length} (${b4mTools.length} B4M + ${mcpTools.length} MCP + ${cliTools.length} CLI + ${featureTools.length} feature)`
|
|
3583
4575
|
);
|
|
3584
4576
|
if (contextResult.globalContext) {
|
|
3585
4577
|
startupLog.push(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
|
|
@@ -3590,13 +4582,15 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3590
4582
|
for (const error of contextResult.errors) {
|
|
3591
4583
|
startupLog.push(`\u26A0\uFE0F Context file error: ${error}`);
|
|
3592
4584
|
}
|
|
4585
|
+
const featureModulePrompts = featureRegistry.getSystemPromptSections();
|
|
3593
4586
|
const cliSystemPrompt = buildCoreSystemPrompt({
|
|
3594
4587
|
contextContent: contextResult.mergedContent,
|
|
3595
4588
|
agentStore,
|
|
3596
4589
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
3597
4590
|
enableSkillTool,
|
|
3598
4591
|
enableDynamicAgentCreation: config.preferences.enableDynamicAgentCreation === true,
|
|
3599
|
-
additionalDirectories
|
|
4592
|
+
additionalDirectories,
|
|
4593
|
+
featureModulePrompts: featureModulePrompts || void 0
|
|
3600
4594
|
});
|
|
3601
4595
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
3602
4596
|
const agent = new ReActAgent({
|
|
@@ -3664,8 +4658,10 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3664
4658
|
// WebSocket connection manager (null if using SSE fallback)
|
|
3665
4659
|
checkpointStore,
|
|
3666
4660
|
// File change checkpointing for undo/restore
|
|
3667
|
-
additionalDirectories
|
|
4661
|
+
additionalDirectories,
|
|
3668
4662
|
// Store additional directories for file access
|
|
4663
|
+
featureRegistry
|
|
4664
|
+
// Feature module registry for opt-in modules
|
|
3669
4665
|
}));
|
|
3670
4666
|
setStoreSession(newSession);
|
|
3671
4667
|
const bannerLines = [
|
|
@@ -3942,7 +4938,8 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3942
4938
|
agentStore: state.agentStore || void 0,
|
|
3943
4939
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
3944
4940
|
enableSkillTool: config?.preferences.enableSkillTool !== false,
|
|
3945
|
-
additionalDirectories: state.additionalDirectories
|
|
4941
|
+
additionalDirectories: state.additionalDirectories,
|
|
4942
|
+
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
|
|
3946
4943
|
});
|
|
3947
4944
|
const contextUsage = tokenCounter2.countSessionTokens(activeSession, systemPrompt);
|
|
3948
4945
|
if (contextUsage.totalTokens >= threshold) {
|
|
@@ -4997,7 +5994,8 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
4997
5994
|
agentStore: state.agentStore || void 0,
|
|
4998
5995
|
customCommands: commands,
|
|
4999
5996
|
enableSkillTool: state.config?.preferences.enableSkillTool !== false,
|
|
5000
|
-
additionalDirectories: state.additionalDirectories
|
|
5997
|
+
additionalDirectories: state.additionalDirectories,
|
|
5998
|
+
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
|
|
5001
5999
|
});
|
|
5002
6000
|
const usage = tokenCounter2.countSessionTokens(state.session, systemPrompt);
|
|
5003
6001
|
const totalWithTools = usage.totalTokens + mcpToolsTokens;
|
|
@@ -5545,15 +6543,70 @@ Allowed domains (${domains.length}):`);
|
|
|
5545
6543
|
console.log("Violation log cleared.");
|
|
5546
6544
|
break;
|
|
5547
6545
|
}
|
|
5548
|
-
default:
|
|
6546
|
+
default: {
|
|
6547
|
+
if (state.featureRegistry?.executeCommand(command, args)) {
|
|
6548
|
+
break;
|
|
6549
|
+
}
|
|
5549
6550
|
console.log(`Unknown command: /${command}`);
|
|
5550
6551
|
console.log("Type /help for available commands");
|
|
6552
|
+
}
|
|
5551
6553
|
}
|
|
5552
6554
|
};
|
|
5553
6555
|
const handleSaveConfig = async (updatedConfig) => {
|
|
5554
6556
|
await state.configStore.save(updatedConfig);
|
|
5555
6557
|
const modelChanged = state.config?.defaultModel !== updatedConfig.defaultModel;
|
|
6558
|
+
const featuresChanged = JSON.stringify(state.config?.features ?? {}) !== JSON.stringify(updatedConfig.features ?? {});
|
|
6559
|
+
let newFeatureRegistry = state.featureRegistry;
|
|
6560
|
+
if (featuresChanged && state.agent) {
|
|
6561
|
+
state.featureRegistry?.disposeAll();
|
|
6562
|
+
clearFeatureModuleTools();
|
|
6563
|
+
newFeatureRegistry = new FeatureModuleRegistry();
|
|
6564
|
+
const apiClient = new ApiClient(getApiUrl(updatedConfig.apiConfig), state.configStore);
|
|
6565
|
+
if (updatedConfig.features?.tavern) {
|
|
6566
|
+
newFeatureRegistry.register(
|
|
6567
|
+
new TavernModule(
|
|
6568
|
+
apiClient,
|
|
6569
|
+
(entry) => useCliStore.getState().addTavernLogEntry(entry),
|
|
6570
|
+
() => useCliStore.getState().tavernActivityLog
|
|
6571
|
+
)
|
|
6572
|
+
);
|
|
6573
|
+
}
|
|
6574
|
+
const newToolNames = newFeatureRegistry.getAllToolNames();
|
|
6575
|
+
if (newToolNames.length > 0) {
|
|
6576
|
+
registerFeatureModuleTools(newToolNames);
|
|
6577
|
+
}
|
|
6578
|
+
if (state.wsManager && newFeatureRegistry.hasModules) {
|
|
6579
|
+
newFeatureRegistry.registerAllWsHandlers(state.wsManager);
|
|
6580
|
+
}
|
|
6581
|
+
const agentContext = state.agent.context;
|
|
6582
|
+
const oldFeatureToolNames = new Set(state.featureRegistry?.getAllToolNames() ?? []);
|
|
6583
|
+
const baseTools = agentContext.tools.filter((t) => !oldFeatureToolNames.has(t.toolSchema.name));
|
|
6584
|
+
const newFeatureTools = newFeatureRegistry.getAllTools();
|
|
6585
|
+
agentContext.tools = [...baseTools, ...newFeatureTools];
|
|
6586
|
+
const newFeaturePrompts = newFeatureRegistry.getSystemPromptSections();
|
|
6587
|
+
agentContext.systemPrompt = buildCoreSystemPrompt({
|
|
6588
|
+
contextContent: state.contextContent,
|
|
6589
|
+
agentStore: state.agentStore || void 0,
|
|
6590
|
+
customCommands: state.customCommandStore.getAllCommands(),
|
|
6591
|
+
enableSkillTool: updatedConfig.preferences.enableSkillTool !== false,
|
|
6592
|
+
enableDynamicAgentCreation: updatedConfig.preferences.enableDynamicAgentCreation === true,
|
|
6593
|
+
additionalDirectories: state.additionalDirectories,
|
|
6594
|
+
featureModulePrompts: newFeaturePrompts || void 0
|
|
6595
|
+
});
|
|
6596
|
+
const moduleNames = newFeatureRegistry.getModuleNames();
|
|
6597
|
+
if (moduleNames.length > 0) {
|
|
6598
|
+
console.error(`
|
|
6599
|
+
\x1B[36m\u{1F3F0} Feature modules hot-reloaded: ${moduleNames.join(", ")}\x1B[0m`);
|
|
6600
|
+
} else {
|
|
6601
|
+
console.error(`
|
|
6602
|
+
\x1B[36m\u{1F3F0} Feature modules disabled\x1B[0m`);
|
|
6603
|
+
}
|
|
6604
|
+
}
|
|
5556
6605
|
setState((prev) => {
|
|
6606
|
+
const updates = { config: updatedConfig };
|
|
6607
|
+
if (featuresChanged) {
|
|
6608
|
+
updates.featureRegistry = newFeatureRegistry;
|
|
6609
|
+
}
|
|
5557
6610
|
if (modelChanged && prev.session) {
|
|
5558
6611
|
const updatedSession = {
|
|
5559
6612
|
...prev.session,
|
|
@@ -5564,9 +6617,9 @@ Allowed domains (${domains.length}):`);
|
|
|
5564
6617
|
if (prev.agent) {
|
|
5565
6618
|
prev.agent.context.model = updatedConfig.defaultModel;
|
|
5566
6619
|
}
|
|
5567
|
-
return { ...prev,
|
|
6620
|
+
return { ...prev, ...updates, session: updatedSession };
|
|
5568
6621
|
}
|
|
5569
|
-
return { ...prev,
|
|
6622
|
+
return { ...prev, ...updates };
|
|
5570
6623
|
});
|
|
5571
6624
|
if (modelChanged && state.agent) {
|
|
5572
6625
|
const backend = state.agent.context.llm;
|
|
@@ -5662,7 +6715,11 @@ Allowed domains (${domains.length}):`);
|
|
|
5662
6715
|
if (!isInitialized) {
|
|
5663
6716
|
return /* @__PURE__ */ React22.createElement(Box21, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React22.createElement(Text21, null, "\u{1F680} Initializing..."));
|
|
5664
6717
|
}
|
|
5665
|
-
const
|
|
6718
|
+
const featureCommandDefs = (state.featureRegistry?.getAllCommands() ?? []).map((cmd) => ({
|
|
6719
|
+
name: cmd.name,
|
|
6720
|
+
description: cmd.description
|
|
6721
|
+
}));
|
|
6722
|
+
const allCommands = mergeCommands(state.customCommandStore.getAllCommands(), featureCommandDefs);
|
|
5666
6723
|
return /* @__PURE__ */ React22.createElement(
|
|
5667
6724
|
App,
|
|
5668
6725
|
{
|