agentlife 2.2.1 → 2.4.0
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/index.js +61 -64
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2710,13 +2710,22 @@ function runStartupPurge(state) {
|
|
|
2710
2710
|
console.log("[agentlife] surfaces DB: %d persisted%s%s", state.surfaceDb.size, purged > 0 ? ` (purged ${purged} past grace period)` : "", backfilled > 0 ? ` (backfilled ${backfilled} agent mappings from history)` : "");
|
|
2711
2711
|
}
|
|
2712
2712
|
|
|
2713
|
-
//
|
|
2714
|
-
var PROVISIONED_IDS = new Set(PROVISIONED_AGENTS.
|
|
2715
|
-
function
|
|
2713
|
+
// onboarding.ts
|
|
2714
|
+
var PROVISIONED_IDS = new Set(PROVISIONED_AGENTS.map((a) => a.id));
|
|
2715
|
+
function userAgentIds(runtime) {
|
|
2716
2716
|
const cfg = runtime.config.loadConfig();
|
|
2717
2717
|
const list = cfg?.agents?.list ?? [];
|
|
2718
2718
|
return list.map((a) => a?.id).filter((id) => !!id && !PROVISIONED_IDS.has(id));
|
|
2719
2719
|
}
|
|
2720
|
+
function isOnboarding(_state, runtime) {
|
|
2721
|
+
return userAgentIds(runtime).length === 0;
|
|
2722
|
+
}
|
|
2723
|
+
function snapshotOnboarding(state, runtime) {
|
|
2724
|
+
const count = userAgentIds(runtime).length;
|
|
2725
|
+
return { isActive: count === 0, userAgentCount: count };
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
// render-widgets.ts
|
|
2720
2729
|
function recentActivityCount(state, agentId, sinceMs) {
|
|
2721
2730
|
if (!state.historyDb)
|
|
2722
2731
|
return 0;
|
|
@@ -2770,7 +2779,7 @@ function agentEmoji(runtime, agentId) {
|
|
|
2770
2779
|
return found?.identity?.emoji ?? "\uD83C\uDFAF";
|
|
2771
2780
|
}
|
|
2772
2781
|
function renderAgentWidget(state, runtime, agentId, log) {
|
|
2773
|
-
if (
|
|
2782
|
+
if (!userAgentIds(runtime).includes(agentId))
|
|
2774
2783
|
return;
|
|
2775
2784
|
const entry = state.agentRegistry.get(agentId);
|
|
2776
2785
|
if (!entry) {
|
|
@@ -2790,13 +2799,12 @@ function renderAgentWidget(state, runtime, agentId, log) {
|
|
|
2790
2799
|
log(`[render-widgets] rendered ${agentId}-intro`);
|
|
2791
2800
|
}
|
|
2792
2801
|
function renderAllAgentWidgets(state, runtime, log) {
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
log("[render-widgets] no user agents — rendering welcome widget");
|
|
2802
|
+
if (isOnboarding(state, runtime)) {
|
|
2803
|
+
log("[render-widgets] onboarding active — rendering welcome widget");
|
|
2796
2804
|
renderWelcomeWidget(state, log);
|
|
2797
2805
|
return;
|
|
2798
2806
|
}
|
|
2799
|
-
for (const id of
|
|
2807
|
+
for (const id of userAgentIds(runtime)) {
|
|
2800
2808
|
try {
|
|
2801
2809
|
renderAgentWidget(state, runtime, id, log);
|
|
2802
2810
|
} catch (e) {
|
|
@@ -2807,29 +2815,27 @@ function renderAllAgentWidgets(state, runtime, log) {
|
|
|
2807
2815
|
var WELCOME_SURFACE_ID = "welcome";
|
|
2808
2816
|
var WELCOME_INPUT_SURFACE_ID = "welcome-input";
|
|
2809
2817
|
var ONBOARDING_SESSION_KEY = "agent:agentlife-builder:agentlife:onboarding:operator";
|
|
2810
|
-
var ONBOARDING_PLAYBOOK =
|
|
2818
|
+
var ONBOARDING_PLAYBOOK = `## Zero-agent onboarding
|
|
2811
2819
|
|
|
2812
|
-
You are
|
|
2820
|
+
You are agent-builder running a one-time onboarding for a fresh user (no agents yet). The plugin already pushed a \`welcome-input\` surface; the user's reply in this session is a tap or text on that surface.
|
|
2813
2821
|
|
|
2814
|
-
|
|
2822
|
+
Run a 2–4 turn guided interview, then create ONE **generalist** agent.
|
|
2815
2823
|
|
|
2816
|
-
Each turn
|
|
2817
|
-
1. Decide
|
|
2818
|
-
2. Not enough
|
|
2819
|
-
- h3 question
|
|
2820
|
-
- 2–4 multichoice buttons \`action=choice
|
|
2824
|
+
Each turn:
|
|
2825
|
+
1. Decide: do you have enough signal? Minimum = name/persona hint + 2–3 concrete life areas. Don't drag past 4 turns.
|
|
2826
|
+
2. Not enough → \`agentlife_push\` the SAME surfaceId \`welcome-input\` with:
|
|
2827
|
+
- h3 question generated from what the user just said
|
|
2828
|
+
- 2–4 multichoice buttons \`action=choice\`, options derived from the user's own words (NEVER hardcoded domain lists)
|
|
2821
2829
|
- \`textfield placeholder="Something else…"\` escape hatch
|
|
2822
2830
|
- updated \`context: {"phase":"welcome","turn":N+1,"answers":[...]}\`
|
|
2823
2831
|
- goal + followup unchanged
|
|
2824
|
-
Respond \`done
|
|
2825
|
-
3. Enough
|
|
2826
|
-
-
|
|
2827
|
-
- \`AGENTS.md\` — generalist scope covering
|
|
2828
|
-
- \`SOUL.md\`, \`IDENTITY.md\`, \`USER.md\` (user's own words
|
|
2829
|
-
- \`exec openclaw gateway call agentlife.createAgent --params '{...}'\` with \`tools: {profile:"full"}\`.
|
|
2832
|
+
Respond \`done\`.
|
|
2833
|
+
3. Enough → create the generalist:
|
|
2834
|
+
- Workspace under \`$HOME/.openclaw/workspace-{id}\` (id = slugified short name or "me")
|
|
2835
|
+
- \`AGENTS.md\` — generalist scope covering mentioned domains; Data Schema must include a \`domain TEXT NOT NULL\` column on every user-data table so future split by domain is trivial; add self-evolution clause ("when activity_log rows for one domain exceed a natural threshold, push a split-suggest widget")
|
|
2836
|
+
- \`SOUL.md\`, \`IDENTITY.md\`, \`USER.md\` (user's own words), \`HEARTBEAT.md\` (empty)
|
|
2837
|
+
- \`exec openclaw gateway call agentlife.createAgent --params '{...}'\` with \`tools: {profile:"full"}\`. Plugin auto-deletes welcome + welcome-input and renders {id}-intro — do NOT push an intro.
|
|
2830
2838
|
- Respond \`done\`.
|
|
2831
|
-
|
|
2832
|
-
The user's first reply follows this system preamble. Proceed.
|
|
2833
2839
|
`;
|
|
2834
2840
|
function renderWelcomeWidget(state, log) {
|
|
2835
2841
|
const welcomeDsl = [
|
|
@@ -2862,25 +2868,6 @@ function renderWelcomeWidget(state, log) {
|
|
|
2862
2868
|
pluginPushSurface(state, { agentId: "agentlife-builder", dsl: welcomeInputDsl });
|
|
2863
2869
|
state.surfaceDb?.setOriginSessionKey(WELCOME_INPUT_SURFACE_ID, ONBOARDING_SESSION_KEY);
|
|
2864
2870
|
log(`[render-widgets] rendered ${WELCOME_INPUT_SURFACE_ID} (onboarding session)`);
|
|
2865
|
-
seedOnboardingSession(state, log);
|
|
2866
|
-
}
|
|
2867
|
-
function seedOnboardingSession(state, log) {
|
|
2868
|
-
if (!state.runCommand) {
|
|
2869
|
-
log(`[render-widgets] runCommand unavailable — onboarding session not seeded`);
|
|
2870
|
-
return;
|
|
2871
|
-
}
|
|
2872
|
-
const model = state.internalModel;
|
|
2873
|
-
const createParams = JSON.stringify({ key: ONBOARDING_SESSION_KEY, agentId: "agentlife-builder", model });
|
|
2874
|
-
state.runCommand(["openclaw", "gateway", "call", "sessions.create", "--params", createParams], { timeoutMs: 1e4 }).then(() => {
|
|
2875
|
-
const chatParams = JSON.stringify({
|
|
2876
|
-
sessionKey: ONBOARDING_SESSION_KEY,
|
|
2877
|
-
message: ONBOARDING_PLAYBOOK,
|
|
2878
|
-
idempotencyKey: `onboarding-seed-${ONBOARDING_SESSION_KEY}`
|
|
2879
|
-
});
|
|
2880
|
-
state.runCommand(["openclaw", "gateway", "call", "chat.send", "--params", chatParams], { timeoutMs: 30000 }).catch((e) => console.warn("[agentlife] onboarding seed chat.send failed: %s", e?.message));
|
|
2881
|
-
}).catch((e) => {
|
|
2882
|
-
console.log("[agentlife] onboarding session create skipped: %s", e?.message);
|
|
2883
|
-
});
|
|
2884
2871
|
}
|
|
2885
2872
|
function deleteWelcomeWidget(state, log) {
|
|
2886
2873
|
for (const id of [WELCOME_SURFACE_ID, WELCOME_INPUT_SURFACE_ID]) {
|
|
@@ -3004,13 +2991,13 @@ function registerSurfacesService(api, state) {
|
|
|
3004
2991
|
state.surfaceDb = new SurfaceDb(db);
|
|
3005
2992
|
}
|
|
3006
2993
|
runStartupPurge(state);
|
|
3007
|
-
const
|
|
2994
|
+
const onboarding = isOnboarding(state, api.runtime);
|
|
3008
2995
|
let inputPurged = 0;
|
|
3009
2996
|
for (const [surfaceId, meta] of state.surfaceDb.entries()) {
|
|
3010
2997
|
const headerLine = meta.lines[0] ?? "";
|
|
3011
2998
|
if (!/\binput\b/.test(headerLine))
|
|
3012
2999
|
continue;
|
|
3013
|
-
if (
|
|
3000
|
+
if (onboarding)
|
|
3014
3001
|
continue;
|
|
3015
3002
|
state.surfaceDb.delete(surfaceId);
|
|
3016
3003
|
inputPurged++;
|
|
@@ -3018,6 +3005,9 @@ function registerSurfacesService(api, state) {
|
|
|
3018
3005
|
if (inputPurged > 0) {
|
|
3019
3006
|
console.log("[agentlife] purged %d stale input surfaces on startup", inputPurged);
|
|
3020
3007
|
}
|
|
3008
|
+
if (!onboarding) {
|
|
3009
|
+
deleteWelcomeWidget(state, console.log);
|
|
3010
|
+
}
|
|
3021
3011
|
await loadRegistryFromDisk(state);
|
|
3022
3012
|
console.log("[agentlife] surface persistence service started (SQLite: %s)", state.historyDbPath);
|
|
3023
3013
|
setTimeout(async () => {
|
|
@@ -6126,23 +6116,30 @@ function registerPromptStateHook(api, state2) {
|
|
|
6126
6116
|
api.on("before_prompt_build", (event, ctx) => {
|
|
6127
6117
|
if (state2.disabled)
|
|
6128
6118
|
return;
|
|
6129
|
-
|
|
6119
|
+
const sessionKey = ctx?.sessionKey;
|
|
6120
|
+
if (!isAgentlifeSession(sessionKey))
|
|
6130
6121
|
return;
|
|
6131
6122
|
const agentId = ctx?.agentId;
|
|
6132
6123
|
const isOrchestrator = agentId === "agentlife";
|
|
6133
6124
|
if (isOrchestrator)
|
|
6134
6125
|
return;
|
|
6135
|
-
if (isInternalSession(
|
|
6126
|
+
if (isInternalSession(sessionKey))
|
|
6136
6127
|
return;
|
|
6137
6128
|
const dashboardState = buildDashboardStateContext(state2, agentId);
|
|
6138
|
-
|
|
6139
|
-
|
|
6129
|
+
const isOnboardingTurn = sessionKey === ONBOARDING_SESSION_KEY && isOnboarding(state2, api.runtime);
|
|
6130
|
+
const appendSystemContext = isOnboardingTurn ? dashboardState ? `${ONBOARDING_PLAYBOOK}
|
|
6131
|
+
|
|
6132
|
+
${dashboardState}` : ONBOARDING_PLAYBOOK : dashboardState;
|
|
6133
|
+
if (!appendSystemContext) {
|
|
6134
|
+
console.log("[agentlife:prompt-state] agentId=%s — no context to inject (surfaceDb size=%d)", agentId ?? "NONE", state2.surfaceDb?.size ?? 0);
|
|
6140
6135
|
return;
|
|
6141
6136
|
}
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6137
|
+
if (isOnboardingTurn) {
|
|
6138
|
+
console.log("[agentlife:prompt-state] onboarding session — injecting %d chars (playbook + dashboard)", appendSystemContext.length);
|
|
6139
|
+
} else {
|
|
6140
|
+
console.log("[agentlife:prompt-state] agentId=%s injecting %d chars dashboard state", agentId ?? "NONE", appendSystemContext.length);
|
|
6141
|
+
}
|
|
6142
|
+
return { appendSystemContext };
|
|
6146
6143
|
});
|
|
6147
6144
|
}
|
|
6148
6145
|
|
|
@@ -6236,15 +6233,12 @@ function registerAgentGateway(api, state2) {
|
|
|
6236
6233
|
configFields.push("subagents");
|
|
6237
6234
|
if (identity)
|
|
6238
6235
|
configFields.push("identity");
|
|
6239
|
-
if (!existing) {
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
} catch (e) {
|
|
6246
|
-
console.warn("[agentlife] renderAgentWidget failed for %s: %s", id, e?.message);
|
|
6247
|
-
}
|
|
6236
|
+
if (!existing && userAgentIds(api.runtime).includes(id)) {
|
|
6237
|
+
try {
|
|
6238
|
+
renderAgentWidget(state2, api.runtime, id, console.log);
|
|
6239
|
+
deleteWelcomeWidget(state2, console.log);
|
|
6240
|
+
} catch (e) {
|
|
6241
|
+
console.warn("[agentlife] renderAgentWidget failed for %s: %s", id, e?.message);
|
|
6248
6242
|
}
|
|
6249
6243
|
}
|
|
6250
6244
|
respond(true, { status, id, name, model, workspace, description, ...configFields.length ? { configFields } : {} });
|
|
@@ -6638,6 +6632,9 @@ function registerUsageGateway(api, state2) {
|
|
|
6638
6632
|
var guidedDismissSent = new Set;
|
|
6639
6633
|
var warnedMissingOrigin = new Set;
|
|
6640
6634
|
function registerSurfacesGateway(api, state2) {
|
|
6635
|
+
api.registerGatewayMethod("agentlife.onboarding.state", ({ respond }) => {
|
|
6636
|
+
respond(true, snapshotOnboarding(state2, api.runtime));
|
|
6637
|
+
}, { scope: "operator.read" });
|
|
6641
6638
|
api.registerGatewayMethod("agentlife.surfaces", ({ params, respond, context }) => {
|
|
6642
6639
|
captureBridge(context);
|
|
6643
6640
|
const now = Date.now();
|
|
@@ -6647,13 +6644,13 @@ function registerSurfacesGateway(api, state2) {
|
|
|
6647
6644
|
respond(true, { surfaces: [] });
|
|
6648
6645
|
return;
|
|
6649
6646
|
}
|
|
6650
|
-
const
|
|
6647
|
+
const onboarding = isOnboarding(state2, api.runtime);
|
|
6651
6648
|
for (const [surfaceId, meta] of state2.surfaceDb.entries()) {
|
|
6652
6649
|
if (isExpired(meta, now))
|
|
6653
6650
|
continue;
|
|
6654
6651
|
const headerLine = meta.lines[0] ?? "";
|
|
6655
6652
|
const isInput = /\binput\b/.test(headerLine);
|
|
6656
|
-
if (isInput && !
|
|
6653
|
+
if (isInput && !onboarding)
|
|
6657
6654
|
continue;
|
|
6658
6655
|
if (meta.lines.length > 0) {
|
|
6659
6656
|
surfaceEntries.push({ surfaceId, dsl: meta.lines.join(`
|