assistme 0.8.12 → 0.9.1
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/PLAN.md +1 -1
- package/dist/{chunk-MP4E522X.js → chunk-O5K33FBW.js} +242 -50
- package/dist/{chunk-5ML5YMCM.js → chunk-RRMI6RDG.js} +85 -8
- package/dist/index.js +30 -6
- package/dist/{job-runner-NA3KJCKA.js → job-runner-4KTCVIQP.js} +1 -1
- package/dist/workers/entry.js +2 -2
- package/package.json +1 -1
- package/src/agent/execution/processor.ts +14 -0
- package/src/agent/memory/manager.ts +92 -27
- package/src/agent/scheduling/index.ts +1 -1
- package/src/agent/scheduling/job-runner.ts +72 -7
- package/src/browser/actions.ts +2 -7
- package/src/browser/delays.ts +10 -0
- package/src/browser/navigation.ts +2 -7
- package/src/browser/screenshot.ts +94 -0
- package/src/browser/snapshot.ts +3 -8
- package/src/db/api-client.ts +1 -1
- package/src/mcp/tools/job-tools.ts +109 -5
- package/src/orchestrator.ts +18 -1
- package/src/utils/schemas.ts +11 -0
- package/tests/agent/processor.test.ts +2 -0
- package/tests/browser/snapshot.test.ts +1 -0
package/PLAN.md
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
readAuthStore,
|
|
9
9
|
safeParse,
|
|
10
10
|
writeAuthStore
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RRMI6RDG.js";
|
|
12
12
|
import {
|
|
13
13
|
log,
|
|
14
14
|
newCorrelationId,
|
|
@@ -318,6 +318,7 @@ var CDP_SETTLE_MS = 300;
|
|
|
318
318
|
var PAGE_TRANSITION_MS = 500;
|
|
319
319
|
var MAX_WAIT_MS = 5e3;
|
|
320
320
|
var SCREENSHOT_QUALITY = 80;
|
|
321
|
+
var SCREENSHOT_MAX_DIM_PX = 1568;
|
|
321
322
|
function delay(ms) {
|
|
322
323
|
return new Promise((r) => {
|
|
323
324
|
setTimeout(r, ms);
|
|
@@ -809,6 +810,56 @@ async function tryDismissOverlay(conn) {
|
|
|
809
810
|
}
|
|
810
811
|
}
|
|
811
812
|
|
|
813
|
+
// src/browser/screenshot.ts
|
|
814
|
+
async function getViewportMetrics(conn) {
|
|
815
|
+
try {
|
|
816
|
+
const result = await conn.send("Runtime.evaluate", {
|
|
817
|
+
expression: `JSON.stringify({ width: window.innerWidth, height: window.innerHeight, dpr: window.devicePixelRatio || 1 })`,
|
|
818
|
+
returnByValue: true
|
|
819
|
+
});
|
|
820
|
+
const value = result.result?.value;
|
|
821
|
+
if (value) {
|
|
822
|
+
const parsed = JSON.parse(value);
|
|
823
|
+
const width = Number(parsed.width) || 0;
|
|
824
|
+
const height = Number(parsed.height) || 0;
|
|
825
|
+
const dpr = Number(parsed.dpr) || 1;
|
|
826
|
+
if (width > 0 && height > 0) {
|
|
827
|
+
return { width, height, dpr };
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
} catch {
|
|
831
|
+
}
|
|
832
|
+
return { width: 0, height: 0, dpr: 1 };
|
|
833
|
+
}
|
|
834
|
+
async function captureBoundedScreenshot(conn, maxDim = SCREENSHOT_MAX_DIM_PX) {
|
|
835
|
+
const { width, height, dpr } = await getViewportMetrics(conn);
|
|
836
|
+
if (width === 0 || height === 0) {
|
|
837
|
+
const result2 = await conn.send("Page.captureScreenshot", {
|
|
838
|
+
format: "png",
|
|
839
|
+
quality: SCREENSHOT_QUALITY,
|
|
840
|
+
captureBeyondViewport: false
|
|
841
|
+
});
|
|
842
|
+
return result2.data || "";
|
|
843
|
+
}
|
|
844
|
+
const naturalMax = Math.max(width, height) * dpr;
|
|
845
|
+
if (naturalMax <= maxDim) {
|
|
846
|
+
const result2 = await conn.send("Page.captureScreenshot", {
|
|
847
|
+
format: "png",
|
|
848
|
+
quality: SCREENSHOT_QUALITY,
|
|
849
|
+
captureBeyondViewport: false
|
|
850
|
+
});
|
|
851
|
+
return result2.data || "";
|
|
852
|
+
}
|
|
853
|
+
const scale = Math.min(dpr, maxDim / Math.max(width, height));
|
|
854
|
+
const result = await conn.send("Page.captureScreenshot", {
|
|
855
|
+
format: "png",
|
|
856
|
+
quality: SCREENSHOT_QUALITY,
|
|
857
|
+
captureBeyondViewport: false,
|
|
858
|
+
clip: { x: 0, y: 0, width, height, scale }
|
|
859
|
+
});
|
|
860
|
+
return result.data || "";
|
|
861
|
+
}
|
|
862
|
+
|
|
812
863
|
// src/browser/actions.ts
|
|
813
864
|
var Actions = class {
|
|
814
865
|
constructor(conn, snapshotEngine) {
|
|
@@ -1004,12 +1055,7 @@ var Actions = class {
|
|
|
1004
1055
|
let screenshot;
|
|
1005
1056
|
if (takeScreenshot) {
|
|
1006
1057
|
await delay(CDP_SETTLE_MS);
|
|
1007
|
-
|
|
1008
|
-
format: "png",
|
|
1009
|
-
quality: SCREENSHOT_QUALITY,
|
|
1010
|
-
captureBeyondViewport: false
|
|
1011
|
-
});
|
|
1012
|
-
screenshot = screenshotResult.data || "";
|
|
1058
|
+
screenshot = await captureBoundedScreenshot(this.conn);
|
|
1013
1059
|
}
|
|
1014
1060
|
return { results, screenshot };
|
|
1015
1061
|
}
|
|
@@ -1378,12 +1424,7 @@ URL: ${info.url}`;
|
|
|
1378
1424
|
}
|
|
1379
1425
|
async screenshot() {
|
|
1380
1426
|
this.conn.ensureConnected();
|
|
1381
|
-
|
|
1382
|
-
format: "png",
|
|
1383
|
-
quality: SCREENSHOT_QUALITY,
|
|
1384
|
-
captureBeyondViewport: false
|
|
1385
|
-
});
|
|
1386
|
-
return result.data || "";
|
|
1427
|
+
return captureBoundedScreenshot(this.conn);
|
|
1387
1428
|
}
|
|
1388
1429
|
async detectLoginPage() {
|
|
1389
1430
|
try {
|
|
@@ -1833,12 +1874,7 @@ var SnapshotEngine = class {
|
|
|
1833
1874
|
expression: buildAnnotationOverlayJS(refsJson)
|
|
1834
1875
|
});
|
|
1835
1876
|
}
|
|
1836
|
-
const
|
|
1837
|
-
format: "png",
|
|
1838
|
-
quality: SCREENSHOT_QUALITY,
|
|
1839
|
-
captureBeyondViewport: false
|
|
1840
|
-
});
|
|
1841
|
-
const image = screenshotResult.data || "";
|
|
1877
|
+
const image = await captureBoundedScreenshot(this.conn);
|
|
1842
1878
|
if (annotate) {
|
|
1843
1879
|
await this.conn.send("Runtime.evaluate", {
|
|
1844
1880
|
expression: `(function() { var el = document.getElementById('__assistme_refs__'); if (el) el.remove(); })()`
|
|
@@ -2833,19 +2869,51 @@ var TaskPoller = class {
|
|
|
2833
2869
|
// src/agent/memory/manager.ts
|
|
2834
2870
|
var MemoryManager = class {
|
|
2835
2871
|
/**
|
|
2836
|
-
*
|
|
2837
|
-
*
|
|
2872
|
+
* When set, all memory operations use this agent's users.id as the
|
|
2873
|
+
* effective user, giving the agent its own memory space.
|
|
2874
|
+
*/
|
|
2875
|
+
agentUserId = null;
|
|
2876
|
+
/** The human owner's user ID — used to load owner memories as fallback. */
|
|
2877
|
+
ownerUserId = null;
|
|
2878
|
+
/**
|
|
2879
|
+
* Configure agent-scoped memory.
|
|
2880
|
+
* @param agentUserId The agent's users.id — memories are stored/read here
|
|
2881
|
+
* @param ownerUserId The human owner's users.id — owner memories loaded as fallback
|
|
2882
|
+
*/
|
|
2883
|
+
setAgentContext(agentUserId, ownerUserId) {
|
|
2884
|
+
this.agentUserId = agentUserId;
|
|
2885
|
+
this.ownerUserId = ownerUserId;
|
|
2886
|
+
}
|
|
2887
|
+
/** Clear agent context (revert to normal user-scoped mode). */
|
|
2888
|
+
clearAgentContext() {
|
|
2889
|
+
this.agentUserId = null;
|
|
2890
|
+
this.ownerUserId = null;
|
|
2891
|
+
}
|
|
2892
|
+
/** Inject effective_user_id + owner_user_id into params. */
|
|
2893
|
+
agentParams(extra = {}) {
|
|
2894
|
+
const params = { ...extra };
|
|
2895
|
+
if (this.agentUserId) {
|
|
2896
|
+
params.effective_user_id = this.agentUserId;
|
|
2897
|
+
if (this.ownerUserId) {
|
|
2898
|
+
params.owner_user_id = this.ownerUserId;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
return params;
|
|
2902
|
+
}
|
|
2903
|
+
/**
|
|
2904
|
+
* Store a new memory. Called by the agent after completing tasks.
|
|
2905
|
+
* When agent context is set, stores under the agent's user_id.
|
|
2838
2906
|
*/
|
|
2839
2907
|
async remember(content, category = "general", options) {
|
|
2840
2908
|
const expiresAt = options?.expiresInDays ? new Date(Date.now() + options.expiresInDays * 864e5).toISOString() : null;
|
|
2841
|
-
const data = await callMcpHandler("memory.store", {
|
|
2909
|
+
const data = await callMcpHandler("memory.store", this.agentParams({
|
|
2842
2910
|
category,
|
|
2843
2911
|
content,
|
|
2844
2912
|
importance: options?.importance ?? 5,
|
|
2845
2913
|
tags: options?.tags ?? [],
|
|
2846
2914
|
source_message_id: options?.sourceMessageId ?? null,
|
|
2847
2915
|
expires_at: expiresAt
|
|
2848
|
-
});
|
|
2916
|
+
}));
|
|
2849
2917
|
log.debug(`Memory stored: [${category}] ${content.slice(0, 80)}...`);
|
|
2850
2918
|
return data;
|
|
2851
2919
|
}
|
|
@@ -2854,10 +2922,10 @@ var MemoryManager = class {
|
|
|
2854
2922
|
*/
|
|
2855
2923
|
async search(query9, limit = 10) {
|
|
2856
2924
|
try {
|
|
2857
|
-
return await callMcpHandler("memory.search", {
|
|
2925
|
+
return await callMcpHandler("memory.search", this.agentParams({
|
|
2858
2926
|
query: query9,
|
|
2859
2927
|
limit
|
|
2860
|
-
});
|
|
2928
|
+
}));
|
|
2861
2929
|
} catch (err) {
|
|
2862
2930
|
log.warn(`Memory search failed: ${err instanceof Error ? err.message : err}`);
|
|
2863
2931
|
return [];
|
|
@@ -2865,13 +2933,13 @@ var MemoryManager = class {
|
|
|
2865
2933
|
}
|
|
2866
2934
|
/**
|
|
2867
2935
|
* Get the most important/recent memories to include in context.
|
|
2868
|
-
*
|
|
2869
|
-
*
|
|
2936
|
+
* When agent context is set, loads agent's memories first,
|
|
2937
|
+
* then supplements with the owner's memories as fallback.
|
|
2870
2938
|
*/
|
|
2871
2939
|
async getContext(maxItems = 20) {
|
|
2872
|
-
const all = await callMcpHandler("memory.get_context", {
|
|
2940
|
+
const all = await callMcpHandler("memory.get_context", this.agentParams({
|
|
2873
2941
|
max_items: maxItems
|
|
2874
|
-
});
|
|
2942
|
+
}));
|
|
2875
2943
|
const seen = /* @__PURE__ */ new Set();
|
|
2876
2944
|
return (all || []).filter((m) => {
|
|
2877
2945
|
if (seen.has(m.id)) return false;
|
|
@@ -2885,48 +2953,63 @@ var MemoryManager = class {
|
|
|
2885
2953
|
async buildMemoryPrompt() {
|
|
2886
2954
|
const memories = await this.getContext();
|
|
2887
2955
|
if (memories.length === 0) return "";
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
if (!sections[key]) sections[key] = [];
|
|
2892
|
-
sections[key].push(`- ${m.content}`);
|
|
2893
|
-
}
|
|
2956
|
+
const hasOwnerFlag = memories.some((m) => m._from_owner);
|
|
2957
|
+
const agentMemories = hasOwnerFlag ? memories.filter((m) => !m._from_owner) : memories;
|
|
2958
|
+
const ownerMemories = hasOwnerFlag ? memories.filter((m) => m._from_owner) : [];
|
|
2894
2959
|
const categoryLabels = {
|
|
2895
2960
|
instruction: "Standing Instructions",
|
|
2896
|
-
preference: "
|
|
2961
|
+
preference: "Preferences",
|
|
2897
2962
|
general: "Known Facts",
|
|
2898
2963
|
context: "Context",
|
|
2899
2964
|
skill_learned: "Learned Skills",
|
|
2900
2965
|
fact: "Facts"
|
|
2901
2966
|
};
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2967
|
+
function formatSection(mems) {
|
|
2968
|
+
const sections = {};
|
|
2969
|
+
for (const m of mems) {
|
|
2970
|
+
const key = m.category;
|
|
2971
|
+
if (!sections[key]) sections[key] = [];
|
|
2972
|
+
sections[key].push(`- ${m.content}`);
|
|
2973
|
+
}
|
|
2974
|
+
let out = "";
|
|
2975
|
+
for (const [cat, items] of Object.entries(sections)) {
|
|
2976
|
+
out += `
|
|
2905
2977
|
### ${categoryLabels[cat] || cat}
|
|
2906
2978
|
`;
|
|
2907
|
-
|
|
2979
|
+
out += `${items.join("\n")}
|
|
2908
2980
|
`;
|
|
2981
|
+
}
|
|
2982
|
+
return out;
|
|
2983
|
+
}
|
|
2984
|
+
let prompt = "";
|
|
2985
|
+
if (agentMemories.length > 0) {
|
|
2986
|
+
prompt += this.agentUserId ? "\n\n## Your Memories\n" : "\n\n## What You Know About The User\n";
|
|
2987
|
+
prompt += formatSection(agentMemories);
|
|
2988
|
+
}
|
|
2989
|
+
if (ownerMemories.length > 0) {
|
|
2990
|
+
prompt += "\n\n## Owner's Context\n";
|
|
2991
|
+
prompt += formatSection(ownerMemories);
|
|
2909
2992
|
}
|
|
2910
2993
|
return prompt;
|
|
2911
2994
|
}
|
|
2912
2995
|
// ── CRUD for CLI ────────────────────────────────────────────
|
|
2913
2996
|
async list(category, limit = 20) {
|
|
2914
|
-
const data = await callMcpHandler("memory.list", {
|
|
2997
|
+
const data = await callMcpHandler("memory.list", this.agentParams({
|
|
2915
2998
|
category: category || null,
|
|
2916
2999
|
limit
|
|
2917
|
-
});
|
|
3000
|
+
}));
|
|
2918
3001
|
return data || [];
|
|
2919
3002
|
}
|
|
2920
3003
|
async add(content, category = "general", importance = 5, tags = []) {
|
|
2921
3004
|
return this.remember(content, category, { importance, tags });
|
|
2922
3005
|
}
|
|
2923
3006
|
async remove(memoryId) {
|
|
2924
|
-
await callMcpHandler("memory.remove", { memory_id: memoryId });
|
|
3007
|
+
await callMcpHandler("memory.remove", this.agentParams({ memory_id: memoryId }));
|
|
2925
3008
|
}
|
|
2926
3009
|
async clear(category) {
|
|
2927
|
-
const result = await callMcpHandler("memory.clear", {
|
|
3010
|
+
const result = await callMcpHandler("memory.clear", this.agentParams({
|
|
2928
3011
|
category: category || null
|
|
2929
|
-
});
|
|
3012
|
+
}));
|
|
2930
3013
|
return result.count;
|
|
2931
3014
|
}
|
|
2932
3015
|
};
|
|
@@ -5528,7 +5611,7 @@ function createJobTools(sessionId, taskId) {
|
|
|
5528
5611
|
const job = await runner.loadJob(args.job_name);
|
|
5529
5612
|
if (!job) {
|
|
5530
5613
|
const jobs = await runner.listJobs();
|
|
5531
|
-
const available = jobs.length > 0 ? `Available jobs: ${jobs.map((j) => `"${j.name}" (${j.skillCount} skills)`).join(", ")}` : "No jobs defined yet. Use skill_generate to create a job from a job description.";
|
|
5614
|
+
const available = jobs.length > 0 ? `Available jobs: ${jobs.map((j) => `"${j.name}" (${j.skillCount} skills, ${j.agentCount} agents)`).join(", ")}` : "No jobs defined yet. Use skill_generate to create a job from a job description.";
|
|
5532
5615
|
return textResponse(`Job "${args.job_name}" not found. ${available}`);
|
|
5533
5616
|
}
|
|
5534
5617
|
if (job.skills.length === 0) {
|
|
@@ -5569,11 +5652,38 @@ function createJobTools(sessionId, taskId) {
|
|
|
5569
5652
|
}
|
|
5570
5653
|
}
|
|
5571
5654
|
}
|
|
5572
|
-
const
|
|
5655
|
+
const effectiveRunId = runId || "untracked";
|
|
5656
|
+
const prompt = runner.buildJobPrompt(job, effectiveRunId);
|
|
5657
|
+
const primaryAgentForFilter = job.agents.length > 0 ? job.agents.find((p) => p.role === "primary") || job.agents[0] : null;
|
|
5658
|
+
const parallelAgents = job.agents.filter(
|
|
5659
|
+
(a) => a.role === "parallel" && a.agentId !== primaryAgentForFilter?.agentId
|
|
5660
|
+
);
|
|
5661
|
+
let fullResponse = prompt;
|
|
5662
|
+
if (parallelAgents.length > 0) {
|
|
5663
|
+
fullResponse += `
|
|
5664
|
+
|
|
5665
|
+
---
|
|
5666
|
+
|
|
5667
|
+
## Parallel Agent Dispatch
|
|
5668
|
+
`;
|
|
5669
|
+
fullResponse += `The following parallel agents are assigned to this job. `;
|
|
5670
|
+
fullResponse += `After you complete your primary tasks, review their responsibilities and execute any that haven't been covered:
|
|
5671
|
+
|
|
5672
|
+
`;
|
|
5673
|
+
for (const pa of parallelAgents) {
|
|
5674
|
+
fullResponse += `### ${pa.agentName} (@${pa.agentUsername})
|
|
5675
|
+
`;
|
|
5676
|
+
if (pa.agentBio) fullResponse += `*${pa.agentBio}*
|
|
5677
|
+
`;
|
|
5678
|
+
fullResponse += `**Instructions:** ${pa.agentPrompt}
|
|
5679
|
+
|
|
5680
|
+
`;
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5573
5683
|
log.info(
|
|
5574
|
-
`Job "${args.job_name}" started with ${job.skills.length} skills (run: ${
|
|
5684
|
+
`Job "${args.job_name}" started with ${job.skills.length} skills, ${job.agents.length} agents (run: ${effectiveRunId.slice(0, 8)})`
|
|
5575
5685
|
);
|
|
5576
|
-
return textResponse(
|
|
5686
|
+
return textResponse(fullResponse);
|
|
5577
5687
|
})
|
|
5578
5688
|
),
|
|
5579
5689
|
tool4(
|
|
@@ -5639,6 +5749,80 @@ function createJobTools(sessionId, taskId) {
|
|
|
5639
5749
|
}
|
|
5640
5750
|
)
|
|
5641
5751
|
),
|
|
5752
|
+
tool4(
|
|
5753
|
+
"job_assign_agent",
|
|
5754
|
+
"Create or update an agent for a job. The agent is a user with a specific prompt and identity that will execute this job.",
|
|
5755
|
+
{
|
|
5756
|
+
job_name: z4.string().describe("Name of the job to assign the agent to"),
|
|
5757
|
+
agent_name: z4.string().describe("Display name for the agent (e.g. 'Daily Reporter')"),
|
|
5758
|
+
agent_prompt: z4.string().describe("The agent's system prompt that defines its behavior and personality"),
|
|
5759
|
+
agent_bio: z4.string().optional().describe("Short bio describing the agent's role"),
|
|
5760
|
+
role: z4.enum(["primary", "parallel"]).optional().describe("Agent role: 'primary' (default) or 'parallel' for concurrent execution")
|
|
5761
|
+
},
|
|
5762
|
+
typedHandler(
|
|
5763
|
+
async (args) => {
|
|
5764
|
+
try {
|
|
5765
|
+
const result = await callMcpHandler("job.save_agent", {
|
|
5766
|
+
job_name: args.job_name,
|
|
5767
|
+
agent_name: args.agent_name,
|
|
5768
|
+
agent_prompt: args.agent_prompt,
|
|
5769
|
+
agent_bio: args.agent_bio || null,
|
|
5770
|
+
role: args.role || "primary"
|
|
5771
|
+
});
|
|
5772
|
+
if (!result) {
|
|
5773
|
+
return textResponse(`Failed to create agent for job "${args.job_name}".`);
|
|
5774
|
+
}
|
|
5775
|
+
log.info(
|
|
5776
|
+
`Agent "${result.username}" assigned to job "${args.job_name}" (${args.role || "primary"})`
|
|
5777
|
+
);
|
|
5778
|
+
let response = `## Agent Assigned to Job: ${args.job_name}
|
|
5779
|
+
|
|
5780
|
+
`;
|
|
5781
|
+
response += `- **Agent:** ${args.agent_name} (@${result.username})
|
|
5782
|
+
`;
|
|
5783
|
+
response += `- **Role:** ${args.role || "primary"}
|
|
5784
|
+
`;
|
|
5785
|
+
if (args.agent_bio) {
|
|
5786
|
+
response += `- **Bio:** ${args.agent_bio}
|
|
5787
|
+
`;
|
|
5788
|
+
}
|
|
5789
|
+
response += `
|
|
5790
|
+
The agent is now ready to execute this job.`;
|
|
5791
|
+
return textResponse(response);
|
|
5792
|
+
} catch (err) {
|
|
5793
|
+
return textResponse(
|
|
5794
|
+
`Failed to assign agent: ${err instanceof Error ? err.message : err}`
|
|
5795
|
+
);
|
|
5796
|
+
}
|
|
5797
|
+
}
|
|
5798
|
+
)
|
|
5799
|
+
),
|
|
5800
|
+
tool4(
|
|
5801
|
+
"job_remove_agent",
|
|
5802
|
+
"Remove (deactivate) an agent from a job.",
|
|
5803
|
+
{
|
|
5804
|
+
job_name: z4.string().describe("Name of the job"),
|
|
5805
|
+
agent_name: z4.string().describe("Display name of the agent to remove")
|
|
5806
|
+
},
|
|
5807
|
+
typedHandler(
|
|
5808
|
+
async (args) => {
|
|
5809
|
+
try {
|
|
5810
|
+
await callMcpHandler("job.remove_agent", {
|
|
5811
|
+
job_name: args.job_name,
|
|
5812
|
+
agent_name: args.agent_name
|
|
5813
|
+
});
|
|
5814
|
+
log.info(`Agent "${args.agent_name}" removed from job "${args.job_name}"`);
|
|
5815
|
+
return textResponse(
|
|
5816
|
+
`Agent "${args.agent_name}" has been removed from job "${args.job_name}".`
|
|
5817
|
+
);
|
|
5818
|
+
} catch (err) {
|
|
5819
|
+
return textResponse(
|
|
5820
|
+
`Failed to remove agent: ${err instanceof Error ? err.message : err}`
|
|
5821
|
+
);
|
|
5822
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
)
|
|
5825
|
+
),
|
|
5642
5826
|
tool4(
|
|
5643
5827
|
"job_status",
|
|
5644
5828
|
"Check the status and run history of a job.",
|
|
@@ -5657,7 +5841,7 @@ function createJobTools(sessionId, taskId) {
|
|
|
5657
5841
|
}
|
|
5658
5842
|
let response2 = "## Your Jobs\n\n";
|
|
5659
5843
|
for (const job of jobs) {
|
|
5660
|
-
response2 += `- **${job.name}** (${job.skillCount} skills): ${job.description.slice(0, 100)}
|
|
5844
|
+
response2 += `- **${job.name}** (${job.skillCount} skills, ${job.agentCount} agents): ${job.description.slice(0, 100)}
|
|
5661
5845
|
`;
|
|
5662
5846
|
}
|
|
5663
5847
|
response2 += "\nUse `job_run` to execute a job, or `job_schedule` to automate it.";
|
|
@@ -8420,6 +8604,11 @@ var TaskProcessor = class {
|
|
|
8420
8604
|
resetEventSequence();
|
|
8421
8605
|
newCorrelationId();
|
|
8422
8606
|
log.info(`Processing task ${task.id.slice(0, 8)}...`);
|
|
8607
|
+
const taskAgentId = task.metadata?.agent_id || (task.sender_id !== this.userId ? task.sender_id : null);
|
|
8608
|
+
if (taskAgentId && this.memoryManager && this.userId) {
|
|
8609
|
+
this.memoryManager.setAgentContext(taskAgentId, this.userId);
|
|
8610
|
+
log.debug(`Memory context set to agent ${taskAgentId.slice(0, 8)}`);
|
|
8611
|
+
}
|
|
8423
8612
|
const toolCallRecords = [];
|
|
8424
8613
|
const toolFailures = [];
|
|
8425
8614
|
try {
|
|
@@ -8479,6 +8668,9 @@ var TaskProcessor = class {
|
|
|
8479
8668
|
await emitEvent(task.id, "status_change", { status: "failed" });
|
|
8480
8669
|
} finally {
|
|
8481
8670
|
setCorrelationId(null);
|
|
8671
|
+
if (taskAgentId && this.memoryManager) {
|
|
8672
|
+
this.memoryManager.clearAgentContext();
|
|
8673
|
+
}
|
|
8482
8674
|
try {
|
|
8483
8675
|
const browser = getBrowser();
|
|
8484
8676
|
if (browser.isConnected()) {
|
|
@@ -43,7 +43,7 @@ function getRawToken() {
|
|
|
43
43
|
async function callMcpHandler(action, params = {}, overrideToken) {
|
|
44
44
|
const config = getConfig();
|
|
45
45
|
const token = overrideToken || getRawToken();
|
|
46
|
-
const url = `${config.supabaseUrl}/functions/v1/mcp-handler`;
|
|
46
|
+
const url = `${config.supabaseUrl}/functions/v1/main-mcp-handler`;
|
|
47
47
|
const response = await fetch(url, {
|
|
48
48
|
method: "POST",
|
|
49
49
|
headers: {
|
|
@@ -91,6 +91,14 @@ var SkillRowSchema = z.object({
|
|
|
91
91
|
source_skill_id: z.string().optional().nullable(),
|
|
92
92
|
invocation_count: z.number().optional().default(0)
|
|
93
93
|
});
|
|
94
|
+
var JobAgentSchema = z.object({
|
|
95
|
+
agent_id: z.string(),
|
|
96
|
+
agent_username: z.string(),
|
|
97
|
+
agent_name: z.string().optional().default(""),
|
|
98
|
+
agent_bio: z.string().optional().nullable(),
|
|
99
|
+
agent_prompt: z.string(),
|
|
100
|
+
role: z.string().optional().default("primary")
|
|
101
|
+
});
|
|
94
102
|
var JobRowSchema = z.object({
|
|
95
103
|
job_id: z.string(),
|
|
96
104
|
job_name: z.string(),
|
|
@@ -100,14 +108,16 @@ var JobRowSchema = z.object({
|
|
|
100
108
|
skill_name: z.string().optional().nullable(),
|
|
101
109
|
skill_description: z.string().optional().default(""),
|
|
102
110
|
skill_emoji: z.string().optional().default(""),
|
|
103
|
-
skill_content: z.string().optional().default("")
|
|
111
|
+
skill_content: z.string().optional().default(""),
|
|
112
|
+
agents: z.array(JobAgentSchema).optional().default([])
|
|
104
113
|
});
|
|
105
114
|
var JobListRowSchema = z.object({
|
|
106
115
|
id: z.string(),
|
|
107
116
|
name: z.string(),
|
|
108
117
|
description: z.string().optional().default(""),
|
|
109
118
|
prompt: z.string().optional().nullable(),
|
|
110
|
-
skill_count: z.number().optional().default(0)
|
|
119
|
+
skill_count: z.number().optional().default(0),
|
|
120
|
+
agent_count: z.number().optional().default(0)
|
|
111
121
|
});
|
|
112
122
|
var JobRunRowSchema = z.object({
|
|
113
123
|
run_id: z.string(),
|
|
@@ -193,6 +203,15 @@ var JobRunner = class {
|
|
|
193
203
|
const rows = data.map((row) => safeParse(JobRowSchema, row)).filter((r) => r != null);
|
|
194
204
|
if (rows.length === 0) return null;
|
|
195
205
|
const first = rows[0];
|
|
206
|
+
const rawAgents = first.agents || [];
|
|
207
|
+
const agents = rawAgents.map((a) => safeParse(JobAgentSchema, a)).filter((a) => a != null).map((a) => ({
|
|
208
|
+
agentId: a.agent_id,
|
|
209
|
+
agentUsername: a.agent_username,
|
|
210
|
+
agentName: a.agent_name || "",
|
|
211
|
+
agentBio: a.agent_bio ?? null,
|
|
212
|
+
agentPrompt: a.agent_prompt,
|
|
213
|
+
role: a.role
|
|
214
|
+
}));
|
|
196
215
|
return {
|
|
197
216
|
jobId: first.job_id,
|
|
198
217
|
jobName: first.job_name,
|
|
@@ -204,7 +223,8 @@ var JobRunner = class {
|
|
|
204
223
|
skillDescription: row.skill_description,
|
|
205
224
|
skillEmoji: row.skill_emoji,
|
|
206
225
|
skillContent: row.skill_content
|
|
207
|
-
}))
|
|
226
|
+
})),
|
|
227
|
+
agents
|
|
208
228
|
};
|
|
209
229
|
} catch (err) {
|
|
210
230
|
log.debug(`Failed to load job "${jobName}": ${errorMessage(err)}`);
|
|
@@ -221,7 +241,8 @@ var JobRunner = class {
|
|
|
221
241
|
id: row.id,
|
|
222
242
|
name: row.name,
|
|
223
243
|
description: row.description,
|
|
224
|
-
skillCount: row.skill_count
|
|
244
|
+
skillCount: row.skill_count,
|
|
245
|
+
agentCount: row.agent_count
|
|
225
246
|
}));
|
|
226
247
|
} catch (err) {
|
|
227
248
|
log.debug(`Failed to list jobs: ${errorMessage(err)}`);
|
|
@@ -313,6 +334,9 @@ var JobRunner = class {
|
|
|
313
334
|
`;
|
|
314
335
|
}
|
|
315
336
|
prompt += `## Instructions
|
|
337
|
+
|
|
338
|
+
`;
|
|
339
|
+
prompt += `### Step 1: Analyze and set up skills
|
|
316
340
|
`;
|
|
317
341
|
prompt += `For each capability the job needs:
|
|
318
342
|
`;
|
|
@@ -326,8 +350,24 @@ var JobRunner = class {
|
|
|
326
350
|
|
|
327
351
|
`;
|
|
328
352
|
prompt += `Be practical \u2014 only create skills that would genuinely help automate this job.
|
|
353
|
+
|
|
354
|
+
`;
|
|
355
|
+
prompt += `### Step 2: Create the job's agent
|
|
356
|
+
`;
|
|
357
|
+
prompt += `After setting up skills, create an agent for this job using \`job_assign_agent\`.
|
|
358
|
+
`;
|
|
359
|
+
prompt += `The agent is the identity that will execute this job. Design it with:
|
|
329
360
|
`;
|
|
330
|
-
prompt +=
|
|
361
|
+
prompt += `- **agent_name**: A concise, role-based name (e.g. "Daily Reporter", "Code Reviewer")
|
|
362
|
+
`;
|
|
363
|
+
prompt += `- **agent_prompt**: A system prompt that defines the agent's behavior, expertise, and personality. `;
|
|
364
|
+
prompt += `Include the job's goals, preferred approach, and any domain knowledge the agent should have. `;
|
|
365
|
+
prompt += `Reference the linked skills as capabilities the agent can use.
|
|
366
|
+
`;
|
|
367
|
+
prompt += `- **agent_bio**: A one-line description of what this agent does.
|
|
368
|
+
|
|
369
|
+
`;
|
|
370
|
+
prompt += `When done, summarize what skills were created/updated and the agent that was assigned.
|
|
331
371
|
`;
|
|
332
372
|
return prompt;
|
|
333
373
|
}
|
|
@@ -340,6 +380,10 @@ var JobRunner = class {
|
|
|
340
380
|
* chain them based on what it discovers at runtime.
|
|
341
381
|
*/
|
|
342
382
|
buildJobPrompt(job, runId) {
|
|
383
|
+
const primaryAgent = job.agents.length > 0 ? job.agents.find((a) => a.role === "primary") || job.agents[0] : null;
|
|
384
|
+
const parallelAgents = job.agents.filter(
|
|
385
|
+
(a) => a.role === "parallel" && a.agentId !== primaryAgent?.agentId
|
|
386
|
+
);
|
|
343
387
|
const effectiveDescription = job.jobPrompt || job.jobDescription;
|
|
344
388
|
let prompt = `## Job: ${job.jobName}
|
|
345
389
|
`;
|
|
@@ -349,10 +393,43 @@ var JobRunner = class {
|
|
|
349
393
|
prompt += `**Run ID:** ${runId}
|
|
350
394
|
|
|
351
395
|
`;
|
|
352
|
-
|
|
353
|
-
|
|
396
|
+
if (primaryAgent) {
|
|
397
|
+
prompt += `## Agent Identity
|
|
398
|
+
`;
|
|
399
|
+
prompt += `You are **${primaryAgent.agentName}** (@${primaryAgent.agentUsername}).
|
|
400
|
+
`;
|
|
401
|
+
if (primaryAgent.agentBio) {
|
|
402
|
+
prompt += `*${primaryAgent.agentBio}*
|
|
403
|
+
`;
|
|
404
|
+
}
|
|
405
|
+
prompt += `
|
|
406
|
+
### Agent Instructions
|
|
407
|
+
`;
|
|
408
|
+
prompt += `${primaryAgent.agentPrompt}
|
|
409
|
+
|
|
410
|
+
`;
|
|
411
|
+
} else {
|
|
412
|
+
prompt += `You are now acting as "${job.jobName}". `;
|
|
413
|
+
prompt += `Your goal is to accomplish the objectives described above using the skills and tools available to you.
|
|
414
|
+
|
|
415
|
+
`;
|
|
416
|
+
}
|
|
417
|
+
if (parallelAgents.length > 0) {
|
|
418
|
+
prompt += `### Parallel Agents
|
|
419
|
+
`;
|
|
420
|
+
prompt += `The following agents are running concurrently on this job. `;
|
|
421
|
+
prompt += `They handle their own tasks independently \u2014 coordinate to avoid duplicate work.
|
|
354
422
|
|
|
355
423
|
`;
|
|
424
|
+
for (const pa of parallelAgents) {
|
|
425
|
+
prompt += `- **${pa.agentName}** (@${pa.agentUsername})`;
|
|
426
|
+
if (pa.agentBio) prompt += ` \u2014 ${pa.agentBio}`;
|
|
427
|
+
prompt += `
|
|
428
|
+
`;
|
|
429
|
+
}
|
|
430
|
+
prompt += `
|
|
431
|
+
`;
|
|
432
|
+
}
|
|
356
433
|
prompt += `### Available Skills
|
|
357
434
|
`;
|
|
358
435
|
prompt += `These skills are your capabilities for this job. `;
|
package/dist/index.js
CHANGED
|
@@ -34,11 +34,11 @@ import {
|
|
|
34
34
|
setSessionBusy,
|
|
35
35
|
toggleScheduledTask,
|
|
36
36
|
updateHeartbeat
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-O5K33FBW.js";
|
|
38
38
|
import {
|
|
39
39
|
JobRunner,
|
|
40
40
|
callMcpHandler
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-RRMI6RDG.js";
|
|
42
42
|
import {
|
|
43
43
|
log,
|
|
44
44
|
setLogConversationId,
|
|
@@ -382,7 +382,7 @@ function registerJobCommands(program2) {
|
|
|
382
382
|
jobCmd.command("list").description("List your defined jobs").action(async () => {
|
|
383
383
|
try {
|
|
384
384
|
await getCurrentUserId();
|
|
385
|
-
const { JobRunner: JobRunner2 } = await import("./job-runner-
|
|
385
|
+
const { JobRunner: JobRunner2 } = await import("./job-runner-4KTCVIQP.js");
|
|
386
386
|
const runner = new JobRunner2();
|
|
387
387
|
const jobs = await runner.listJobs();
|
|
388
388
|
if (jobs.length === 0) {
|
|
@@ -406,7 +406,7 @@ function registerJobCommands(program2) {
|
|
|
406
406
|
jobCmd.command("status [name]").description("Show run history for a job (or all jobs)").option("-l, --limit <number>", "Max runs to show (default: 5)").action(async (name, opts) => {
|
|
407
407
|
try {
|
|
408
408
|
await getCurrentUserId();
|
|
409
|
-
const { JobRunner: JobRunner2 } = await import("./job-runner-
|
|
409
|
+
const { JobRunner: JobRunner2 } = await import("./job-runner-4KTCVIQP.js");
|
|
410
410
|
const runner = new JobRunner2();
|
|
411
411
|
const runs = await runner.getRunHistory(name, parseInt(opts.limit || "5"));
|
|
412
412
|
if (runs.length === 0) {
|
|
@@ -454,7 +454,7 @@ Job Run History${name ? ` \u2014 ${name}` : ""}:`));
|
|
|
454
454
|
process.exit(1);
|
|
455
455
|
}
|
|
456
456
|
await getCurrentUserId();
|
|
457
|
-
const { JobRunner: JobRunner2 } = await import("./job-runner-
|
|
457
|
+
const { JobRunner: JobRunner2 } = await import("./job-runner-4KTCVIQP.js");
|
|
458
458
|
const runner = new JobRunner2();
|
|
459
459
|
const job = await runner.loadJob(name);
|
|
460
460
|
if (!job) {
|
|
@@ -2002,7 +2002,31 @@ var Orchestrator = class {
|
|
|
2002
2002
|
} catch (linkErr) {
|
|
2003
2003
|
log.debug(`Failed to link session to job run: ${linkErr}`);
|
|
2004
2004
|
}
|
|
2005
|
-
|
|
2005
|
+
let prompt = runner.buildJobPrompt(job, jobRun.id);
|
|
2006
|
+
const primaryAgent = job.agents.length > 0 ? job.agents.find((a) => a.role === "primary") || job.agents[0] : null;
|
|
2007
|
+
const parallelAgents = job.agents.filter(
|
|
2008
|
+
(a) => a.role === "parallel" && a.agentId !== primaryAgent?.agentId
|
|
2009
|
+
);
|
|
2010
|
+
if (parallelAgents.length > 0) {
|
|
2011
|
+
prompt += `
|
|
2012
|
+
|
|
2013
|
+
---
|
|
2014
|
+
|
|
2015
|
+
## Parallel Agent Responsibilities
|
|
2016
|
+
`;
|
|
2017
|
+
prompt += `The following agents are also assigned. Execute their responsibilities as part of this run:
|
|
2018
|
+
|
|
2019
|
+
`;
|
|
2020
|
+
for (const pa of parallelAgents) {
|
|
2021
|
+
prompt += `### ${pa.agentName}
|
|
2022
|
+
`;
|
|
2023
|
+
if (pa.agentBio) prompt += `*${pa.agentBio}*
|
|
2024
|
+
`;
|
|
2025
|
+
prompt += `**Instructions:** ${pa.agentPrompt}
|
|
2026
|
+
|
|
2027
|
+
`;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2006
2030
|
try {
|
|
2007
2031
|
await this.dispatchAndWait(`[JobRun: ${jobRun.job_name}] ${prompt}`);
|
|
2008
2032
|
await runner.completeRun(jobRun.id, "completed", "Job executed via web trigger");
|