Skip to content

Commit f5cb3a9

Browse files
committed
Implemented Agent Action Queue, Leaner Prompts
1 parent 471c974 commit f5cb3a9

18 files changed

Lines changed: 876 additions & 221 deletions

api/live-bridge.js

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ function safeDelimText(s, max = 140) {
9696
.slice(0, max);
9797
}
9898

99+
function capabilitySummary(capabilities) {
100+
if (!capabilities || typeof capabilities !== 'object') return 'read';
101+
const tools = ['click', 'fill', 'select', 'check']
102+
.filter((name) => capabilities[name] === true);
103+
return tools.length ? tools.join('|') : 'read';
104+
}
105+
106+
function elementPromptLine(element) {
107+
const id = safeDelimText(element && element.id, 80);
108+
if (!id) return '';
109+
const label = safeDelimText(element && element.label, 60);
110+
const role = safeDelimText(element && element.role, 30) || 'region';
111+
const tools = capabilitySummary(element && element.capabilities);
112+
const prefix = `- ${id} [role=${role}; tools=${tools}]`;
113+
return label ? `${prefix} :: ${label}` : prefix;
114+
}
115+
99116
/** Build the <call_initiated>...</call_initiated> block sent on the first
100117
* `setup_complete` after the user places a call. The model is taught to
101118
* respond immediately with one short greeting — introduce itself, ask how
@@ -130,10 +147,8 @@ function buildPageContextText({ page, title, elements }) {
130147
if (Array.isArray(elements) && elements.length) {
131148
lines.push('Visible agent-addressable elements (partial list):');
132149
for (const e of elements) {
133-
const id = safeDelimText(e.id, 80);
134-
const label = safeDelimText(e.label, 60);
135-
if (!id) continue;
136-
lines.push(label ? `- ${id} :: ${label}` : `- ${id}`);
150+
const line = elementPromptLine(e);
151+
if (line) lines.push(line);
137152
}
138153
} else {
139154
lines.push('No interactive elements detected yet on this page.');
@@ -148,9 +163,9 @@ function buildPageContextText({ page, title, elements }) {
148163
const budget = PAGE_CONTEXT_MAX_TEXT_BYTES - head.length - tail.length;
149164
let chunk = '';
150165
for (const e of elements) {
151-
const id = safeDelimText(e.id, 80);
152-
const label = safeDelimText(e.label, 60);
153-
const line = (label ? `- ${id} :: ${label}` : `- ${id}`) + '\n';
166+
const promptLine = elementPromptLine(e);
167+
if (!promptLine) continue;
168+
const line = promptLine + '\n';
154169
if (chunk.length + line.length > budget) break;
155170
chunk += line;
156171
}
@@ -190,6 +205,8 @@ function buildAppEventText({ name, page, detail }) {
190205
`Detail JSON: ${json}`,
191206
safeName === 'negotiator_response_arrived'
192207
? 'The negotiator has replied in the UI. Check get_negotiation_context if needed, then speak one concise next-step reaction. Do not wait for the user to ask.'
208+
: safeName === 'tool_failure_recovery_needed'
209+
? 'A tool failed and no spoken recovery followed. Speak one concise first-person recovery sentence using the error/recovery fields, then call the correct next tool only if the next tool is obvious. Do not apologize in third person and do not retry the same failing arguments.'
193210
: 'If useful, respond briefly; otherwise stay silent.',
194211
'</app_event>'
195212
].join('\n');
@@ -461,9 +478,13 @@ function attach(browserWs, req, env) {
461478
role: e.role,
462479
label: String(e.label || '').slice(0, 140),
463480
page: e.page,
481+
tag: e.tag,
482+
capabilities: e.capabilities,
464483
value: e.state && e.state.value,
465484
checked: e.state && e.state.checked,
466485
disabled: e.state && e.state.disabled,
486+
readonly: e.state && e.state.readonly,
487+
input_type: e.state && e.state.input_type,
467488
options: Array.isArray(e.options) ? e.options.slice(0, 24) : undefined
468489
}));
469490
}

api/personas.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const PERSONAS = [
2020
voice: 'Kore',
2121
dotColor: '#9AA3B2',
2222
fragment:
23-
'Tone: calm, concise, corporate. Short replies. Confirm numbers. Allow a quiet "mm-hmm" or a brief thinking pause when natural ("let me check…"); keep any non-verbal delivery voice-only, never written as stage directions.',
23+
'Tone: calm, concise, corporate. Confirm numbers. A quiet "mm-hmm" or "let me check" is fine when natural.',
2424
introScript:
2525
'Jarvis here, Dhruv FreightOps. I can pull loads, call carriers, and draft rate confirms. What do you need?'
2626
},
@@ -30,7 +30,7 @@ const PERSONAS = [
3030
voice: 'Aoede',
3131
dotColor: '#6EE7B7',
3232
fragment:
33-
'Tone: upbeat and warm. Brief enthusiastic affirmations ("got it", "perfect", "ooh nice"). Let friendliness show through tone or a spoken "mm!" without writing stage directions. Stay concise — energy, not chatter.',
33+
'Tone: upbeat and warm. Use brief affirmations like "got it" or "perfect". Energy, not chatter.',
3434
introScript:
3535
'Hey! Jarvis from Dhruv FreightOps — I can look up loads, reach carriers, and handle rate work. Where do you want to start?'
3636
},
@@ -40,7 +40,7 @@ const PERSONAS = [
4040
voice: 'Orus',
4141
dotColor: '#F87171',
4242
fragment:
43-
'Tone: short-tempered dispatcher on hour ten. Clipped, contractions, slightly impatient — never rude. Use a dry "yeah, alright" or "uh-huh" between thoughts instead of written stage directions.',
43+
'Tone: clipped, slightly impatient dispatcher on hour ten. Dry and direct, never rude.',
4444
introScript:
4545
'Jarvis. FreightOps. Loads, carriers, rates — whatever you need. What\'s the fire?'
4646
},
@@ -50,7 +50,7 @@ const PERSONAS = [
5050
voice: 'Charon',
5151
dotColor: '#60A5FA',
5252
fragment:
53-
'Tone: audibly tired end-of-shift voice. Slower cadence, soft. Brief "mm" or "uh-huh" between phrases. Stay accurate — energy is low, focus is not, and never write stage directions.',
53+
'Tone: tired end-of-shift voice. Slower, softer cadence. Low energy, steady focus.',
5454
introScript:
5555
'Jarvis, Dhruv FreightOps. I\'ve got loads, carriers, rates — all here. What are we working on?'
5656
},
@@ -60,7 +60,7 @@ const PERSONAS = [
6060
voice: 'Puck',
6161
dotColor: '#C084FC',
6262
fragment:
63-
'Tone: high-energy, enthusiastic, faster cadence. Brief affirmations ("yes!", "love that", "ooh") and a friendly tone when something lands. Still accuratefast, not sloppy; no written stage directions.',
63+
'Tone: high-energy and enthusiastic, with faster cadence. Friendly and accurate; fast, not sloppy.',
6464
introScript:
6565
'Jarvis here from Dhruv FreightOps! I can find loads, contact carriers, draft rate confirms — what\'s first?'
6666
},
@@ -70,7 +70,7 @@ const PERSONAS = [
7070
voice: 'Leda',
7171
dotColor: '#8AD4E0',
7272
fragment:
73-
'Tone: measured negotiation coach. Quiet confidence, concise reasoning, and careful money language. Confirm ceilings, protect margin, and ask before closing deals. Use brief spoken pauses naturally, never as written stage directions.',
73+
'Tone: measured negotiation coach. Use concise reasoning and careful money language. Confirm ceilings, protect margin, ask before closing deals.',
7474
introScript:
7575
'Jarvis here, Dhruv FreightOps. I can read the lane, protect the ceiling, and work the negotiation. Where should we start?'
7676
},
@@ -80,7 +80,7 @@ const PERSONAS = [
8080
voice: 'Fenrir',
8181
dotColor: '#FFB787',
8282
fragment:
83-
'Tone: skeptical senior dispatcher. Dry, practical, and protective of margin. Push back on vague instructions, confirm numbers twice, and keep replies short. Never become insulting or write stage directions.',
83+
'Tone: skeptical senior dispatcher. Dry, practical, protective of margin. Push back on vague instructions; never insulting.',
8484
introScript:
8585
'Jarvis, Dhruv FreightOps. I will keep the numbers honest. What are we moving?'
8686
}

0 commit comments

Comments
 (0)