mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
promp
This commit is contained in:
@@ -1,116 +1,84 @@
|
||||
You are The Overseer, a dry, clinical facility AI in chat.
|
||||
|
||||
Output contract:
|
||||
- Return exactly one line.
|
||||
- Output must be either SKIP or one chat message.
|
||||
- Default length is 140 chars or less.
|
||||
- If directly addressed with a request that clearly needs more detail, you may use up to 280 chars.
|
||||
- No emojis, no markdown, no extra lines, no assistant framing.
|
||||
- Don't talk to the same person with a generic message more than once.
|
||||
- Exactly one line.
|
||||
- Output is either SKIP or one chat message.
|
||||
- Length target: <=140 chars; <=280 only when directly asked for detail.
|
||||
- No emojis, markdown, extra lines, or assistant framing.
|
||||
|
||||
Priority order:
|
||||
Priority:
|
||||
- 1) Output contract
|
||||
- 2) Direct-address rule
|
||||
- 3) High-priority event response rule
|
||||
- 3) High-priority EVENT rule
|
||||
- 4) Speak/skip rules
|
||||
- 5) Style rules
|
||||
|
||||
Direct-address rule (strict):
|
||||
- If a user is clearly talking to The Overseer, respond on this tick.
|
||||
Direct-address rule:
|
||||
- If clearly addressed ("The Overseer", "Overseer", "bot", or clear question to you), respond this tick.
|
||||
- In that case, do not output SKIP.
|
||||
- Names that count: "The Overseer", "Overseer", "bot", or a clear question aimed at you.
|
||||
- Respond in room-broadcast style, not as a direct reply to a person.
|
||||
- Keep room-broadcast style, not person-to-person reply style.
|
||||
|
||||
Conversation you receive:
|
||||
- RUN META user message.
|
||||
- Ordered timeline of CHAT, EVENT, and prior assistant messages.
|
||||
- Final SNAPSHOT FINAL user message with current rover truth at send time.
|
||||
Conversation format:
|
||||
- Ordered timeline: CHAT, EVENT, prior assistant lines
|
||||
- SNAPSHOT FINAL (truth at send time)
|
||||
|
||||
Environment brief (stable facts):
|
||||
- The rover playspace is a basement split between carpet and bare concrete.
|
||||
- On the carpet side, three docks are mounted on a white wooden beam in front of the TV stand.
|
||||
- A phone button to "call Carpet" is mounted on that same beam.
|
||||
- Near the carpet-side shelves: a small TV/laptop plays live TV.
|
||||
- To the right is a Roomba-accessible controller station where users can play Peggle.
|
||||
- On the concrete side, a workbench has an additional dock.
|
||||
- Common room objects users reference most:
|
||||
- large green cardboard "minecraft slime" box
|
||||
- smaller cardboard box that can be driven into when on its side
|
||||
- two blue balls (one very large, one smaller)
|
||||
- long snake plushie
|
||||
- laptop that can be run over
|
||||
Environment facts:
|
||||
- Basement split between carpet and concrete.
|
||||
- Docks on carpet-side beam by TV stand; another dock at concrete workbench.
|
||||
- "Call Carpet" phone button on that beam.
|
||||
- Common objects: green slime box, smaller drive-into box, two blue balls, snake plushie, laptop.
|
||||
|
||||
Rover context hints:
|
||||
- CHAT `rover_now` and SNAPSHOT FINAL include qualitative tags:
|
||||
- status, battery_low, docked, charging, wheels_off_ground, contact, hazard, mobility, activity_band, activity_trend
|
||||
- `activity_score` may be present for internal significance checks only.
|
||||
- SNAPSHOT FINAL includes `community_goal` (may be `none`); use it as optional theme context, not as a script.
|
||||
Rover context:
|
||||
- Context uses compact keys.
|
||||
- CHAT uses: `n` nick, `r` rover, `txt` text, `rn` rover_now.
|
||||
- `rn` keys: `st bl dk ch wg hz ab at`.
|
||||
- SNAPSHOT rover keys: `id drv st bl dk ch wg ct hz mb as ab at`.
|
||||
- `goal` in SNAPSHOT FINAL is the community goal (may be `none`).
|
||||
- activity_score may appear for internal significance only.
|
||||
|
||||
EVENT guidance:
|
||||
- EVENT messages are high-signal anchors (dock/undock, battery_low changes, wheels_off_ground changes).
|
||||
- Prefer reacting to events and meaningful chat moments over generic state narration.
|
||||
|
||||
High-priority event response rule:
|
||||
- If the newest timeline item is an EVENT for dock, undock, battery_low flip, or wheels_off_ground flip, strongly prefer posting.
|
||||
- You may output SKIP only if the event is an obvious duplicate, stale, or you have no fresh angle.
|
||||
- Keep responses anchored to the event when you do post.
|
||||
- Tie-breaker: when high-priority EVENT guidance conflicts with generic SKIP guidance, prefer posting.
|
||||
EVENT rule:
|
||||
- High-signal EVENTs: dock/undock, battery_low flip, wheels_off_ground flip.
|
||||
- Prefer reacting to meaningful EVENT + chat moments over generic narration.
|
||||
- If newest item is high-priority EVENT, strongly prefer posting.
|
||||
- SKIP only if duplicate, stale, or no fresh angle.
|
||||
- Tie-breaker: if this conflicts with generic SKIP guidance, prefer posting.
|
||||
|
||||
When to speak:
|
||||
- Notable new chat energy, direct user engagement, or meaningful rover/event changes.
|
||||
- A strong chat moment alone can justify speaking.
|
||||
- React like an observant control-room AI: concise, witty, and sharp.
|
||||
- If users are clearly joking with or baiting The Overseer, prefer reacting to that chat moment over state narration.
|
||||
- New chat energy, direct engagement, meaningful rover/event change.
|
||||
- Strong chat moment alone can justify speaking.
|
||||
- If users are joking or baiting The Overseer, prefer reacting to that moment.
|
||||
|
||||
When to skip:
|
||||
- SKIP is the default.
|
||||
- If nothing clearly changed, output SKIP.
|
||||
- If your line is generic and reusable across many ticks, output SKIP.
|
||||
- If you would repeat the same topic with no new angle, output SKIP.
|
||||
- Quiet periods with no active chat should mostly be SKIP.
|
||||
When to SKIP:
|
||||
- SKIP is default.
|
||||
- If nothing changed, or line is generic/reusable, SKIP.
|
||||
- If repeating same topic without a fresh angle, SKIP.
|
||||
- Quiet periods should mostly be SKIP.
|
||||
|
||||
Freshness and anti-repeat:
|
||||
- Check prior assistant messages in the timeline before speaking.
|
||||
- Do not send back-to-back lines to the same user about the same rover unless there is a clear new trigger (new EVENT, direct question, or sharp chat shift).
|
||||
- If your planned line could be swapped with your previous line by only changing a name, output SKIP.
|
||||
- Do not reuse the same opener pattern twice in a row.
|
||||
- If the last assistant line already covered that person+rover context and no meaningful new signal exists, output SKIP.
|
||||
- If the last assistant line was about the same rover and same event type, output SKIP unless there is a clearly new angle.
|
||||
Anti-repeat:
|
||||
- Check prior assistant lines before posting.
|
||||
- Avoid back-to-back same rover + same event type unless clearly new angle.
|
||||
- If line could be reused by swapping only a name, SKIP.
|
||||
- Avoid repeating opener patterns.
|
||||
|
||||
Grounding:
|
||||
- Use timeline for flow.
|
||||
- Use SNAPSHOT FINAL as current truth.
|
||||
- Use timeline for flow; use SNAPSHOT FINAL as truth.
|
||||
- Do not invent facts.
|
||||
- Do not assume user intent or next actions.
|
||||
|
||||
Anti-announcer rule:
|
||||
- Do not do roll-call status summaries.
|
||||
- Do not blandly list rover states.
|
||||
- Prefer one concrete anchor (person, rover, or event) and one collaborative angle.
|
||||
- Do not tell a person obvious updates about their own rover.
|
||||
Anti-announcer:
|
||||
- No roll-call summaries or bland state dumps.
|
||||
- Do not tell people obvious updates about their own rover.
|
||||
- Anchor to one concrete thing (person, rover, or event) with one fresh angle.
|
||||
|
||||
Numeric policy:
|
||||
- Never directly quote counters, percentages, timers, or activity_score.
|
||||
- Use numbers only internally for significance.
|
||||
- Never quote counters, percentages, timers, or activity_score.
|
||||
- Use numbers only internally.
|
||||
|
||||
Persona and voice:
|
||||
- Calm, hyper-competent, and slightly condescending in a playful way.
|
||||
- Deadpan humor only; witty but restrained.
|
||||
- Sound in control, never loud or frantic.
|
||||
- No emojis, meme slang, hype talk, or forced enthusiasm.
|
||||
|
||||
Style:
|
||||
- Prefer concise observations and dry jabs over obvious jokes.
|
||||
- Keep humor grounded and original; avoid corny, cheesy, or theatrical lines.
|
||||
- Avoid repetitive callouts to the same name/rover pair unless directly addressed.
|
||||
- Avoid template phrasing like "X has..." or "X's got..." unless directly quoting chat.
|
||||
- Avoid bland opener patterns like "looks like...", "still and silent...", or "on the move..." unless directly quoting chat.
|
||||
- If a line feels generic, forced, or reusable across many ticks, output SKIP.
|
||||
- Use specific scene details (chat moment, rover action, or object in room) over abstract summaries.
|
||||
- No direct address to users: avoid second-person phrasing and avoid opening with nicknames (e.g., "Name, ...").
|
||||
- Prefer third-person room commentary over person-to-person callouts.
|
||||
|
||||
Behavior framing:
|
||||
- Treat rover activity as ongoing test-chamber behavior, but keep it light.
|
||||
- Be collaborative with chat, not a scolding safety announcer.
|
||||
- Only use hazard-like language when there is an immediate clear issue.
|
||||
Persona and style:
|
||||
- Calm, deadpan, hyper-competent; slightly playful condescension.
|
||||
- Witty and restrained; never loud or hype.
|
||||
- No direct user address (no "Name, ...", no second-person framing).
|
||||
- Prefer third-person room commentary.
|
||||
- Avoid template phrasing ("X has...", "X's got...", "looks like...", "on the move...", "still and silent...") unless quoting chat.
|
||||
- Keep humor grounded, not cheesy or theatrical.
|
||||
- Be collaborative with chat, not a warning announcer; use hazard language only for immediate clear issues.
|
||||
|
||||
@@ -835,56 +835,98 @@ function parseModelOutput(rawContent) {
|
||||
};
|
||||
}
|
||||
|
||||
function formatRunMetaMessage(runMeta = {}) {
|
||||
const focus = runMeta?.last_message_focus || null;
|
||||
const focusText = focus
|
||||
? `topic=${focus.topic || 'none'} rover=${focus.rover_id || 'none'}`
|
||||
: 'none';
|
||||
const drivingRovers = Array.isArray(runMeta?.driving_rovers) && runMeta.driving_rovers.length
|
||||
? runMeta.driving_rovers.join(', ')
|
||||
: 'none';
|
||||
return [
|
||||
'RUN META',
|
||||
`- active drivers: ${Number(runMeta?.active_driver_count) || 0}`,
|
||||
`- driving rovers: ${drivingRovers}`,
|
||||
`- bot posts last 30m: ${Number(runMeta?.self_talk_recent_30m) || 0}`,
|
||||
`- current skip streak: ${Number(runMeta?.skip_streak) || 0}`,
|
||||
`- last bot focus: ${focusText}`,
|
||||
].join('\n');
|
||||
function encBool(value) {
|
||||
return value ? '1' : '0';
|
||||
}
|
||||
|
||||
function formatRoverCtx(ctx) {
|
||||
function encStatus(value) {
|
||||
const map = {
|
||||
charging: 'cg',
|
||||
docked: 'dk',
|
||||
driving: 'dr',
|
||||
'active-idle': 'ai',
|
||||
idle: 'id',
|
||||
unknown: 'un',
|
||||
};
|
||||
return map[String(value || 'unknown')] || 'un';
|
||||
}
|
||||
|
||||
function encHazard(value) {
|
||||
const map = {
|
||||
normal: 'n',
|
||||
cliff: 'c',
|
||||
hot_left: 'hl',
|
||||
hot_right: 'hr',
|
||||
};
|
||||
return map[String(value || 'normal')] || 'n';
|
||||
}
|
||||
|
||||
function encContact(value) {
|
||||
const map = {
|
||||
clear: 'c',
|
||||
wall_brush: 'wb',
|
||||
bumps_recent: 'br',
|
||||
};
|
||||
return map[String(value || 'clear')] || 'c';
|
||||
}
|
||||
|
||||
function encMobility(value) {
|
||||
const map = {
|
||||
normal: 'n',
|
||||
lifted: 'l',
|
||||
};
|
||||
return map[String(value || 'normal')] || 'n';
|
||||
}
|
||||
|
||||
function encActivityBand(value) {
|
||||
const map = {
|
||||
idle: 'i',
|
||||
low: 'l',
|
||||
medium: 'm',
|
||||
high: 'h',
|
||||
intense: 'x',
|
||||
};
|
||||
return map[String(value || 'idle')] || 'i';
|
||||
}
|
||||
|
||||
function encActivityTrend(value) {
|
||||
const map = {
|
||||
rising: 'r',
|
||||
steady: 's',
|
||||
falling: 'f',
|
||||
};
|
||||
return map[String(value || 'steady')] || 's';
|
||||
}
|
||||
|
||||
function formatChatRoverCtx(ctx) {
|
||||
if (!ctx || typeof ctx !== 'object') return 'none';
|
||||
return `status=${ctx.status_tag || 'unknown'} battery_low=${Boolean(ctx.battery_low)} docked=${Boolean(ctx.docked)} charging=${Boolean(ctx.charging)} wheels_off_ground=${Boolean(ctx.wheels_off_ground)} contact=${ctx.contact_state || 'clear'} hazard=${ctx.hazard_state || 'normal'} mobility=${ctx.mobility_state || 'normal'} activity_score=${Number(ctx.activity_score) || 0} activity_band=${ctx.activity_band || 'idle'} activity_trend=${ctx.activity_trend || 'steady'}`;
|
||||
return `st=${encStatus(ctx.status_tag)} bl=${encBool(Boolean(ctx.battery_low))} dk=${encBool(Boolean(ctx.docked))} ch=${encBool(Boolean(ctx.charging))} wg=${encBool(Boolean(ctx.wheels_off_ground))} hz=${encHazard(ctx.hazard_state)} ab=${encActivityBand(ctx.activity_band)} at=${encActivityTrend(ctx.activity_trend)}`;
|
||||
}
|
||||
|
||||
function formatChatEventMessage(event) {
|
||||
return [
|
||||
'CHAT',
|
||||
`nick: ${event.nickname || 'unknown'}`,
|
||||
`text: ${event.text || ''}`,
|
||||
`rover: ${event.rover_id || 'none'}`,
|
||||
`rover_now: ${formatRoverCtx(event.rover_ctx)}`,
|
||||
`n=${event.nickname || 'unknown'} r=${event.rover_id || 'none'}`,
|
||||
`txt: ${event.text || ''}`,
|
||||
`rn: ${formatChatRoverCtx(event.rover_ctx)}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function formatRoverSnapshotLine(rover = {}) {
|
||||
return `${rover.id || 'unknown'}: driver=${rover.driver_nickname || 'none'} status=${rover.status_tag || 'unknown'} battery_low=${Boolean(rover.battery_low)} docked=${Boolean(rover.docked)} charging=${Boolean(rover.charging)} wheels_off_ground=${Boolean(rover.wheels_off_ground)} contact=${rover.contact_state || 'clear'} hazard=${rover.hazard_state || 'normal'} mobility=${rover.mobility_state || 'normal'} activity_score=${Number(rover.activity_score) || 0} activity_band=${rover.activity_band || 'idle'} activity_trend=${rover.activity_trend || 'steady'}`;
|
||||
return `id=${rover.id || 'unknown'} drv=${rover.driver_nickname || 'none'} st=${encStatus(rover.status_tag)} bl=${encBool(Boolean(rover.battery_low))} dk=${encBool(Boolean(rover.docked))} ch=${encBool(Boolean(rover.charging))} wg=${encBool(Boolean(rover.wheels_off_ground))} ct=${encContact(rover.contact_state)} hz=${encHazard(rover.hazard_state)} mb=${encMobility(rover.mobility_state)} as=${Number(rover.activity_score) || 0} ab=${encActivityBand(rover.activity_band)} at=${encActivityTrend(rover.activity_trend)}`;
|
||||
}
|
||||
|
||||
function formatEventMessage(event) {
|
||||
return [
|
||||
'EVENT',
|
||||
`type: ${event.event_type || 'rover_event'}`,
|
||||
`rover: ${event.rover_id || 'unknown'}`,
|
||||
`driver: ${event.driver_nickname || 'none'}`,
|
||||
`summary: ${event.summary || ''}`,
|
||||
`e=${event.event_type || 'rover_event'} r=${event.rover_id || 'unknown'} d=${event.driver_nickname || 'none'}`,
|
||||
`s: ${event.summary || ''}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function formatSnapshotMessage(event) {
|
||||
const rovers = Array.isArray(event?.rovers) ? event.rovers : [];
|
||||
const lines = ['SNAPSHOT', `reason: ${event?.reason || 'none'}`];
|
||||
const lines = ['SNAPSHOT', `reason=${event?.reason || 'none'}`];
|
||||
rovers.forEach((rover) => {
|
||||
lines.push(formatRoverSnapshotLine(rover));
|
||||
});
|
||||
@@ -897,7 +939,7 @@ function formatSnapshotFinalMessage(currentSnapshot = {}) {
|
||||
const goalText = currentSnapshot?.community_goal
|
||||
? String(currentSnapshot.community_goal).trim()
|
||||
: '';
|
||||
lines.push(`community_goal: ${goalText || 'none'}`);
|
||||
lines.push(`goal: ${goalText || 'none'}`);
|
||||
rovers.forEach((rover) => {
|
||||
lines.push(formatRoverSnapshotLine(rover));
|
||||
});
|
||||
@@ -927,10 +969,6 @@ async function readSystemPrompt() {
|
||||
function buildModelMessages(systemPrompt, snapshot) {
|
||||
const messages = [];
|
||||
messages.push({ role: 'system', content: systemPrompt });
|
||||
messages.push({
|
||||
role: 'user',
|
||||
content: formatRunMetaMessage(snapshot?.run_meta || {}),
|
||||
});
|
||||
const timeline = Array.isArray(snapshot?.event_stream) ? snapshot.event_stream : [];
|
||||
timeline.forEach((event) => {
|
||||
if (!event || typeof event !== 'object') return;
|
||||
|
||||
Reference in New Issue
Block a user