@audienti/cli 0.2.0-exora.22 → 0.2.0-exora.24
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/cli/audienti.mjs +2 -1
- package/cli/intent.mjs +46 -3
- package/cli/owner-account-client.mjs +3 -2
- package/cli/sender-account-operations.mjs +1 -0
- package/cli/sender-accounts.mjs +4 -4
- package/cli/tools-operations.mjs +1 -0
- package/cli/tools.mjs +2 -2
- package/package.json +1 -1
- package/skills/getting-started/references/replies.md +6 -0
- package/source-manifest.json +10 -10
package/cli/audienti.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const args = process.argv.slice(2);
|
|
|
6
6
|
const usage = `Profiles: audienti profiles list|search|get ID | match evaluate|apply SOURCE CANDIDATE | history RESOLUTION (saved workspace records)
|
|
7
7
|
Skills: audienti skills list [--compact]|show SKILL|read SKILL RESOURCE|helper NAME --file INPUT.json|- [--json]
|
|
8
8
|
Tools: audienti call TOOL ['JSON'] | tools search "WORDS"|get TOOL|list|runs|balance [--help]
|
|
9
|
-
Sender: audienti sender accounts list|get|alias|register|bind|unbind|state|automation|activity report [--profile PATH]
|
|
9
|
+
Sender: audienti sender accounts list|get|alias|register|bind|unbind|state|workspaces|automation|activity report [--profile PATH]
|
|
10
10
|
Managed LinkedIn: audienti sender managed list|connect [--workspace ID] [--profile PATH] (connect: the user only; returns a sign-in link)
|
|
11
11
|
audienti sender managed plan MANAGED_ACCOUNT_ID --plan free|premium_career|premium_business|premium_all_in_one|sales_navigator_core|sales_navigator_advanced|recruiter_lite|none [--workspace ID] (the user only; sets the connection note length; none clears it)
|
|
12
12
|
Prospecting: audienti prospecting settings show|save|accounts|account-show|account-save|history [--profile PATH]
|
|
@@ -81,6 +81,7 @@ Discovery: prospects list|get ID|timeline ID [--limit N]|observation create|cita
|
|
|
81
81
|
usage breakdown [--workspace ID] [--since month|7d|30d|90d] [--by tool|provider|model|caller|day] [--format json|csv]
|
|
82
82
|
workspace usage summary|callers|calls [--after ID] [--caller user:ID|agent:ID|key:ID] [--status all|succeeded|failed|pending]|call ID [--workspace ID] (paid tool use, last 30 days, and single calls)
|
|
83
83
|
intent list [--workspace ID] (the closed set of message labels: name, direction, event, channels, typed detail; output is JSON)
|
|
84
|
+
intent suggest (--text TEXT | --text-file PATH) --channel email|linkedin [--direction inbound|outbound] [--context TEXT] [--request-id UUID] [--workspace ID] (paid: what a message may mean, read by a model; prints the price per 1M input tokens first; suggests labels with a quote and reason, records nothing; keep one with intent record)
|
|
84
85
|
intent record --person ID --evidence ID --label NAME --quote TEXT --reason TEXT [--confidence high|medium|low] [--request-id UUID] [--participation ID] [--workspace ID] (what a stored message means; get EVIDENCE from prospects conversation append|list; --file LABELS.json for several labels or a typed detail such as a stop result or a meeting time; every label is checked and a refusal says what to fix; a message you sent that asks for a meeting takes --label meeting_requested on its outbound evidence)
|
|
85
86
|
audit list [--workspace ID] [--since 7d] [--actor agent|person] [--category NAME] [--format json|csv]
|
|
86
87
|
budgets set --workspace ID [--agent ID --cap N|none] [--new-agent-cap N|none] [--at-limit pause|ask] [--alert80 on|off] (alert80 covers Operator and email at 80%)
|
package/cli/intent.mjs
CHANGED
|
@@ -1,9 +1,50 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { callWorkspace, configuration } from './workspaces.mjs';
|
|
3
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
3
4
|
import { readJsonFile } from './json-file.mjs';
|
|
5
|
+
import { printPaid } from './tools.mjs';
|
|
4
6
|
|
|
5
|
-
const RECORD_FLAGS = ['workspace', 'profile', 'person', 'evidence', 'label', 'quote', 'reason', 'confidence', 'request-id', 'participation', 'file'];
|
|
6
|
-
const
|
|
7
|
+
const RECORD_FLAGS = ['workspace', 'profile', 'person', 'evidence', 'label', 'quote', 'reason', 'confidence', 'request-id', 'participation', 'file', 'text', 'text-file', 'direction', 'channel', 'context'];
|
|
8
|
+
const SUGGEST_FLAGS = ['workspace', 'profile', 'text', 'text-file', 'direction', 'channel', 'context', 'request-id'];
|
|
9
|
+
const TEXT_MAX_BYTES = 16384;
|
|
10
|
+
const TEXT_MAX_CHARACTERS = 4000;
|
|
11
|
+
const CONTEXT_MAX_CHARACTERS = 2000;
|
|
12
|
+
const RECORD_ONLY_OK = ['workspace', 'profile', 'person', 'evidence', 'label', 'quote', 'reason', 'confidence', 'request-id', 'participation', 'file'];
|
|
13
|
+
|
|
14
|
+
function readText(path) {
|
|
15
|
+
let stat;
|
|
16
|
+
try { stat = statSync(path); } catch { throw Error(`Cannot read the message file ${path}. Check the path and try again.`); }
|
|
17
|
+
if (!stat.isFile() || stat.size > TEXT_MAX_BYTES) throw Error(`The message file must be a regular text file no larger than ${TEXT_MAX_BYTES / 1024} KiB: ${path}`);
|
|
18
|
+
try { return new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(path)); } catch { throw Error(`The message file must be UTF-8 text: ${path}`); }
|
|
19
|
+
}
|
|
20
|
+
/** What the person should do after a call that did not give suggestions, in plain words. The JSON above it is for programs. */
|
|
21
|
+
const explain = requestId => result => result?.status === 'rejected'
|
|
22
|
+
? 'Nothing was charged. The call was not accepted. If the reason above is insufficient_credits, add credits in the app under Settings, then Billing, and run the command again.'
|
|
23
|
+
: `The model did not answer, so there are no suggestions. The charge is not settled yet. Run the same command again with --request-id ${requestId} to check or retry: the same request ID is never charged twice.`;
|
|
24
|
+
const money = value => value >= 1 ? value.toFixed(2) : value.toPrecision(2);
|
|
25
|
+
|
|
26
|
+
/** Suggest labels for a message. Paid: shows the price per million input tokens first, then makes the call. Records nothing. */
|
|
27
|
+
async function suggest(flags) {
|
|
28
|
+
if (Object.keys(flags).some(key => !SUGGEST_FLAGS.includes(key))) throw Error('Option does not apply to intent suggest.');
|
|
29
|
+
if ((flags.text === undefined) === (flags['text-file'] === undefined)) throw Error(`Give the message once: --text TEXT or --text-file PATH. ${SUGGEST_USAGE}`);
|
|
30
|
+
if (!flags.channel) throw Error(`--channel is required (for example email or linkedin). ${SUGGEST_USAGE}`);
|
|
31
|
+
const direction = flags.direction ?? 'inbound';
|
|
32
|
+
if (!['inbound', 'outbound'].includes(direction)) throw Error(`--direction must be inbound (a message they sent) or outbound (one we sent). ${SUGGEST_USAGE}`);
|
|
33
|
+
const text = flags.text ?? readText(flags['text-file']);
|
|
34
|
+
if (!text.trim()) throw Error('The message has no words. Give the text of one message.');
|
|
35
|
+
if (Array.from(text).length > TEXT_MAX_CHARACTERS) throw Error(`The message is ${Array.from(text).length} characters; the most is ${TEXT_MAX_CHARACTERS}. Send only the new message, without the quoted thread.`);
|
|
36
|
+
if (flags.context !== undefined && Array.from(flags.context).length > CONTEXT_MAX_CHARACTERS) throw Error(`--context is too long; the most is ${CONTEXT_MAX_CHARACTERS} characters.`);
|
|
37
|
+
const config = configuration(flags.profile);
|
|
38
|
+
const entry = await callWorkspace('tools_get', { workspaceId: flags.workspace, tool: 'audienti.intent.label' }, config);
|
|
39
|
+
const price = entry?.data?.tokenPrice;
|
|
40
|
+
if (!price || typeof price.usd !== 'number') throw Error('Could not read the price of intent suggest. Nothing was charged.');
|
|
41
|
+
process.stderr.write(`Price: ${money(price.credits)} credits (about $${money(price.usd)}) per 1M input tokens. You pay for the tokens measured, so one short message costs a small part of a credit (for example, about ${money(price.credits * 3000 / 1e6)} credits for a 1,000-character message). Output is free. Nothing is recorded.\n`);
|
|
42
|
+
const requestId = flags['request-id'] ?? randomUUID();
|
|
43
|
+
if (!flags['request-id']) process.stderr.write(`request-id: ${requestId}\n`);
|
|
44
|
+
await printPaid('tools_intent_label', { workspaceId: flags.workspace, requestId, input: { text, direction, channel: flags.channel, ...(flags.context ? { context: flags.context } : {}) } }, { profile: flags.profile, explain: explain(requestId) });
|
|
45
|
+
}
|
|
46
|
+
const SUGGEST_USAGE = 'Use: intent suggest (--text TEXT | --text-file PATH) --channel email|linkedin [--direction inbound|outbound] [--context TEXT] [--request-id UUID] [--workspace ID].';
|
|
47
|
+
const USAGE = 'Use intent list [--workspace ID], intent suggest (--text TEXT | --text-file PATH) --channel email|linkedin [--direction inbound|outbound] [--context TEXT] [--request-id UUID] [--workspace ID], or intent record --person ID --evidence ID (--label NAME --quote TEXT --reason TEXT [--confidence high|medium|low] | --file LABELS.json) [--request-id UUID] [--participation ID] [--workspace ID].';
|
|
7
48
|
|
|
8
49
|
export async function intentCli(args) {
|
|
9
50
|
const flags = {}, positions = [];
|
|
@@ -16,12 +57,14 @@ export async function intentCli(args) {
|
|
|
16
57
|
flags[key] = args[++i];
|
|
17
58
|
}
|
|
18
59
|
const command = positions[1];
|
|
19
|
-
if (positions.length !== 2 || positions[0] !== 'intent' || !['list', 'record'].includes(command)) throw Error(USAGE);
|
|
60
|
+
if (positions.length !== 2 || positions[0] !== 'intent' || !['list', 'suggest', 'record'].includes(command)) throw Error(USAGE);
|
|
20
61
|
if (command === 'list') {
|
|
21
62
|
if (Object.keys(flags).some(key => !['workspace', 'profile'].includes(key))) throw Error('Option does not apply to intent list.');
|
|
22
63
|
console.log(JSON.stringify(await callWorkspace('intent_labels_list', { workspaceId: flags.workspace }, configuration(flags.profile))));
|
|
23
64
|
return;
|
|
24
65
|
}
|
|
66
|
+
if (command === 'suggest') { await suggest(flags); return; }
|
|
67
|
+
if (Object.keys(flags).some(key => !RECORD_ONLY_OK.includes(key))) throw Error('Option does not apply to intent record.');
|
|
25
68
|
if (!flags.person || !flags.evidence) throw Error(`--person ID and --evidence ID are required. ${USAGE}`);
|
|
26
69
|
const single = ['label', 'quote', 'reason', 'confidence'].filter(key => flags[key] !== undefined);
|
|
27
70
|
if (flags.file && single.length) throw Error('Give the labels in --file, or one label with --label, --quote and --reason. Not both.');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { configuration,errorGuidance,validateUrl,WorkspaceRequestError } from './workspaces.mjs';
|
|
2
|
-
export async function callOwnerAccountOperation(operation,args,profilePath=process.env.AUDIENTI_PROFILE,label='prospecting settings') {
|
|
2
|
+
export async function callOwnerAccountOperation(operation,args,profilePath=process.env.AUDIENTI_PROFILE,label='prospecting settings',showServerMessage=false) {
|
|
3
3
|
const parsed=operation?.schema.safeParse(args);
|
|
4
4
|
if(!parsed?.success)throw Error(`Invalid ${label} command or fields.`);
|
|
5
5
|
const config=configuration(profilePath,'agents:manage'),profile=config.profile;
|
|
@@ -13,6 +13,7 @@ export async function callOwnerAccountOperation(operation,args,profilePath=proce
|
|
|
13
13
|
const url=validateUrl(config.url);let response;
|
|
14
14
|
try{response=await fetch(new URL('/api/v1'+operation.path(parsed.data),url),{method:operation.method,headers:{Authorization:`Bearer ${config.token}`,Accept:'application/json','Content-Type':'application/json'},...(operation.method==='POST'?{body:JSON.stringify(operation.body?operation.body(parsed.data):parsed.data)}:{}),redirect:'error',signal:AbortSignal.timeout(10000)});}catch{throw Error('Could not reach the API. Redirects are not followed.');}
|
|
15
15
|
let result;try{result=await response.json();}catch{throw Error('The API returned an invalid response.');}
|
|
16
|
-
if(!response.ok){const code=typeof result?.error?.code==='string'&&/^[a-z_]+$/.test(result.error.code)?result.error.code:'request_failed';
|
|
16
|
+
if(!response.ok){const code=typeof result?.error?.code==='string'&&/^[a-z_]+$/.test(result.error.code)?result.error.code:'request_failed';const said=showServerMessage&&typeof result?.error?.message==='string'?result.error.message.trim():'',plain=said&&said.length<=300&&!/[\u0000-\u001f\u007f]/.test(said)&&!said.includes(config.token)?said:'';
|
|
17
|
+
throw new WorkspaceRequestError(response.status,code,plain?`${plain} (${code})`:`${label} request failed: ${code} (HTTP ${response.status}).${response.status===422&&code==='hours_not_narrower'?' An account can only narrow your working hours. Choose hours inside them, or change your own working hours first.':''}`,undefined,undefined,undefined,errorGuidance(result?.error,config.token));}
|
|
17
18
|
if(!result||!Object.hasOwn(result,'data'))throw Error('The API returned an invalid response.');return result;
|
|
18
19
|
}
|
|
@@ -21,6 +21,7 @@ export const senderAccountOperations={
|
|
|
21
21
|
sender_alias_bind:{schema:z.object({...base,...alias,senderAccountId:uuid,agentId:uuid}).strict(),method:'POST',path:a=>path(a)+'/aliases',body,ownerOnly:true},
|
|
22
22
|
sender_alias_unbind:{schema:z.object({...base,...alias,senderAccountId:uuid}).strict(),method:'POST',path:a=>path(a)+'/aliases/unbind',body,ownerOnly:true},
|
|
23
23
|
sender_account_state_set:{schema:z.object({...base,senderAccountId:uuid,expectedVersion:version,state:z.enum(['active','retired'])}).strict(),method:'POST',path:a=>path(a)+'/lifecycle',body,ownerOnly:true},
|
|
24
|
+
sender_account_workspaces_set:{schema:z.object({...base,senderAccountId:uuid,useIn:useIn.describe('Where the account is used from now on, replacing the earlier choice: allWorkspaces true with an empty workspaceIds for all of the user\'s workspaces, or allWorkspaces false with at least one workspace id the user belongs to.')}).strict(),method:'POST',path:a=>path(a)+'/workspaces',body,ownerOnly:true,description:'Changes where an approved sending account is used: all of the user\'s workspaces, or only the listed ones, each a workspace the user belongs to. Replaces the earlier choice. The answer carries useIn, the same shape sender_account_get gives.'},
|
|
24
25
|
sender_automation_get:{schema:z.object({senderAccountId:uuid,actionType}).strict(),method:'GET',path:a=>path(a)+'/automation/'+encodeURIComponent(a.actionType)},
|
|
25
26
|
sender_automation_set:{schema:z.object({...base,senderAccountId:uuid,actionType,expectedVersion:version,enabled:z.boolean()}).strict(),method:'POST',path:a=>path(a)+'/automation/'+encodeURIComponent(a.actionType),body,ownerOnly:true},
|
|
26
27
|
sender_action_modes_get:{schema:z.object({senderAccountId:uuid}).strict(),method:'GET',path:a=>path(a)+'/action-modes'},
|
package/cli/sender-accounts.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {callOwnerAccountOperation} from './owner-account-client.mjs';
|
|
|
3
3
|
import {readJsonFile} from './json-file.mjs';
|
|
4
4
|
import {WorkspaceRequestError,callWorkspace,configuration} from './workspaces.mjs';
|
|
5
5
|
export async function callSenderAccounts(name,args,profilePath){
|
|
6
|
-
return callOwnerAccountOperation(senderAccountOperations[name],args,profilePath,'sender account');
|
|
6
|
+
return callOwnerAccountOperation(senderAccountOperations[name],args,profilePath,'sender account',true);
|
|
7
7
|
}
|
|
8
8
|
export async function senderAccountsCli(args){
|
|
9
9
|
const flags={},positions=[];const known=['profile','file','cursor','limit','aliases-cursor','aliases-limit','history-cursor','history-limit','action-type','capability','provider','account-ref','workspace','plan'];
|
|
@@ -18,11 +18,11 @@ export async function senderAccountsCli(args){
|
|
|
18
18
|
if(!names[positions[2]]||positions.length!==3||Object.keys(flags).some(key=>!['profile','workspace'].includes(key)))throw Error('Use sender managed list|connect|plan [--workspace ID] [--profile PATH].');
|
|
19
19
|
console.log(JSON.stringify(await callWorkspace(names[positions[2]],{workspaceId:flags.workspace},configuration(flags.profile??process.env.AUDIENTI_PROFILE))));return;
|
|
20
20
|
}
|
|
21
|
-
if(positions[0]!=='sender'||positions[1]!=='accounts')throw Error('Use sender accounts list|get|alias|register|bind|unbind|state|automation|modes.');
|
|
21
|
+
if(positions[0]!=='sender'||positions[1]!=='accounts')throw Error('Use sender accounts list|get|alias|register|bind|unbind|state|workspaces|automation|modes.');
|
|
22
22
|
const automation=positions[2]==='automation',modes=positions[2]==='modes',activity=positions[2]==='activity',nested=automation||modes||activity,command=nested?`${positions[2]}-${positions[3]}`:positions[2];
|
|
23
|
-
const names={'activity-report':'sender_activity_report',alias:'sender_alias_get',list:'sender_accounts_list',get:'sender_account_get',register:'sender_account_register',bind:'sender_alias_bind',unbind:'sender_alias_unbind',state:'sender_account_state_set','automation-get':'sender_automation_get','automation-set':'sender_automation_set','modes-get':'sender_action_modes_get','modes-set':'sender_action_mode_set'};
|
|
23
|
+
const names={'activity-report':'sender_activity_report',alias:'sender_alias_get',list:'sender_accounts_list',get:'sender_account_get',register:'sender_account_register',bind:'sender_alias_bind',unbind:'sender_alias_unbind',state:'sender_account_state_set',workspaces:'sender_account_workspaces_set','automation-get':'sender_automation_get','automation-set':'sender_automation_set','modes-get':'sender_action_modes_get','modes-set':'sender_action_mode_set'};
|
|
24
24
|
const name=names[command];if(!name)throw Error('Unknown sender account command.');
|
|
25
|
-
const operation=senderAccountOperations[name],hasId=!['list','register','alias'].includes(command),expected=nested?5:hasId?4:3;if(positions.length!==expected)throw Error('Unexpected sender arguments.');
|
|
25
|
+
const operation=senderAccountOperations[name],hasId=!['list','register','alias'].includes(command),expected=nested?5:hasId?4:3;if(positions.length!==expected)throw Error('Unexpected sender arguments.'+(command==='workspaces'?' Use sender accounts workspaces ACCOUNT_ID --file scope.json [--profile PATH].':''));
|
|
26
26
|
const allowed=['profile',...(operation.method==='POST'?['file']:command==='alias'?['provider','account-ref']:command==='list'?['cursor','limit']:command==='get'?['aliases-cursor','aliases-limit','history-cursor','history-limit']:[]),...(automation?['action-type']:[]),...(command==='modes-set'?['capability']:[])];
|
|
27
27
|
if(Object.keys(flags).some(key=>!allowed.includes(key)))throw Error('Option does not apply to this sender command.');
|
|
28
28
|
let input={};if(operation.method==='POST'){if(!flags.file)throw Error('--file INPUT.json is required.');input=readJsonFile(flags.file,65536,'Sender input');if(!input||typeof input!=='object'||Array.isArray(input))throw Error('invalid_fields: input must be a JSON object.');if(Object.hasOwn(input,'senderAccountId')||Object.hasOwn(input,'actionType')||Object.hasOwn(input,'capability')||Object.hasOwn(input,'workspaceId'))throw Error('Path IDs and workspaceId are not allowed in the file.');}
|
package/cli/tools-operations.mjs
CHANGED
|
@@ -43,6 +43,7 @@ export const hostedToolOperations = {
|
|
|
43
43
|
tools_proxy_sessions_create:{tool:'proxy.sessions.create',paid:true,limits:{maxSeconds:3600,concurrentWorkspaceConnections:32,meter:'upstream_tcp_payload_bytes'},schema:z.object({...workspace,requestId:uuid,input:z.object({ttlSeconds:z.number().int().min(60).max(3600).optional(),parentOperationId:uuid.optional()}).strict()}).strict(),method:'POST',path:a=>root(a)+'/proxy.sessions.create',body:a=>({requestId:a.requestId,input:a.input}),scoped:true,timeoutMs:30000},
|
|
44
44
|
tools_proxy_sessions_close:{tool:'proxy.sessions.close',schema:z.object({...workspace,operationId:uuid}).strict(),method:'POST',path:a=>root(a)+'/proxy.sessions.close',body:a=>({operationId:a.operationId}),scoped:true},
|
|
45
45
|
tools_decide:{tool:'decide',paid:true,schema:z.object({...workspace,requestId:uuid,input:z.object({state:z.union([z.string(),z.record(z.string(),z.unknown()),z.array(z.unknown())]),questions:z.record(key,question).refine(v=>Object.keys(v).length>=1&&Object.keys(v).length<=16)}).strict()}).strict(),method:'POST',path:a=>root(a)+'/decide',body:a=>({requestId:a.requestId,input:a.input}),scoped:true,timeoutMs:30000},
|
|
46
|
+
tools_intent_label:{tool:'intent.label',paid:true,limits:{textCharacters:4000,contextCharacters:2000,suggestions:2},description:'Suggest what a message means. Paid: built on decide, billed on the input tokens the provider measures at the decide price (read it first with tools_get audienti.intent.label: tokenPrice). Give the message text, direction (inbound or outbound) and channel, and optionally context. Returns up to two suggestions from the intent label list (one reading, one meeting label), each with a quote that is words of the message, a plain reason, a confidence and any typed detail still to add (needs). Records nothing and sends nothing: record a suggestion you keep with intent_record, which runs every check again. Reuse requestId after any interruption; a replay is free.',schema:z.object({...workspace,requestId:uuid,input:z.object({text:z.string().min(1).max(4000),direction:z.enum(['inbound','outbound']),channel:z.enum(['email','linkedin']),context:z.string().trim().min(1).max(2000).optional()}).strict()}).strict(),method:'POST',path:a=>root(a)+'/intent.label',body:a=>({requestId:a.requestId,input:a.input}),scoped:true,timeoutMs:30000},
|
|
46
47
|
tools_profiles_fetch:{tool:'profiles.fetch',paid:true,schema:z.object({...workspace,requestId:uuid,input:z.object({url:z.string().min(1).max(1024),refresh:z.boolean().optional(),cached:z.boolean().optional(),fields:z.array(z.enum(['name','headline','about','location','experience','currentPositions','education','skills','websites','photo','connections','followers','certifications','languages','industries','employeeCount','employeeCountRange','founded','specialities','locations','companyType'])).min(1).max(20).optional()}).strict()}).strict(),method:'POST',path:a=>root(a)+'/profiles.fetch',body:a=>({requestId:a.requestId,input:a.input}),scoped:true,timeoutMs:30000},
|
|
47
48
|
tools_runs_get:{schema:z.object({...workspace,operationId:uuid,attemptAfter:z.number().int().min(0).max(2147483647).optional(),entryAfter:uuid.optional()}).strict(),method:'GET',path:a=>root(a)+`/runs/${a.operationId}`+((a.attemptAfter!==undefined||a.entryAfter)?`?${new URLSearchParams({...a.attemptAfter!==undefined?{attemptAfter:String(a.attemptAfter)}:{},...a.entryAfter?{entryAfter:a.entryAfter}:{}})}`:''),scoped:true},
|
|
48
49
|
tools_runs_list:{schema:z.object({...workspace,cursor:uuid.optional()}).strict(),method:'GET',path:a=>root(a)+'/runs'+(a.cursor?`?cursor=${encodeURIComponent(a.cursor)}`:''),scoped:true},
|
package/cli/tools.mjs
CHANGED
|
@@ -54,12 +54,12 @@ async function readStdin() {
|
|
|
54
54
|
try{return JSON.parse(new TextDecoder('utf-8',{fatal:true}).decode(Buffer.concat(chunks)));}catch{throw new Error('Tool input must be valid UTF-8 JSON.');}
|
|
55
55
|
}
|
|
56
56
|
const asJson=value=>{try{return JSON.parse(value);}catch{throw new Error('Tool input must be valid JSON.');}};
|
|
57
|
-
async function printPaid(name,args,values){
|
|
57
|
+
export async function printPaid(name,args,values){
|
|
58
58
|
try{
|
|
59
59
|
const result=await callWorkspace(name,args,configuration(values.profile));
|
|
60
60
|
const paidResult=paidToolResult(name,result?.data,args);
|
|
61
61
|
if(['failed','uncertain','rejected'].includes(paidResult?.status)){
|
|
62
|
-
process.stderr.write(JSON.stringify({error:{code:paidResult.error?.code??'tool_incomplete'},operationId:paidResult.operationId,requestId:args.requestId,billing:paidResult.billing,...(paidResult.result?.persistence?{result:paidResult.result}:{}),requestTraceId:result.requestTraceId,recovery:paidResult.status==='rejected'?'resolve_rejection_then_new_request_id':paidResult.result?.persistence?.recovery??'retry_same_request_id'})+'\n');process.exitCode=1;return;
|
|
62
|
+
process.stderr.write(JSON.stringify({error:{code:paidResult.error?.code??'tool_incomplete'},operationId:paidResult.operationId,requestId:args.requestId,billing:paidResult.billing,...(paidResult.result?.persistence?{result:paidResult.result}:{}),requestTraceId:result.requestTraceId,recovery:paidResult.status==='rejected'?'resolve_rejection_then_new_request_id':paidResult.result?.persistence?.recovery??'retry_same_request_id'})+'\n');if(values.explain)process.stderr.write(values.explain(paidResult)+'\n');process.exitCode=1;return;
|
|
63
63
|
}
|
|
64
64
|
console.log(JSON.stringify(result));
|
|
65
65
|
}catch(error){
|
package/package.json
CHANGED
|
@@ -113,6 +113,12 @@ values and the `next` step. The checks:
|
|
|
113
113
|
reply and at most one meeting label.
|
|
114
114
|
- The typed detail is present: a `stop`, `bounce` or `referral` needs its `result`; `meeting_booked` needs `meeting`.
|
|
115
115
|
|
|
116
|
+
To get a second reading before you record, `audienti intent suggest --channel email --text "..."` asks a model
|
|
117
|
+
to suggest labels. It costs credits: the call prints the price per million input tokens first, and a message
|
|
118
|
+
uses a small part of that. It returns up to two suggestions, each with a `quote`, a `reason`, a `confidence` and
|
|
119
|
+
`needs` (the typed detail to add, for example the `scope` of a stop). It records nothing. Keep, change or drop
|
|
120
|
+
a suggestion, then record it with `intent record`, which runs every check above again.
|
|
121
|
+
|
|
116
122
|
`replies set` records the same labels. Add `"intent": {"quote": "...", "reason": "..."}` next to `classification`
|
|
117
123
|
or `meetingState` and it runs the same checks and stores the words on the event. Without `intent` it works as before.
|
|
118
124
|
|
package/source-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repository": "https://github.com/omalab/exora",
|
|
3
|
-
"sourceCommit": "
|
|
3
|
+
"sourceCommit": "c3617a64f6e2edcd7a7edcdee344c6a77e69a8cf",
|
|
4
4
|
"files": {
|
|
5
5
|
"LICENSE": "220f297cfcd5c38eb64e6b4b4a77cab4ebc7f4686d4d99c6260a475d02ca11e5",
|
|
6
6
|
"README.md": "7ff32cc8ac89dd54b64d7b39c0b41b1f37e154b7ea10ad5a7bceefc3df77d87f",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"cli/attachments.mjs": "2fee6b4abbf82da9847d4a927a3d4d3ca947a198a903a78927596a2ea858cbf4",
|
|
17
17
|
"cli/audience-operations.mjs": "133b72dc6b9e3a6b4f173ce28f1524163f9c7b049505b885115f83b9e4af7170",
|
|
18
18
|
"cli/audiences.mjs": "3c377346efc1a8bdde432a16c2d19a3f51f34f3333d344d3a2bfa94c188a017d",
|
|
19
|
-
"cli/audienti.mjs": "
|
|
19
|
+
"cli/audienti.mjs": "02731f5d6852b858940af662966bf42d414b97e9bd7fbe9bd0f036a4b967b0fe",
|
|
20
20
|
"cli/audit-operations.mjs": "afaf87d592a1e5f6bff2a8649a6a64a8f471950b7d99e98995d9205aa5910398",
|
|
21
21
|
"cli/audit.mjs": "a7becaed67c58b063e668b5e66844b6dc15c11a63b428faa171b542ad922c001",
|
|
22
22
|
"cli/budget-operations.mjs": "d74916551ef393e29734c6e13cf9021251e0ed126eeaa529e18cf2332146e1e0",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"cli/hand-task-operations.mjs": "473473fe95324c8c8733e037feab5ac468c07b0658fabd739cfd7d400a7faa83",
|
|
38
38
|
"cli/hand-tasks.mjs": "2c895cf6b30c594a7e27cc4ec4b7eddeb39f941cd195b9255c6e0d6b4a56371f",
|
|
39
39
|
"cli/intent-operations.mjs": "97b08e7474cf0fd8201650f08fa5ca5a2be2b0ddf5ea2079eb644e21aa2a0153",
|
|
40
|
-
"cli/intent.mjs": "
|
|
40
|
+
"cli/intent.mjs": "5aa62593f65f58f2714bb402365624005ae17f73f65da3952b06f45e3c109450",
|
|
41
41
|
"cli/json-file.mjs": "96431b18215834c2531f5901e2526875c634dd2e85a9465fcffc937fbec52150",
|
|
42
42
|
"cli/kv-operations.mjs": "505d79d0d535d3441883f8a37817c30c73367216a35dddb07181f0f0e799df79",
|
|
43
43
|
"cli/kv.mjs": "05783610001dd002af07a4bb8f26e64d74aa4981bbe38a2100552b810cb3bc72",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"cli/outbound.mjs": "23903eb0fec4d7af3aa0031d63488ed9a8697e07ccf1314d194b48e109d15f82",
|
|
50
50
|
"cli/outcome-operations.mjs": "cf133097799f240a006264a38a4c6bd4094078d6dec78a71679700ac3bdeacd5",
|
|
51
51
|
"cli/outcomes.mjs": "765ccb112a90fc4d228b2a41e5e19c5e1f3e2fe14bc1d8128b0090fc95cdbf3f",
|
|
52
|
-
"cli/owner-account-client.mjs": "
|
|
52
|
+
"cli/owner-account-client.mjs": "aa2790fd3c16714b1a82922fe13012f261cced99025d692bca5d0c605a717cd1",
|
|
53
53
|
"cli/playbook-help.mjs": "dad00cae19eb107f84c7934812800431535c6cf1dbcdcdd22c16522cfaddadf3",
|
|
54
54
|
"cli/playbook-operations.mjs": "431738b47b56091e10f0466f03673c602ae00653f8b455a20d39a8242d845e21",
|
|
55
55
|
"cli/profiles.mjs": "45929b224ffc916b6dbd7a94e06ac09a1ff7feec430633b10d160c1608fc2d32",
|
|
@@ -67,14 +67,14 @@
|
|
|
67
67
|
"cli/search-operations.mjs": "903f12fffb6824872160c4136925ab5638142bb4e39236b37f927cd2c6a43776",
|
|
68
68
|
"cli/secret-operations.mjs": "faefe9c9ece81087dc7aab32e88f331ed942d0757ce5a978b5f0722d514f377f",
|
|
69
69
|
"cli/secrets.mjs": "cab4ea932e724ce3c807c7825869810b44fb8d75cdacec32f8101353f0e7c5f5",
|
|
70
|
-
"cli/sender-account-operations.mjs": "
|
|
71
|
-
"cli/sender-accounts.mjs": "
|
|
70
|
+
"cli/sender-account-operations.mjs": "cf1c04e6289937611f5bd666953389c96887881f2b46203d79b9d8f57c55f3b2",
|
|
71
|
+
"cli/sender-accounts.mjs": "febe2a21f8cda4999e14eb78c01e9924dcc1914ff3c5cadcd845b7dbc4523491",
|
|
72
72
|
"cli/skills-mcp.mjs": "6a91b16a789f50035ae0fe33f8ae2758bb9829949db7efb05c6d65dde335a9e0",
|
|
73
73
|
"cli/skills.mjs": "ea8dfef32664714f9c63251d9a6bbdb44d77d41e272df46bb102ebfcd8df8b66",
|
|
74
74
|
"cli/suppression-operations.mjs": "d1f827a785670fc6e44d87b18e4cfb6596b09e5be7c4f84c4b9a75ed13a962c6",
|
|
75
75
|
"cli/suppression.mjs": "2b10be67e290deec9ed915139c3d98d45d7d10fd41abb67b5a35a630d636a4ed",
|
|
76
|
-
"cli/tools-operations.mjs": "
|
|
77
|
-
"cli/tools.mjs": "
|
|
76
|
+
"cli/tools-operations.mjs": "f64e58f75ef0c02b9317c6b6e07ccc7b9891464cf29824cee75f0fcae9026eb2",
|
|
77
|
+
"cli/tools.mjs": "16967f23a2b2460d28e766c827721a254e83d34b2df5195981cc9f899f6a5ed0",
|
|
78
78
|
"cli/usage-operations.mjs": "64dd1ae850f52bb72c7648be78a8ab2dfab986afba2d2d2cd08034c4f7b3ace6",
|
|
79
79
|
"cli/usage.mjs": "cd582c061f83ca4f220ddd3cd2a174a1a3a3c0ee308b3d5a5f47752a501e322e",
|
|
80
80
|
"cli/work-execution-operations.mjs": "842d706b36bb035aa54e1dee8bf950f0619c495bcae84faa1926fbb05f6842bc",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"cli/work-operations.mjs": "8b3a84ca15e8e4ad79ef92ced4c5adaffd5129f630e3bfc2c74a844a90867600",
|
|
85
85
|
"cli/work.mjs": "751107ecc3de5a6be9db4a068cddc41f3ad8e77c87e59686eaf522862caf9e9f",
|
|
86
86
|
"cli/workspaces.mjs": "eebe2c4bfc6ddedb2fb0dd551d5fa348eeda2fdf2105babd514b29a97f4d6225",
|
|
87
|
-
"package.json": "
|
|
87
|
+
"package.json": "fd3900114d654f8923fa54c3a13d7fa1323f757d5cca4d26074c746d3b81e264",
|
|
88
88
|
"skills/agent-rooms/SKILL.md": "08f917ff85fee1d23499a4499056ce845b39ce6727029b104819dad41ee87cc2",
|
|
89
89
|
"skills/agent-rooms/references/commands.md": "ef5afa5543ca9da967a147f638774647998ea1c1a2a821959f3bf87d54c292bd",
|
|
90
90
|
"skills/audienti/SKILL.md": "8f2124065bfc3a005b44e194e7dcce9bbf14062ab332e7db66d441eeccb518ed",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"skills/getting-started/references/capabilities.md": "982e3583a47ba4ac832efae2f6af3a4d8c0c18cace159c76b2a4ad1a8d8e910e",
|
|
101
101
|
"skills/getting-started/references/mailbox-check.md": "113574bb5a573125620dcde4e65ebf44164f7b0727cc936fb41234f5d57bba73",
|
|
102
102
|
"skills/getting-started/references/outcome-checks.md": "094d09d231b38d4935aa9eb8ac089e46ba8e698489852fa97040e6b5eac77a9b",
|
|
103
|
-
"skills/getting-started/references/replies.md": "
|
|
103
|
+
"skills/getting-started/references/replies.md": "acb5b77833cd9272ffeb05c27c24f9f2a8b1723da4e9a25cd6e8e6e666db2865",
|
|
104
104
|
"skills/getting-started/references/reply-checks.md": "85fe692ad6b7bc73e204de313b27d225be3da1a0af71e8e7bb9945ae511a0dc3",
|
|
105
105
|
"skills/playbook-design/SKILL.md": "56aa5692c1bbe3843f11819f0f9270988ddd0424b16f38db72a854864155407f",
|
|
106
106
|
"skills/playbook-design/references/fields.md": "7af0c8a2ad7b2ee83ff006fe4707a90c3edacdb8ccf83c09fa17f692b5fa2c81"
|