@fancyboi999/open-tag-daemon 0.4.0 → 0.5.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/dist/cli.mjs +135 -4
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -5329,6 +5329,132 @@ var cursorRuntime = {
|
|
|
5329
5329
|
}
|
|
5330
5330
|
};
|
|
5331
5331
|
|
|
5332
|
+
// src/daemon/demoRuntime.ts
|
|
5333
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
5334
|
+
var DEMO_NOTICE = "I'm a **demo agent** running on a no-op runtime \u2014 I don't call any LLM, so I can't do real work here. To get a real AI teammate, self-host open-tag and connect a runtime like Claude Code, Codex, or your own API key. See [getopentag.com](https://getopentag.com) to get started.";
|
|
5335
|
+
var GREETINGS = ["Hi there! \u{1F44B}", "Hello again! \u{1F44B}", "Hey! \u{1F44B}", "Thanks for your message! \u{1F44B}", "Received! \u{1F44B}"];
|
|
5336
|
+
function extractBody(text) {
|
|
5337
|
+
const m = /\] [^:]+: (.+)$/s.exec(text);
|
|
5338
|
+
return m ? m[1].trim() : "";
|
|
5339
|
+
}
|
|
5340
|
+
function extractTarget(text) {
|
|
5341
|
+
const m = /^\[target=(\S+)/.exec(text);
|
|
5342
|
+
return m ? m[1] : null;
|
|
5343
|
+
}
|
|
5344
|
+
function buildReply(userBody, turnIndex) {
|
|
5345
|
+
const greeting = GREETINGS[turnIndex % GREETINGS.length];
|
|
5346
|
+
const snippet = userBody.slice(0, 120);
|
|
5347
|
+
const tail = userBody.length > 120 ? "\u2026" : "";
|
|
5348
|
+
const echo = snippet ? `
|
|
5349
|
+
|
|
5350
|
+
> You said: "${snippet}${tail}"` : "";
|
|
5351
|
+
return `${greeting} ${DEMO_NOTICE}${echo}`;
|
|
5352
|
+
}
|
|
5353
|
+
function makeTransport(serverUrl2, agentToken, agentId) {
|
|
5354
|
+
const base = serverUrl2.replace(/\/$/, "");
|
|
5355
|
+
const headers = {
|
|
5356
|
+
"Authorization": `Bearer ${agentToken}`,
|
|
5357
|
+
"x-agent-id": agentId,
|
|
5358
|
+
"Content-Type": "application/json"
|
|
5359
|
+
};
|
|
5360
|
+
return {
|
|
5361
|
+
async check() {
|
|
5362
|
+
const r = await fetch(`${base}/agent-api/message/check`, { headers });
|
|
5363
|
+
const d = await r.json();
|
|
5364
|
+
return d.messages ?? [];
|
|
5365
|
+
},
|
|
5366
|
+
async send(target, content) {
|
|
5367
|
+
await fetch(`${base}/agent-api/message/send`, {
|
|
5368
|
+
method: "POST",
|
|
5369
|
+
headers,
|
|
5370
|
+
body: JSON.stringify({ target, content })
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
5373
|
+
};
|
|
5374
|
+
}
|
|
5375
|
+
var DemoRun = class {
|
|
5376
|
+
constructor(opts, cb, transport) {
|
|
5377
|
+
this.opts = opts;
|
|
5378
|
+
this.cb = cb;
|
|
5379
|
+
this.sessionId = opts.sessionId || randomUUID2();
|
|
5380
|
+
this.transport = transport ?? makeTransport(
|
|
5381
|
+
opts.env.OPEN_TAG_SERVER_URL ?? "",
|
|
5382
|
+
opts.env.OPEN_TAG_AGENT_TOKEN ?? "",
|
|
5383
|
+
opts.env.OPEN_TAG_AGENT_ID ?? ""
|
|
5384
|
+
);
|
|
5385
|
+
cb.onSession(this.sessionId);
|
|
5386
|
+
this.enqueue(opts.initialPrompt);
|
|
5387
|
+
}
|
|
5388
|
+
opts;
|
|
5389
|
+
cb;
|
|
5390
|
+
sessionId;
|
|
5391
|
+
queue = [];
|
|
5392
|
+
turnBusy = false;
|
|
5393
|
+
stopped = false;
|
|
5394
|
+
turnIndex = 0;
|
|
5395
|
+
transport;
|
|
5396
|
+
enqueue(text) {
|
|
5397
|
+
if (this.stopped) return;
|
|
5398
|
+
this.queue.push(text);
|
|
5399
|
+
this.pump();
|
|
5400
|
+
}
|
|
5401
|
+
pump() {
|
|
5402
|
+
if (this.stopped || this.turnBusy || this.queue.length === 0) return;
|
|
5403
|
+
this.runTurn(this.queue.shift());
|
|
5404
|
+
}
|
|
5405
|
+
// Each turn: check messages → for each pending target, build + post a demo reply → mark online.
|
|
5406
|
+
// Uses setImmediate to stay non-blocking before the await chain takes over.
|
|
5407
|
+
runTurn(_prompt) {
|
|
5408
|
+
this.turnBusy = true;
|
|
5409
|
+
this.cb.onActivity("working", "turn");
|
|
5410
|
+
setImmediate(() => void this.executeTurn());
|
|
5411
|
+
}
|
|
5412
|
+
async executeTurn() {
|
|
5413
|
+
if (this.stopped) {
|
|
5414
|
+
this.turnBusy = false;
|
|
5415
|
+
return;
|
|
5416
|
+
}
|
|
5417
|
+
try {
|
|
5418
|
+
const messages = await this.transport.check();
|
|
5419
|
+
if (!messages.length) {
|
|
5420
|
+
this.cb.onActivity("online", "");
|
|
5421
|
+
this.turnBusy = false;
|
|
5422
|
+
this.pump();
|
|
5423
|
+
return;
|
|
5424
|
+
}
|
|
5425
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
5426
|
+
for (const m of messages) {
|
|
5427
|
+
const target = extractTarget(m.text);
|
|
5428
|
+
if (!target) continue;
|
|
5429
|
+
byTarget.set(target, extractBody(m.text));
|
|
5430
|
+
}
|
|
5431
|
+
for (const [target, body] of byTarget) {
|
|
5432
|
+
const reply = buildReply(body, this.turnIndex++);
|
|
5433
|
+
this.cb.onTrajectory([{ kind: "text", text: reply }]);
|
|
5434
|
+
await this.transport.send(target, reply);
|
|
5435
|
+
}
|
|
5436
|
+
} catch (e) {
|
|
5437
|
+
this.cb.log.warn("demo: turn failed", { detail: String(e?.message ?? e) });
|
|
5438
|
+
}
|
|
5439
|
+
if (!this.stopped) {
|
|
5440
|
+
this.cb.onActivity("online", "");
|
|
5441
|
+
this.turnBusy = false;
|
|
5442
|
+
this.pump();
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
stop() {
|
|
5446
|
+
this.stopped = true;
|
|
5447
|
+
}
|
|
5448
|
+
};
|
|
5449
|
+
var demoRuntime = {
|
|
5450
|
+
name: "demo",
|
|
5451
|
+
experimental: true,
|
|
5452
|
+
start(opts, cb) {
|
|
5453
|
+
const run = new DemoRun(opts, cb);
|
|
5454
|
+
return { deliver: (text) => run.enqueue(text), stop: () => run.stop() };
|
|
5455
|
+
}
|
|
5456
|
+
};
|
|
5457
|
+
|
|
5332
5458
|
// src/daemon/runtimes.ts
|
|
5333
5459
|
function has(tool) {
|
|
5334
5460
|
try {
|
|
@@ -5340,9 +5466,9 @@ function has(tool) {
|
|
|
5340
5466
|
}
|
|
5341
5467
|
function detectRuntimes() {
|
|
5342
5468
|
const found = ["claude", "codex", "copilot", "kimi", "opencode", "pi", "cursor-agent"].filter(has).map((t) => t === "cursor-agent" ? "cursor" : t);
|
|
5343
|
-
return found;
|
|
5469
|
+
return [...found, "demo"];
|
|
5344
5470
|
}
|
|
5345
|
-
var REG = { claude: claudeRuntime, codex: codexRuntime, copilot: copilotRuntime, opencode: opencodeRuntime, kimi: kimiRuntime, pi: piRuntime, cursor: cursorRuntime };
|
|
5471
|
+
var REG = { claude: claudeRuntime, codex: codexRuntime, copilot: copilotRuntime, opencode: opencodeRuntime, kimi: kimiRuntime, pi: piRuntime, cursor: cursorRuntime, demo: demoRuntime };
|
|
5346
5472
|
function getRuntime(name) {
|
|
5347
5473
|
return REG[name] ?? null;
|
|
5348
5474
|
}
|
|
@@ -5867,6 +5993,8 @@ async function listModels(runtime) {
|
|
|
5867
5993
|
const models = parseCodexModels(r.stdout);
|
|
5868
5994
|
return models.length ? models : null;
|
|
5869
5995
|
}
|
|
5996
|
+
case "demo":
|
|
5997
|
+
return [{ id: "demo", label: "Demo", provider: "demo", default: true }];
|
|
5870
5998
|
default:
|
|
5871
5999
|
return null;
|
|
5872
6000
|
}
|
|
@@ -5909,8 +6037,11 @@ conn = new Connection(serverUrl, apiKey, (msg) => {
|
|
|
5909
6037
|
case "ready:ack":
|
|
5910
6038
|
if (typeof msg.machineId === "string" && msg.machineId) saveMachineId(msg.machineId);
|
|
5911
6039
|
break;
|
|
6040
|
+
// Agent dials the same server URL this daemon connected with (proven reachable), overriding the
|
|
6041
|
+
// server-reported config.serverUrl (SELF_URL = localhost:PORT on the server box — wrong whenever the
|
|
6042
|
+
// daemon runs on a different host than the server, e.g. local daemon ↔ getopentag.com).
|
|
5912
6043
|
case "agent:start":
|
|
5913
|
-
void mgr.start(msg.agentId, { ...msg.config });
|
|
6044
|
+
void mgr.start(msg.agentId, { ...msg.config, serverUrl });
|
|
5914
6045
|
break;
|
|
5915
6046
|
case "agent:deliver":
|
|
5916
6047
|
mgr.deliver(msg.agentId, msg.from ?? "someone", msg.target ?? "", !!msg.mentioned, { targetName: msg.targetName, msgShort: msg.msgShort, isTask: msg.isTask });
|
|
@@ -5954,7 +6085,7 @@ conn = new Connection(serverUrl, apiKey, (msg) => {
|
|
|
5954
6085
|
runningAgents: mgr.running(),
|
|
5955
6086
|
hostname: os4.hostname(),
|
|
5956
6087
|
os: `${os4.platform()} ${os4.arch()}`,
|
|
5957
|
-
daemonVersion: "0.
|
|
6088
|
+
daemonVersion: "0.5.1",
|
|
5958
6089
|
machineId: readMachineId()
|
|
5959
6090
|
// Stable identity: empty on first connection; server sends it back via ready:ack for persistence.
|
|
5960
6091
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fancyboi999/open-tag-daemon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "open-tag compute-plane daemon — connect any machine to an open-tag server so its agents run there. No repo clone needed.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|