@sulala/agent 0.1.39 → 0.1.41
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/README.md +7 -1
- package/bin/sulala copy.mjs +7 -0
- package/bin/sulala.mjs +10 -4
- package/dashboard/dist/assets/index-CpWzBXHV.js +88 -0
- package/dashboard/dist/assets/index-DUAWeMLm.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/agent/content-writer-agent.d.ts +52 -0
- package/dist/agent/content-writer-agent.d.ts.map +1 -0
- package/dist/agent/content-writer-agent.js +271 -0
- package/dist/agent/content-writer-agent.js.map +1 -0
- package/dist/agent/execution-context.d.ts +45 -0
- package/dist/agent/execution-context.d.ts.map +1 -0
- package/dist/agent/execution-context.js +31 -0
- package/dist/agent/execution-context.js.map +1 -0
- package/dist/agent/lead-agent-schedule.d.ts +10 -0
- package/dist/agent/lead-agent-schedule.d.ts.map +1 -0
- package/dist/agent/lead-agent-schedule.js +49 -0
- package/dist/agent/lead-agent-schedule.js.map +1 -0
- package/dist/agent/lead-agent.d.ts +60 -0
- package/dist/agent/lead-agent.d.ts.map +1 -0
- package/dist/agent/lead-agent.js +205 -0
- package/dist/agent/lead-agent.js.map +1 -0
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +66 -21
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/news-social-agent-schedule.d.ts +5 -0
- package/dist/agent/news-social-agent-schedule.d.ts.map +1 -0
- package/dist/agent/news-social-agent-schedule.js +42 -0
- package/dist/agent/news-social-agent-schedule.js.map +1 -0
- package/dist/agent/news-social-agent.d.ts +52 -0
- package/dist/agent/news-social-agent.d.ts.map +1 -0
- package/dist/agent/news-social-agent.js +199 -0
- package/dist/agent/news-social-agent.js.map +1 -0
- package/dist/agent/run-cancel.d.ts +20 -0
- package/dist/agent/run-cancel.d.ts.map +1 -0
- package/dist/agent/run-cancel.js +38 -0
- package/dist/agent/run-cancel.js.map +1 -0
- package/dist/agent/skills.d.ts.map +1 -1
- package/dist/agent/skills.js +97 -118
- package/dist/agent/skills.js.map +1 -1
- package/dist/agent/social-agent.d.ts +46 -0
- package/dist/agent/social-agent.d.ts.map +1 -0
- package/dist/agent/social-agent.js +199 -0
- package/dist/agent/social-agent.js.map +1 -0
- package/dist/agent/tool/spec-loader.d.ts.map +1 -1
- package/dist/agent/tool/spec-loader.js +62 -8
- package/dist/agent/tool/spec-loader.js.map +1 -1
- package/dist/agent/tools.d.ts.map +1 -1
- package/dist/agent/tools.js +204 -4
- package/dist/agent/tools.js.map +1 -1
- package/dist/agent/workflow-agents-schedule.d.ts +14 -0
- package/dist/agent/workflow-agents-schedule.d.ts.map +1 -0
- package/dist/agent/workflow-agents-schedule.js +46 -0
- package/dist/agent/workflow-agents-schedule.js.map +1 -0
- package/dist/agent/workflow-agents.d.ts +38 -0
- package/dist/agent/workflow-agents.d.ts.map +1 -0
- package/dist/agent/workflow-agents.js +155 -0
- package/dist/agent/workflow-agents.js.map +1 -0
- package/dist/agent/workflow-folder.d.ts +18 -0
- package/dist/agent/workflow-folder.d.ts.map +1 -0
- package/dist/agent/workflow-folder.js +57 -0
- package/dist/agent/workflow-folder.js.map +1 -0
- package/dist/agent/workflow-runner.d.ts +16 -0
- package/dist/agent/workflow-runner.d.ts.map +1 -0
- package/dist/agent/workflow-runner.js +163 -0
- package/dist/agent/workflow-runner.js.map +1 -0
- package/dist/channels/telegram.d.ts +15 -0
- package/dist/channels/telegram.d.ts.map +1 -1
- package/dist/channels/telegram.js +100 -0
- package/dist/channels/telegram.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +74 -2
- package/dist/config.js.map +1 -1
- package/dist/db/index.d.ts +78 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +279 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema.sql +47 -0
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/gateway/server.js +1057 -13
- package/dist/gateway/server.js.map +1 -1
- package/dist/index.js +315 -2
- package/dist/index.js.map +1 -1
- package/dist/media/upload-handlers/dropbox.d.ts +2 -0
- package/dist/media/upload-handlers/dropbox.d.ts.map +1 -0
- package/dist/media/upload-handlers/dropbox.js +67 -0
- package/dist/media/upload-handlers/dropbox.js.map +1 -0
- package/dist/onboard-env.d.ts +9 -1
- package/dist/onboard-env.d.ts.map +1 -1
- package/dist/onboard-env.js +15 -1
- package/dist/onboard-env.js.map +1 -1
- package/dist/onboard.d.ts.map +1 -1
- package/dist/onboard.js +7 -0
- package/dist/onboard.js.map +1 -1
- package/dist/tailscale.d.ts +5 -0
- package/dist/tailscale.d.ts.map +1 -0
- package/dist/tailscale.js +36 -0
- package/dist/tailscale.js.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -2
- package/src/db/schema.sql +47 -0
- package/src/index.ts +326 -2
- package/dashboard/dist/assets/index-C-H2KUVU.js +0 -88
- package/dashboard/dist/assets/index-CG6dieHw.css +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Lead Agent schedule configuration.
|
|
3
|
+
* This ensures the Lead Agent runs on a configurable cron schedule.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Ensure the Lead Agent is scheduled to run autonomously.
|
|
7
|
+
* Called at startup to initialize the default schedule if not already present.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureLeadAgentSchedule(): void;
|
|
10
|
+
//# sourceMappingURL=lead-agent-schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-agent-schedule.d.ts","sourceRoot":"","sources":["../../src/agent/lead-agent-schedule.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAoC9C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Lead Agent schedule configuration.
|
|
3
|
+
* This ensures the Lead Agent runs on a configurable cron schedule.
|
|
4
|
+
*/
|
|
5
|
+
import { getAgentBySlug, listScheduledJobs, insertScheduledJob } from '../db/index.js';
|
|
6
|
+
import { log } from '../db/index.js';
|
|
7
|
+
const LEAD_AGENT_SCHEDULE_ID = 'lead-agent-daily';
|
|
8
|
+
const DEFAULT_LEAD_AGENT_CRON = '0 8 * * *'; // Daily at 08:00 UTC
|
|
9
|
+
/**
|
|
10
|
+
* Ensure the Lead Agent is scheduled to run autonomously.
|
|
11
|
+
* Called at startup to initialize the default schedule if not already present.
|
|
12
|
+
*/
|
|
13
|
+
export function ensureLeadAgentSchedule() {
|
|
14
|
+
const agent = getAgentBySlug('lead-agent');
|
|
15
|
+
if (!agent || !agent.enabled) {
|
|
16
|
+
log('lead-agent', 'info', 'Lead Agent not enabled, skipping schedule setup');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// Check if schedule already exists
|
|
20
|
+
const existing = listScheduledJobs(false).find((j) => j.id === LEAD_AGENT_SCHEDULE_ID);
|
|
21
|
+
if (existing) {
|
|
22
|
+
log('lead-agent', 'debug', 'Lead Agent schedule already exists');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Create default schedule
|
|
26
|
+
try {
|
|
27
|
+
insertScheduledJob({
|
|
28
|
+
id: LEAD_AGENT_SCHEDULE_ID,
|
|
29
|
+
name: 'Lead Agent Daily Run',
|
|
30
|
+
description: 'Autonomous lead generation and reporting (daily at 08:00 UTC)',
|
|
31
|
+
cron_expression: DEFAULT_LEAD_AGENT_CRON,
|
|
32
|
+
task_type: 'lead_agent_run',
|
|
33
|
+
payload: JSON.stringify({
|
|
34
|
+
agentId: agent.id,
|
|
35
|
+
provider: agent.default_provider || 'openai',
|
|
36
|
+
model: agent.default_model || 'gpt-4o-mini',
|
|
37
|
+
}),
|
|
38
|
+
enabled: 1,
|
|
39
|
+
});
|
|
40
|
+
log('lead-agent', 'info', 'Lead Agent schedule created', {
|
|
41
|
+
scheduleId: LEAD_AGENT_SCHEDULE_ID,
|
|
42
|
+
cron: DEFAULT_LEAD_AGENT_CRON,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
log('lead-agent', 'error', `Failed to create Lead Agent schedule: ${err instanceof Error ? err.message : String(err)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=lead-agent-schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-agent-schedule.js","sourceRoot":"","sources":["../../src/agent/lead-agent-schedule.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAClD,MAAM,uBAAuB,GAAG,WAAW,CAAC,CAAC,qBAAqB;AAElE;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,KAAK,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7B,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,iDAAiD,CAAC,CAAC;QAC7E,OAAO;IACT,CAAC;IAED,mCAAmC;IACnC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,sBAAsB,CAAC,CAAC;IACvF,IAAI,QAAQ,EAAE,CAAC;QACb,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,oCAAoC,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,0BAA0B;IAC1B,IAAI,CAAC;QACH,kBAAkB,CAAC;YACjB,EAAE,EAAE,sBAAsB;YAC1B,IAAI,EAAE,sBAAsB;YAC5B,WAAW,EAAE,+DAA+D;YAC5E,eAAe,EAAE,uBAAuB;YACxC,SAAS,EAAE,gBAAgB;YAC3B,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;gBACtB,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,QAAQ,EAAE,KAAK,CAAC,gBAAgB,IAAI,QAAQ;gBAC5C,KAAK,EAAE,KAAK,CAAC,aAAa,IAAI,aAAa;aAC5C,CAAC;YACF,OAAO,EAAE,CAAC;SACX,CAAC,CAAC;QACH,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,6BAA6B,EAAE;YACvD,UAAU,EAAE,sBAAsB;YAClC,IAAI,EAAE,uBAAuB;SAC9B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,yCAAyC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1H,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead Agent Workflow — autonomous lead generation and reporting.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline:
|
|
5
|
+
* 1. Recall ICP and past leads from memory
|
|
6
|
+
* 2. Search for new potential leads
|
|
7
|
+
* 3. Score and deduplicate leads
|
|
8
|
+
* 4. Store in knowledge graph and memory
|
|
9
|
+
* 5. Generate and save report
|
|
10
|
+
* 6. Record metrics
|
|
11
|
+
*/
|
|
12
|
+
import { type AgentStreamEvent } from './loop.js';
|
|
13
|
+
export interface LeadAgentWorkflowOptions {
|
|
14
|
+
/** Session ID for the workflow run. */
|
|
15
|
+
sessionId: string;
|
|
16
|
+
/** Optional user ID. */
|
|
17
|
+
userId?: string;
|
|
18
|
+
/** Override provider (defaults to agent's default_provider). */
|
|
19
|
+
provider?: string;
|
|
20
|
+
/** Override model (defaults to agent's default_model). */
|
|
21
|
+
model?: string;
|
|
22
|
+
/** Max execution time in ms. */
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
/** Optional abort signal for cancellation. */
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
/** When set, workflow uses streaming and calls this for each event (for live UI). */
|
|
27
|
+
onStreamEvent?: (ev: AgentStreamEvent) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface LeadAgentWorkflowResult {
|
|
30
|
+
success: boolean;
|
|
31
|
+
turnCount: number;
|
|
32
|
+
leadsFound: number;
|
|
33
|
+
message: string;
|
|
34
|
+
reportPath?: string;
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
37
|
+
export type OutputDestination = 'file' | 'google_sheet' | 'google_doc';
|
|
38
|
+
export interface LeadAgentSetup {
|
|
39
|
+
targetIndustry: string;
|
|
40
|
+
targetRole: string;
|
|
41
|
+
companySize: 'any' | 'startup' | 'smb' | 'enterprise';
|
|
42
|
+
leadSource: 'web_search' | 'custom';
|
|
43
|
+
numLeads: number;
|
|
44
|
+
geographicFocus: string;
|
|
45
|
+
enrichmentDepth: 'basic' | 'standard' | 'deep';
|
|
46
|
+
/** Where to save the leads report. 'file' = file_write (always available). */
|
|
47
|
+
outputDestination: OutputDestination;
|
|
48
|
+
/** Optional: spreadsheet ID for Google Sheets (from URL docs.google.com/spreadsheets/d/ID) */
|
|
49
|
+
spreadsheetId?: string;
|
|
50
|
+
/** Optional: document ID for Google Docs (from URL docs.google.com/document/d/ID) */
|
|
51
|
+
documentId?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Run the Lead Agent workflow.
|
|
55
|
+
*
|
|
56
|
+
* Sends a system prompt + user instruction to guide the agent through the pipeline.
|
|
57
|
+
* Workflow is autonomous: the agent decides when to call tools and when to finish.
|
|
58
|
+
*/
|
|
59
|
+
export declare function runLeadAgentWorkflow(_agentId: string, options: LeadAgentWorkflowOptions): Promise<LeadAgentWorkflowResult>;
|
|
60
|
+
//# sourceMappingURL=lead-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-agent.d.ts","sourceRoot":"","sources":["../../src/agent/lead-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAoC,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAGpF,MAAM,WAAW,wBAAwB;IACvC,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAElB,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB,qFAAqF;IACrF,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,cAAc,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,YAAY,CAAC;IACtD,UAAU,EAAE,YAAY,GAAG,QAAQ,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;IAC/C,8EAA8E;IAC9E,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,8FAA8F;IAC9F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiGD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC,CA2FlC"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead Agent Workflow — autonomous lead generation and reporting.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline:
|
|
5
|
+
* 1. Recall ICP and past leads from memory
|
|
6
|
+
* 2. Search for new potential leads
|
|
7
|
+
* 3. Score and deduplicate leads
|
|
8
|
+
* 4. Store in knowledge graph and memory
|
|
9
|
+
* 5. Generate and save report
|
|
10
|
+
* 6. Record metrics
|
|
11
|
+
*/
|
|
12
|
+
import { recordAgentMetric, getAgentBySlug, getChannelConfig } from '../db/index.js';
|
|
13
|
+
import { runAgentTurn, runAgentTurnStream } from './loop.js';
|
|
14
|
+
import { log } from '../db/index.js';
|
|
15
|
+
const LEAD_AGENT_SETUP_KEY = 'lead_agent_setup';
|
|
16
|
+
function getLeadAgentSetup() {
|
|
17
|
+
const raw = getChannelConfig(LEAD_AGENT_SETUP_KEY);
|
|
18
|
+
if (!raw?.trim()) {
|
|
19
|
+
return {
|
|
20
|
+
targetIndustry: '',
|
|
21
|
+
targetRole: '',
|
|
22
|
+
companySize: 'any',
|
|
23
|
+
leadSource: 'web_search',
|
|
24
|
+
numLeads: 10,
|
|
25
|
+
geographicFocus: '',
|
|
26
|
+
enrichmentDepth: 'standard',
|
|
27
|
+
outputDestination: 'file',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const o = JSON.parse(raw);
|
|
32
|
+
const dest = ['file', 'google_sheet', 'google_doc'].includes(String(o.outputDestination))
|
|
33
|
+
? o.outputDestination
|
|
34
|
+
: 'file';
|
|
35
|
+
return {
|
|
36
|
+
targetIndustry: typeof o.targetIndustry === 'string' ? o.targetIndustry : '',
|
|
37
|
+
targetRole: typeof o.targetRole === 'string' ? o.targetRole : '',
|
|
38
|
+
companySize: ['any', 'startup', 'smb', 'enterprise'].includes(String(o.companySize)) ? o.companySize : 'any',
|
|
39
|
+
leadSource: ['web_search', 'custom'].includes(String(o.leadSource)) ? o.leadSource : 'web_search',
|
|
40
|
+
numLeads: typeof o.numLeads === 'number' && o.numLeads >= 1 ? Math.min(100, Math.round(o.numLeads)) : 10,
|
|
41
|
+
geographicFocus: typeof o.geographicFocus === 'string' ? o.geographicFocus : '',
|
|
42
|
+
enrichmentDepth: ['basic', 'standard', 'deep'].includes(String(o.enrichmentDepth)) ? o.enrichmentDepth : 'standard',
|
|
43
|
+
outputDestination: dest,
|
|
44
|
+
spreadsheetId: typeof o.spreadsheetId === 'string' ? o.spreadsheetId.trim() || undefined : undefined,
|
|
45
|
+
documentId: typeof o.documentId === 'string' ? o.documentId.trim() || undefined : undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return {
|
|
50
|
+
targetIndustry: '',
|
|
51
|
+
targetRole: '',
|
|
52
|
+
companySize: 'any',
|
|
53
|
+
leadSource: 'web_search',
|
|
54
|
+
numLeads: 10,
|
|
55
|
+
geographicFocus: '',
|
|
56
|
+
enrichmentDepth: 'standard',
|
|
57
|
+
outputDestination: 'file',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function buildCriteriaBlock(setup) {
|
|
62
|
+
const parts = [];
|
|
63
|
+
if (setup.targetIndustry?.trim())
|
|
64
|
+
parts.push(`Target industry: ${setup.targetIndustry.trim()}`);
|
|
65
|
+
if (setup.targetRole?.trim())
|
|
66
|
+
parts.push(`Target roles (decision-makers): ${setup.targetRole.trim()}`);
|
|
67
|
+
if (setup.companySize && setup.companySize !== 'any') {
|
|
68
|
+
const labels = { startup: 'Startup (1-50)', smb: 'SMB (50-500)', enterprise: 'Enterprise (500+)' };
|
|
69
|
+
parts.push(`Company size: ${labels[setup.companySize] ?? setup.companySize}`);
|
|
70
|
+
}
|
|
71
|
+
if (setup.leadSource === 'web_search')
|
|
72
|
+
parts.push('Lead source: Web search (use web_search to find prospects).');
|
|
73
|
+
if (setup.geographicFocus?.trim())
|
|
74
|
+
parts.push(`Geographic focus: ${setup.geographicFocus.trim()}`);
|
|
75
|
+
if (setup.enrichmentDepth && setup.enrichmentDepth !== 'basic') {
|
|
76
|
+
const depth = {
|
|
77
|
+
standard: 'Enrich with company size, industry, tech stack where possible.',
|
|
78
|
+
deep: 'Enrich with company size, industry, tech stack, funding, recent news, social profiles where possible.',
|
|
79
|
+
};
|
|
80
|
+
parts.push(`Enrichment: ${depth[setup.enrichmentDepth] ?? setup.enrichmentDepth}`);
|
|
81
|
+
}
|
|
82
|
+
if (parts.length === 0)
|
|
83
|
+
return '';
|
|
84
|
+
return `Configured criteria (use these when searching and scoring):\n${parts.map((p) => `- ${p}`).join('\n')}\n\n`;
|
|
85
|
+
}
|
|
86
|
+
function buildOutputInstruction(setup) {
|
|
87
|
+
const dest = setup.outputDestination;
|
|
88
|
+
if (dest === 'google_sheet') {
|
|
89
|
+
const idHint = setup.spreadsheetId
|
|
90
|
+
? `Use spreadsheet_id="${setup.spreadsheetId}" (from the URL).`
|
|
91
|
+
: 'Create a new spreadsheet with sheets_create if none is specified, or use an existing one.';
|
|
92
|
+
return `6. Save the leads report to Google Sheets:
|
|
93
|
+
- Format: header row (Company, Role, Name, Industry, Size, Link, Score), then one row per lead.
|
|
94
|
+
- ${idHint}
|
|
95
|
+
- Use sheets_update_values to write the header and data, or sheets_append_values to append rows. Range: Sheet1!A1:G.
|
|
96
|
+
- Report back with the spreadsheet URL or "saved to Google Sheets [url]".`;
|
|
97
|
+
}
|
|
98
|
+
if (dest === 'google_doc') {
|
|
99
|
+
const idHint = setup.documentId
|
|
100
|
+
? `Use document_id="${setup.documentId}" (from the URL). Get endIndex with docs_get_document, then docs_insert_text at that index.`
|
|
101
|
+
: 'Create a new document with docs_create, then use docs_insert_text to add the report content (header + table or list of leads).';
|
|
102
|
+
return `6. Save the leads report to Google Docs:
|
|
103
|
+
- ${idHint}
|
|
104
|
+
- Format: title "Lead Report", then a table or list of leads (company, role, name, industry, size, link, score).
|
|
105
|
+
- Report back with the document URL or "saved to Google Docs [url]".`;
|
|
106
|
+
}
|
|
107
|
+
return `6. Generate a summary report (CSV or JSON) and use file_write to save it (leads.csv or leads.json). Report back with "saved to [path]".`;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Run the Lead Agent workflow.
|
|
111
|
+
*
|
|
112
|
+
* Sends a system prompt + user instruction to guide the agent through the pipeline.
|
|
113
|
+
* Workflow is autonomous: the agent decides when to call tools and when to finish.
|
|
114
|
+
*/
|
|
115
|
+
export async function runLeadAgentWorkflow(_agentId, options) {
|
|
116
|
+
const agent = getAgentBySlug('lead-agent');
|
|
117
|
+
if (!agent) {
|
|
118
|
+
log('lead-agent', 'error', 'Lead Agent not found');
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
turnCount: 0,
|
|
122
|
+
leadsFound: 0,
|
|
123
|
+
message: 'Lead Agent not found',
|
|
124
|
+
error: 'Lead Agent not configured',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const setup = getLeadAgentSetup();
|
|
128
|
+
const outputInstruction = buildOutputInstruction(setup);
|
|
129
|
+
const systemPrompt = agent.persona_prompt ||
|
|
130
|
+
`You are a lead generation specialist. Your job is to:
|
|
131
|
+
1. Use memory_recall and knowledge_query to retrieve your ICP and existing leads.
|
|
132
|
+
2. Use web_search and web_fetch to discover new potential leads (companies, decision-makers).
|
|
133
|
+
3. Score each lead 0–100 against your ICP criteria.
|
|
134
|
+
4. Deduplicate leads to avoid duplicates.
|
|
135
|
+
5. Use memory_store and knowledge_add_entity to record new leads and company relationships.
|
|
136
|
+
${outputInstruction}
|
|
137
|
+
7. Respond with a summary: "Found X leads, saved to [path/url], metrics: [...]"`;
|
|
138
|
+
const criteriaBlock = buildCriteriaBlock(setup);
|
|
139
|
+
const userPrompt = `Run your full lead generation pipeline now.
|
|
140
|
+
${criteriaBlock}
|
|
141
|
+
Here's your workflow:
|
|
142
|
+
1. Recall ICP criteria and existing leads
|
|
143
|
+
2. Search for new prospects (web_search for companies in target market; use the criteria above to shape your search)
|
|
144
|
+
3. Score and deduplicate
|
|
145
|
+
4. Store new leads in memory and knowledge graph
|
|
146
|
+
5. Save the report (about ${setup.numLeads} leads) to the configured destination. Use your available tools.
|
|
147
|
+
6. Report back with metrics: leads_found, unique_companies, and where the report was saved
|
|
148
|
+
|
|
149
|
+
Use your available tools to complete this end-to-end. Work autonomously.`;
|
|
150
|
+
const turnOptions = {
|
|
151
|
+
sessionId: options.sessionId,
|
|
152
|
+
systemPrompt,
|
|
153
|
+
userMessage: userPrompt,
|
|
154
|
+
provider: options.provider || agent.default_provider || undefined,
|
|
155
|
+
model: options.model || agent.default_model || undefined,
|
|
156
|
+
max_tokens: 4096,
|
|
157
|
+
signal: options.signal,
|
|
158
|
+
skipToolApproval: true, // autonomous run, don't wait for approval
|
|
159
|
+
};
|
|
160
|
+
try {
|
|
161
|
+
const result = options.onStreamEvent
|
|
162
|
+
? await runAgentTurnStream(turnOptions, options.onStreamEvent)
|
|
163
|
+
: await runAgentTurn(turnOptions);
|
|
164
|
+
// Parse the final response for metrics
|
|
165
|
+
const finalContent = result.finalContent || '';
|
|
166
|
+
const leadsMatch = finalContent.match(/(\d+)\s+leads?/i);
|
|
167
|
+
const leadsFound = leadsMatch ? parseInt(leadsMatch[1], 10) : 0;
|
|
168
|
+
// Record metrics
|
|
169
|
+
recordAgentMetric(agent.id, 'leads_found', leadsFound, String(leadsFound));
|
|
170
|
+
recordAgentMetric(agent.id, 'last_run', Date.now(), new Date().toISOString());
|
|
171
|
+
recordAgentMetric(agent.id, 'last_report', undefined, finalContent.slice(0, 500));
|
|
172
|
+
log('lead-agent', 'info', 'Workflow completed', {
|
|
173
|
+
sessionId: options.sessionId,
|
|
174
|
+
leadsFound,
|
|
175
|
+
turnsNeeded: result.turnCount,
|
|
176
|
+
});
|
|
177
|
+
return {
|
|
178
|
+
success: true,
|
|
179
|
+
turnCount: result.turnCount,
|
|
180
|
+
leadsFound,
|
|
181
|
+
message: finalContent,
|
|
182
|
+
reportPath: extractReportPath(finalContent),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
187
|
+
log('lead-agent', 'error', 'Workflow failed', { sessionId: options.sessionId, error: errorMsg });
|
|
188
|
+
return {
|
|
189
|
+
success: false,
|
|
190
|
+
turnCount: 0,
|
|
191
|
+
leadsFound: 0,
|
|
192
|
+
message: 'Workflow failed',
|
|
193
|
+
error: errorMsg,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Extract the report file path from the agent's final message.
|
|
199
|
+
* Looks for patterns like "saved to /path/to/leads.csv" or "leads.json".
|
|
200
|
+
*/
|
|
201
|
+
function extractReportPath(content) {
|
|
202
|
+
const match = content.match(/(?:saved to|report:?\s*|path:?\s*)([^\s,\n]+\.(?:csv|json|md))/i);
|
|
203
|
+
return match ? match[1] : undefined;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=lead-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lead-agent.js","sourceRoot":"","sources":["../../src/agent/lead-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/loop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGrE,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAoCvC,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAiBjE;AAED,uHAAuH;AACvH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,EAC9C,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAKR;AA+FD,qIAAqI;AACrI,wBAAgB,yBAAyB,IAAI,MAAM,CAMlD;AAyPD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kIAAkI;IAClI,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wIAAwI;IACxI,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGrE,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAoCvC,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAiBjE;AAED,uHAAuH;AACvH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,EAC9C,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAKR;AA+FD,qIAAqI;AACrI,wBAAgB,yBAAyB,IAAI,MAAM,CAMlD;AAyPD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kIAAkI;IAClI,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,wIAAwI;IACxI,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAmND,wBAAsB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAiLlF;AAED,2EAA2E;AAC3E,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,IAAI,GACtC,OAAO,CAAC,aAAa,CAAC,CAiQxB"}
|
package/dist/agent/loop.js
CHANGED
|
@@ -479,7 +479,55 @@ function collectFiles(base) {
|
|
|
479
479
|
}
|
|
480
480
|
return files;
|
|
481
481
|
}
|
|
482
|
-
|
|
482
|
+
/** Extract first "## Tool: name" from skill body for the index. */
|
|
483
|
+
function extractToolNameFromBody(body) {
|
|
484
|
+
const m = body.match(/##\s+Tool:\s*(\S+)/);
|
|
485
|
+
return m ? m[1].trim() : undefined;
|
|
486
|
+
}
|
|
487
|
+
/** Build a short relevance hint based on the current user message so the model picks the right tool. */
|
|
488
|
+
function buildRelevanceHint(userMessage) {
|
|
489
|
+
if (!userMessage || typeof userMessage !== 'string')
|
|
490
|
+
return '';
|
|
491
|
+
const msg = userMessage.toLowerCase().trim();
|
|
492
|
+
if (/fetch|news|perigon|articles|trending/.test(msg) && !/create\s+(a\s+)?skill/.test(msg)) {
|
|
493
|
+
return '**For this request:** Use the **perigon_fetch_articles** tool (Perigon Articles skill). Do NOT use create_skill or mcp_twitter_*.\n\n';
|
|
494
|
+
}
|
|
495
|
+
if (/create\s+(a\s+)?skill|create\s+skill\s+for/.test(msg)) {
|
|
496
|
+
return '**For this request:** User wants to create a skill. Use **create_skill** with the Sulala format (see Workspace rules below).\n\n';
|
|
497
|
+
}
|
|
498
|
+
if (/post|tweet|bluesky|social\s+post/.test(msg)) {
|
|
499
|
+
return '**For this request:** Use the skill tool for the requested platform (e.g. bluesky post, x_post) or mcp_twitter_* for Twitter. Do NOT use perigon_fetch_articles.\n\n';
|
|
500
|
+
}
|
|
501
|
+
return '';
|
|
502
|
+
}
|
|
503
|
+
/** Build only the workspace rules relevant to the user message to keep the prompt focused. */
|
|
504
|
+
function buildWorkspaceSection(userMessage) {
|
|
505
|
+
const msg = (userMessage || '').toLowerCase();
|
|
506
|
+
const isFetchNews = /fetch|news|perigon|articles|trending/.test(msg) && !/create\s+(a\s+)?skill/.test(msg);
|
|
507
|
+
const isCreateSkill = /create\s+(a\s+)?skill|create\s+skill\s+for/.test(msg);
|
|
508
|
+
const isPost = /post|tweet|bluesky/.test(msg);
|
|
509
|
+
const isWatch = /watch\s+folder|automation|when\s+(file|image)/.test(msg);
|
|
510
|
+
const parts = [];
|
|
511
|
+
// Always include a one-line "use existing skills" rule when request is about fetching data
|
|
512
|
+
if (isFetchNews) {
|
|
513
|
+
parts.push('Use **perigon_fetch_articles** for Perigon/news. Do not create_skill.');
|
|
514
|
+
}
|
|
515
|
+
if (isCreateSkill) {
|
|
516
|
+
parts.push('**Creating a skill:** Use create_skill. README: name, description, metadata with env + envHints, body with ## Tool: <name>. tools.yaml: name, request.url, queryParams with $env:KEY, parameters[].name, response. requiredEnv: same as metadata.');
|
|
517
|
+
}
|
|
518
|
+
if (isPost) {
|
|
519
|
+
parts.push('For posting: use the skill tool for that platform or mcp_*; do not use perigon_fetch_articles.');
|
|
520
|
+
}
|
|
521
|
+
if (isWatch) {
|
|
522
|
+
parts.push(`Watch-folder: create script in ${config.workspaceDir}/scripts/, credentials in .env, then register_automation.`);
|
|
523
|
+
}
|
|
524
|
+
// If no specific match, add a short general rule
|
|
525
|
+
if (parts.length === 0) {
|
|
526
|
+
parts.push('Match the user request to an Available skill and use that skill\'s tool. For fetch/news use perigon_fetch_articles. Only use create_skill when user explicitly asks to create a skill.');
|
|
527
|
+
}
|
|
528
|
+
return `## Workspace\n\n${parts.join('\n\n')}\n\n`;
|
|
529
|
+
}
|
|
530
|
+
function loadContextFromPaths(userMessage) {
|
|
483
531
|
const paths = getSkillPaths(config);
|
|
484
532
|
const bySkillName = new Map();
|
|
485
533
|
const nonSkillChunks = [];
|
|
@@ -495,8 +543,9 @@ function loadContextFromPaths() {
|
|
|
495
543
|
const slug = fileName.replace(/\.md$/, '');
|
|
496
544
|
if (parsed.name && parsed.description && isSkillEnabled(slug)) {
|
|
497
545
|
const oauthScopes = extractOAuthScopesFromFrontmatter(parsed.frontmatterBlock);
|
|
546
|
+
const toolName = extractToolNameFromBody(parsed.body);
|
|
498
547
|
bySkillName.set(parsed.name, {
|
|
499
|
-
index: { name: parsed.name, description: parsed.description },
|
|
548
|
+
index: { name: parsed.name, description: parsed.description, ...(toolName ? { toolName } : {}) },
|
|
500
549
|
body: parsed.body,
|
|
501
550
|
slug,
|
|
502
551
|
...(oauthScopes?.length ? { oauthScopes } : {}),
|
|
@@ -513,6 +562,13 @@ function loadContextFromPaths() {
|
|
|
513
562
|
}
|
|
514
563
|
const skillsConfig = loadSkillsConfig();
|
|
515
564
|
const skillIndex = Array.from(bySkillName.values()).map((v) => v.index);
|
|
565
|
+
const indexLines = skillIndex.map((s) => {
|
|
566
|
+
const toolPart = s.toolName ? ` (tool: **${s.toolName}**)` : '';
|
|
567
|
+
return `- **${s.name}**${toolPart}: ${s.description}`;
|
|
568
|
+
});
|
|
569
|
+
const indexSection = indexLines.length > 0
|
|
570
|
+
? `### Available skills (use the tool name when the request matches)\n${indexLines.join('\n')}\n\n`
|
|
571
|
+
: '';
|
|
516
572
|
const chunks = Array.from(bySkillName.values()).map((v) => {
|
|
517
573
|
const entryScopes = skillsConfig.entries?.[v.slug]?.oauthScopes;
|
|
518
574
|
const scopes = Array.isArray(entryScopes) && entryScopes.length > 0 ? entryScopes : v.oauthScopes;
|
|
@@ -520,25 +576,14 @@ function loadContextFromPaths() {
|
|
|
520
576
|
return `### Skill: ${v.index.name}\n\n${scopeLine}${v.body}`;
|
|
521
577
|
});
|
|
522
578
|
chunks.push(...nonSkillChunks);
|
|
523
|
-
if (chunks.length === 0)
|
|
579
|
+
if (chunks.length === 0 && indexSection === '')
|
|
524
580
|
return '';
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
// Inject workspace path so the agent knows where to create skills and watch-folder automations.
|
|
529
|
-
const workspaceSection = `## Workspace\n\n` +
|
|
530
|
-
`- **Installing skills from the hub**: When the user asks for something that needs a capability you don't have (e.g. "read my Gmail", "post to Bluesky", "fetch news"), use **search_skills_registry** with a short query (e.g. "gmail", "bluesky", "news"). If you find a matching skill, suggest installing it by name and ask for confirmation (e.g. "I can add the Gmail skill so I can read your email. Should I install it? (yes/no)"). If the user agrees, use **install_skill_from_registry** with that skill's slug. If the tool returns \`needsConfig: true\`, tell the user to go to **Dashboard → Skills**, open that skill, complete the setup (env vars or OAuth), then **come back and ask again**—do not assume the skill is ready until they have configured it.\n\n` +
|
|
531
|
-
`- **MCP and skills (posting or other actions on a service)**: (1) **Prefer MCP tools**: when the user asks to post or act on a service (e.g. X/Twitter, Gmail), use a tool whose name starts with **mcp_** and matches the service (e.g. mcp_twitter_*, mcp_gmail_*) if available. (2) If no matching MCP tool exists, use the skill tool (e.g. x_post for X/Twitter) or follow the skill doc (run_command with credentials from skill config). Never use an integration tool for a different provider. (3) **If a tool fails**: the system will automatically try the other option (MCP or skill) when possible; you will receive the result from whichever succeeded. Do not ask the user to "try MCP" or "try the skill" unless both attempts already failed.\n\n` +
|
|
532
|
-
`- **Skills you create**: use **write_file** with path \`${config.skillsWorkspaceMyDir}/<slug>/README.md\` (e.g. \`${config.skillsWorkspaceMyDir}/my-skill/README.md\`). Also create \`${config.skillsWorkspaceMyDir}/<slug>/tools.yaml\` with \`tools: []\` and a short comment so the user can add required tools there. Do not use \`~\` or \`$HOME\`. Hub-installed skills live in \`${config.skillsWorkspaceDir}/<slug>/\`; keep created-by-you skills in \`${config.skillsWorkspaceMyDir}/\`.\n\n` +
|
|
533
|
-
`- **Scripts and watch-folder automations**: Workspace root is \`${config.workspaceDir}\`. When the user asks to watch a folder and do something (e.g. post new images to Bluesky or Facebook):\n` +
|
|
534
|
-
` 1. Create a script under \`${config.workspaceDir}/scripts/\` (e.g. \`scripts/watch_bluesky.sh\` or \`scripts/watch_facebook.sh\`) that accepts the **file path as first argument** (\`$1\`) and uses env vars for credentials.\n` +
|
|
535
|
-
` 2. Store credentials in \`${config.workspaceDir}/.env\` (e.g. \`BSKY_HANDLE=...\`, \`BSKY_APP_PASSWORD=...\` or \`PAGE_ACCESS_TOKEN=...\`). Use **write_file** to create or append lines to \`.env\`.\n` +
|
|
536
|
-
` 3. Call **register_automation** with \`id\`, \`script\` (e.g. \`scripts/watch_bluesky.sh\`), \`watch_folders\` (array of absolute paths), and optional \`filter: "image"\` for image-only. The agent will run your script when matching files are added.\n` +
|
|
537
|
-
` 4. **Always test the script yourself** before replying: run it with **run_command** and a real file path from the watch folder (e.g. an existing image). Example: \`bash -lc "set -a; source ${config.workspaceDir}/.env; set +a; ${config.workspaceDir}/scripts/your_script.sh /path/to/existing/image.jpg"\`. If it fails (e.g. missing argument, auth error), fix the script or .env and run again until it succeeds. Do not tell the user to test manually.\n\n`;
|
|
538
|
-
return `\n\n## Context\n\n${workspaceSection}${indexSection}${chunks.join('\n\n')}`;
|
|
581
|
+
const relevanceHint = buildRelevanceHint(userMessage);
|
|
582
|
+
const workspaceSection = buildWorkspaceSection(userMessage);
|
|
583
|
+
return `\n\n## Context\n\n${relevanceHint}${workspaceSection}${indexSection}${chunks.join('\n\n')}`;
|
|
539
584
|
}
|
|
540
|
-
async function resolveSystemPrompt(sessionId, basePrompt, messageCount) {
|
|
541
|
-
const context = loadContextFromPaths();
|
|
585
|
+
async function resolveSystemPrompt(sessionId, basePrompt, messageCount, userMessage) {
|
|
586
|
+
const context = loadContextFromPaths(userMessage);
|
|
542
587
|
let withContext = basePrompt + context;
|
|
543
588
|
const sessionMemory = getMemoryForContext('session', sessionId, { limit: 20, maxChars: 2000 });
|
|
544
589
|
const sharedKey = getSharedScopeKeyForSession(sessionId);
|
|
@@ -568,7 +613,7 @@ export async function runAgentTurn(options) {
|
|
|
568
613
|
const historyLimit = config.agentMaxHistoryMessages > 0 ? config.agentMaxHistoryMessages + 50 : 80;
|
|
569
614
|
const history = getAgentMessages(sessionId, historyLimit);
|
|
570
615
|
const baseSystem = (optionPrompt ?? config.agentSystemPrompt ?? DEFAULT_SYSTEM) + AUTOMATION_JOBS_APPENDIX;
|
|
571
|
-
let systemPrompt = await resolveSystemPrompt(sessionId, baseSystem, history.length + 1);
|
|
616
|
+
let systemPrompt = await resolveSystemPrompt(sessionId, baseSystem, history.length + 1, userMessage);
|
|
572
617
|
const estimatedTotalTokens = systemPrompt.length + estimateTokens(rowsToMessages(history));
|
|
573
618
|
if (config.agentMemoryFlushBeforeCompaction &&
|
|
574
619
|
config.agentMemoryFlushSilentTurn &&
|
|
@@ -717,7 +762,7 @@ export async function runAgentTurnStream(options, onEvent) {
|
|
|
717
762
|
const historyLimit = config.agentMaxHistoryMessages > 0 ? config.agentMaxHistoryMessages + 50 : 80;
|
|
718
763
|
const history = getAgentMessages(sessionId, historyLimit);
|
|
719
764
|
const baseSystem = (optionPrompt ?? config.agentSystemPrompt ?? DEFAULT_SYSTEM) + AUTOMATION_JOBS_APPENDIX;
|
|
720
|
-
let systemPrompt = await resolveSystemPrompt(sessionId, baseSystem, history.length + 1);
|
|
765
|
+
let systemPrompt = await resolveSystemPrompt(sessionId, baseSystem, history.length + 1, userMessage);
|
|
721
766
|
const estimatedTotalTokens = systemPrompt.length + estimateTokens(rowsToMessages(history));
|
|
722
767
|
if (config.agentMemoryFlushBeforeCompaction &&
|
|
723
768
|
config.agentMemoryFlushSilentTurn &&
|