@alook/cli 0.0.10 → 0.0.12
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/index.js +139 -27
- package/dist/session-runner.js +119 -46
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13878,6 +13878,7 @@ var TaskAgentDataApiSchema = exports_external.object({
|
|
|
13878
13878
|
name: exports_external.string(),
|
|
13879
13879
|
runtime_config: exports_external.record(exports_external.string(), exports_external.unknown()).default({}),
|
|
13880
13880
|
email_handle: exports_external.string().nullable().optional(),
|
|
13881
|
+
email_addresses: exports_external.array(exports_external.string()).default([]),
|
|
13881
13882
|
user_email: exports_external.string().nullable().optional()
|
|
13882
13883
|
});
|
|
13883
13884
|
var TaskApiBaseSchema = exports_external.object({
|
|
@@ -14052,7 +14053,9 @@ var SendEmailRequestSchema = exports_external.object({
|
|
|
14052
14053
|
htmlBody: exports_external.string().default(""),
|
|
14053
14054
|
inReplyTo: exports_external.string().optional(),
|
|
14054
14055
|
references: exports_external.string().optional(),
|
|
14055
|
-
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
14056
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional(),
|
|
14057
|
+
customAccountId: exports_external.string().optional(),
|
|
14058
|
+
from: exports_external.string().email().optional()
|
|
14056
14059
|
});
|
|
14057
14060
|
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
14058
14061
|
status: exports_external.enum(["unread", "read", "archived"])
|
|
@@ -14070,6 +14073,48 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
14070
14073
|
inReplyTo: exports_external.string().optional().default(""),
|
|
14071
14074
|
references: exports_external.string().optional().default("")
|
|
14072
14075
|
});
|
|
14076
|
+
var CreateEmailAccountSchema = exports_external.object({
|
|
14077
|
+
emailAddress: exports_external.string().email("valid email required"),
|
|
14078
|
+
displayName: exports_external.string().default(""),
|
|
14079
|
+
imapHost: exports_external.string().min(1, "IMAP host is required"),
|
|
14080
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
14081
|
+
imapUsername: exports_external.string().min(1, "IMAP username is required"),
|
|
14082
|
+
imapPassword: exports_external.string().min(1, "IMAP password is required"),
|
|
14083
|
+
imapTls: exports_external.boolean().default(true),
|
|
14084
|
+
smtpHost: exports_external.string().min(1, "SMTP host is required"),
|
|
14085
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
14086
|
+
smtpUsername: exports_external.string().min(1, "SMTP username is required"),
|
|
14087
|
+
smtpPassword: exports_external.string().min(1, "SMTP password is required"),
|
|
14088
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1),
|
|
14089
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).default(60)
|
|
14090
|
+
});
|
|
14091
|
+
var UpdateEmailAccountSchema = exports_external.object({
|
|
14092
|
+
emailAddress: exports_external.string().email().optional(),
|
|
14093
|
+
displayName: exports_external.string().optional(),
|
|
14094
|
+
imapHost: exports_external.string().min(1).optional(),
|
|
14095
|
+
imapPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
14096
|
+
imapUsername: exports_external.string().min(1).optional(),
|
|
14097
|
+
imapPassword: exports_external.string().min(1).optional(),
|
|
14098
|
+
imapTls: exports_external.boolean().optional(),
|
|
14099
|
+
smtpHost: exports_external.string().min(1).optional(),
|
|
14100
|
+
smtpPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
14101
|
+
smtpUsername: exports_external.string().min(1).optional(),
|
|
14102
|
+
smtpPassword: exports_external.string().min(1).optional(),
|
|
14103
|
+
smtpTls: exports_external.number().int().min(0).max(2).optional(),
|
|
14104
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).optional()
|
|
14105
|
+
});
|
|
14106
|
+
var TestEmailConnectionSchema = exports_external.object({
|
|
14107
|
+
imapHost: exports_external.string().min(1),
|
|
14108
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
14109
|
+
imapUsername: exports_external.string().min(1),
|
|
14110
|
+
imapPassword: exports_external.string().min(1),
|
|
14111
|
+
imapTls: exports_external.boolean().default(true),
|
|
14112
|
+
smtpHost: exports_external.string().min(1),
|
|
14113
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
14114
|
+
smtpUsername: exports_external.string().min(1),
|
|
14115
|
+
smtpPassword: exports_external.string().min(1),
|
|
14116
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1)
|
|
14117
|
+
});
|
|
14073
14118
|
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
14074
14119
|
name: exports_external.string().min(1, "name is required"),
|
|
14075
14120
|
slug: exports_external.string().min(1, "slug is required")
|
|
@@ -15683,6 +15728,37 @@ var artifact = sqliteTable("artifact", {
|
|
|
15683
15728
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15684
15729
|
}).onDelete("cascade")
|
|
15685
15730
|
]);
|
|
15731
|
+
var agentEmailAccount = sqliteTable("agent_email_account", {
|
|
15732
|
+
id: text("id").primaryKey().$defaultFn(() => "aea_" + nanoid3()),
|
|
15733
|
+
agentId: text("agent_id").notNull(),
|
|
15734
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15735
|
+
emailAddress: text("email_address").notNull(),
|
|
15736
|
+
displayName: text("display_name").notNull().default(""),
|
|
15737
|
+
imapHost: text("imap_host").notNull(),
|
|
15738
|
+
imapPort: integer2("imap_port").notNull().default(993),
|
|
15739
|
+
imapUsername: text("imap_username").notNull(),
|
|
15740
|
+
imapPassword: text("imap_password").notNull(),
|
|
15741
|
+
imapTls: integer2("imap_tls", { mode: "boolean" }).notNull().default(true),
|
|
15742
|
+
smtpHost: text("smtp_host").notNull(),
|
|
15743
|
+
smtpPort: integer2("smtp_port").notNull().default(587),
|
|
15744
|
+
smtpUsername: text("smtp_username").notNull(),
|
|
15745
|
+
smtpPassword: text("smtp_password").notNull(),
|
|
15746
|
+
smtpTls: integer2("smtp_tls").notNull().default(1),
|
|
15747
|
+
pollIntervalSeconds: integer2("poll_interval_seconds").notNull().default(60),
|
|
15748
|
+
lastSyncedUid: text("last_synced_uid").notNull().default("0"),
|
|
15749
|
+
lastSyncedAt: text("last_synced_at"),
|
|
15750
|
+
status: text("status").notNull().default("active"),
|
|
15751
|
+
errorMessage: text("error_message").notNull().default(""),
|
|
15752
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15753
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15754
|
+
}, (t) => [
|
|
15755
|
+
index("idx_email_account_agent_ws").on(t.agentId, t.workspaceId),
|
|
15756
|
+
unique("email_account_agent_email").on(t.agentId, t.emailAddress),
|
|
15757
|
+
foreignKey({
|
|
15758
|
+
columns: [t.agentId, t.workspaceId],
|
|
15759
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15760
|
+
}).onDelete("cascade")
|
|
15761
|
+
]);
|
|
15686
15762
|
var machineToken = sqliteTable("machine_token", {
|
|
15687
15763
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15688
15764
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -15823,6 +15899,10 @@ function pidFilePath(profile) {
|
|
|
15823
15899
|
const name = profile ? `daemon_${profile}.pid` : "daemon.pid";
|
|
15824
15900
|
return join3(configDir(), name);
|
|
15825
15901
|
}
|
|
15902
|
+
function lastUpdateMarkerPath(profile) {
|
|
15903
|
+
const name = profile ? `last_update_${profile}` : "last_update";
|
|
15904
|
+
return join3(configDir(), name);
|
|
15905
|
+
}
|
|
15826
15906
|
function daemonLogDir() {
|
|
15827
15907
|
return join3(configDir(), "daemon", "logs");
|
|
15828
15908
|
}
|
|
@@ -15884,7 +15964,7 @@ function loadDaemonConfig(profile) {
|
|
|
15884
15964
|
codexModel: process.env.ALOOK_CODEX_MODEL || "",
|
|
15885
15965
|
opencodeModel: process.env.ALOOK_OPENCODE_MODEL || "",
|
|
15886
15966
|
pollInterval: parseDuration(process.env.ALOOK_DAEMON_POLL_INTERVAL || "3s"),
|
|
15887
|
-
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "
|
|
15967
|
+
agentTimeout: parseDuration(process.env.ALOOK_AGENT_TIMEOUT || "12h"),
|
|
15888
15968
|
maxConcurrentTasks: parseInt(process.env.ALOOK_DAEMON_MAX_CONCURRENT_TASKS || "20"),
|
|
15889
15969
|
daemonId,
|
|
15890
15970
|
deviceName: process.env.ALOOK_DAEMON_DEVICE_NAME || h,
|
|
@@ -15960,7 +16040,7 @@ function fromApiTask(api2) {
|
|
|
15960
16040
|
type: api2.type,
|
|
15961
16041
|
contextKey: api2.context_key ?? null,
|
|
15962
16042
|
context: api2.context ?? undefined,
|
|
15963
|
-
agent: api2.agent ? { name: api2.agent.name, instructions: api2.agent.instructions, emailHandle: api2.agent.email_handle ?? undefined, userEmail: api2.agent.user_email ?? undefined, runtimeConfig: api2.agent.runtime_config ?? undefined } : undefined,
|
|
16043
|
+
agent: api2.agent ? { name: api2.agent.name, instructions: api2.agent.instructions, emailHandle: api2.agent.email_handle ?? undefined, emailAddresses: api2.agent.email_addresses ?? [], userEmail: api2.agent.user_email ?? undefined, runtimeConfig: api2.agent.runtime_config ?? undefined } : undefined,
|
|
15964
16044
|
repos: undefined,
|
|
15965
16045
|
createdAt: api2.created_at
|
|
15966
16046
|
};
|
|
@@ -15997,10 +16077,13 @@ function useColor() {
|
|
|
15997
16077
|
}
|
|
15998
16078
|
function timestamp() {
|
|
15999
16079
|
const d = new Date;
|
|
16080
|
+
const Y = d.getFullYear();
|
|
16081
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
16082
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
16000
16083
|
const h = String(d.getHours()).padStart(2, "0");
|
|
16001
16084
|
const m = String(d.getMinutes()).padStart(2, "0");
|
|
16002
16085
|
const s = String(d.getSeconds()).padStart(2, "0");
|
|
16003
|
-
return `${h}:${m}:${s}`;
|
|
16086
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
16004
16087
|
}
|
|
16005
16088
|
|
|
16006
16089
|
class Logger2 {
|
|
@@ -16104,6 +16187,9 @@ function releaseDaemonPid(profile) {
|
|
|
16104
16187
|
removePidFileIfMatches(process.pid, profile);
|
|
16105
16188
|
}
|
|
16106
16189
|
|
|
16190
|
+
// daemon/update-handler.ts
|
|
16191
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
16192
|
+
|
|
16107
16193
|
// lib/update.ts
|
|
16108
16194
|
import { spawn } from "child_process";
|
|
16109
16195
|
function fetchLatestVersion() {
|
|
@@ -16138,16 +16224,39 @@ var MAX_RETRIES = 3;
|
|
|
16138
16224
|
function isUpdating() {
|
|
16139
16225
|
return updating;
|
|
16140
16226
|
}
|
|
16141
|
-
|
|
16227
|
+
function readUpdateMarker(profile) {
|
|
16228
|
+
try {
|
|
16229
|
+
return readFileSync4(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
|
|
16230
|
+
} catch {
|
|
16231
|
+
return null;
|
|
16232
|
+
}
|
|
16233
|
+
}
|
|
16234
|
+
function writeUpdateMarker(version3, profile) {
|
|
16235
|
+
try {
|
|
16236
|
+
writeFileSync3(lastUpdateMarkerPath(profile), version3, { mode: 384 });
|
|
16237
|
+
} catch {}
|
|
16238
|
+
}
|
|
16239
|
+
function clearUpdateMarker(profile) {
|
|
16240
|
+
try {
|
|
16241
|
+
unlinkSync2(lastUpdateMarkerPath(profile));
|
|
16242
|
+
} catch {}
|
|
16243
|
+
}
|
|
16244
|
+
async function handleCliUpdate(version3, onSuccess, profile) {
|
|
16142
16245
|
if (updating)
|
|
16143
16246
|
return;
|
|
16144
16247
|
if (retryCount >= MAX_RETRIES)
|
|
16145
16248
|
return;
|
|
16249
|
+
const marker = readUpdateMarker(profile);
|
|
16250
|
+
if (marker === version3) {
|
|
16251
|
+
log.info(`Skipping update to v${version3} — already attempted (marker exists)`);
|
|
16252
|
+
return;
|
|
16253
|
+
}
|
|
16146
16254
|
updating = true;
|
|
16147
16255
|
try {
|
|
16148
16256
|
log.info(`Updating CLI to v${version3}...`);
|
|
16149
16257
|
const result = await runNpmUpdate(version3);
|
|
16150
16258
|
if (result.success) {
|
|
16259
|
+
writeUpdateMarker(version3, profile);
|
|
16151
16260
|
log.info(`CLI updated to v${version3} — restarting`);
|
|
16152
16261
|
onSuccess();
|
|
16153
16262
|
} else {
|
|
@@ -16163,7 +16272,7 @@ async function handleCliUpdate(version3, onSuccess) {
|
|
|
16163
16272
|
}
|
|
16164
16273
|
|
|
16165
16274
|
// daemon/daemon.ts
|
|
16166
|
-
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync,
|
|
16275
|
+
import { existsSync, mkdirSync as mkdirSync3, openSync, closeSync, readdirSync, statSync, unlinkSync as unlinkSync3 } from "fs";
|
|
16167
16276
|
import { execSync as execSync3, spawn as spawn2 } from "child_process";
|
|
16168
16277
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16169
16278
|
import { dirname as dirname3, join as join4 } from "path";
|
|
@@ -16200,7 +16309,7 @@ function pruneSessionRunnerLogs() {
|
|
|
16200
16309
|
withMtime.sort((a, b) => b.mtime - a.mtime);
|
|
16201
16310
|
for (const entry of withMtime.slice(MAX_SESSION_RUNNER_LOGS)) {
|
|
16202
16311
|
try {
|
|
16203
|
-
|
|
16312
|
+
unlinkSync3(join4(logDir, entry.name));
|
|
16204
16313
|
} catch {}
|
|
16205
16314
|
}
|
|
16206
16315
|
}
|
|
@@ -16220,6 +16329,11 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16220
16329
|
const config2 = loadDaemonConfig(profile);
|
|
16221
16330
|
if (serverUrl)
|
|
16222
16331
|
config2.serverURL = serverUrl;
|
|
16332
|
+
const marker = readUpdateMarker(profile);
|
|
16333
|
+
if (marker && marker === config2.cliVersion) {
|
|
16334
|
+
clearUpdateMarker(profile);
|
|
16335
|
+
log.info(`Cleared update marker — now running v${config2.cliVersion}`);
|
|
16336
|
+
}
|
|
16223
16337
|
const cliConfig = loadCLIConfigForProfile(profile);
|
|
16224
16338
|
const workspaces = cliConfig.watched_workspaces || [];
|
|
16225
16339
|
if (workspaces.length === 0) {
|
|
@@ -16360,8 +16474,8 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16360
16474
|
evictedIds.push(ws.workspaceId);
|
|
16361
16475
|
continue;
|
|
16362
16476
|
}
|
|
16363
|
-
if (pending_update && !isUpdating()) {
|
|
16364
|
-
handleCliUpdate(pending_update.version, () => requestRestart());
|
|
16477
|
+
if (pending_update && !isUpdating() && pending_update.version !== config2.cliVersion) {
|
|
16478
|
+
handleCliUpdate(pending_update.version, () => requestRestart(), profile);
|
|
16365
16479
|
}
|
|
16366
16480
|
for (const apiTask of apiTasks) {
|
|
16367
16481
|
const task = fromApiTask(apiTask);
|
|
@@ -16433,21 +16547,18 @@ async function startDaemon(profile, serverUrl) {
|
|
|
16433
16547
|
await pollCycle();
|
|
16434
16548
|
}
|
|
16435
16549
|
function spawnSessionRunner(input) {
|
|
16436
|
-
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16437
16550
|
const logDir = sessionRunnerLogDir();
|
|
16438
16551
|
mkdirSync3(logDir, { recursive: true });
|
|
16439
|
-
const
|
|
16440
|
-
|
|
16552
|
+
const logFilePath = join4(logDir, `${input.task.id}.log`);
|
|
16553
|
+
input.logFilePath = logFilePath;
|
|
16554
|
+
const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
|
|
16555
|
+
const fd = openSync(logFilePath, "a");
|
|
16441
16556
|
const child = spawn2(process.execPath, [sessionRunnerPath, encoded], {
|
|
16442
16557
|
detached: true,
|
|
16443
16558
|
stdio: ["ignore", fd, fd]
|
|
16444
16559
|
});
|
|
16445
16560
|
child.unref();
|
|
16446
16561
|
closeSync(fd);
|
|
16447
|
-
if (child.pid) {
|
|
16448
|
-
const pidLogPath = join4(logDir, `${child.pid}.log`);
|
|
16449
|
-
renameSync(tmpLogPath, pidLogPath);
|
|
16450
|
-
}
|
|
16451
16562
|
return child;
|
|
16452
16563
|
}
|
|
16453
16564
|
async function handleTask(client, config2, runtimeIndex, task, token, activeTasks) {
|
|
@@ -16630,7 +16741,7 @@ function configCommand() {
|
|
|
16630
16741
|
|
|
16631
16742
|
// commands/email.ts
|
|
16632
16743
|
import { Command as Command5 } from "commander";
|
|
16633
|
-
import { writeFileSync as
|
|
16744
|
+
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
16634
16745
|
import { basename, join as join5 } from "path";
|
|
16635
16746
|
import PostalMime from "postal-mime";
|
|
16636
16747
|
var VALID_STATUSES = ["unread", "read", "archived"];
|
|
@@ -16721,7 +16832,7 @@ function emailCommand() {
|
|
|
16721
16832
|
references: email3.references || ""
|
|
16722
16833
|
};
|
|
16723
16834
|
const metadataPath = join5(emailDir, "metadata.json");
|
|
16724
|
-
|
|
16835
|
+
writeFileSync4(metadataPath, JSON.stringify(metadata, null, 2));
|
|
16725
16836
|
downloadedPaths.push(metadataPath);
|
|
16726
16837
|
let rawMime;
|
|
16727
16838
|
try {
|
|
@@ -16737,12 +16848,12 @@ function emailCommand() {
|
|
|
16737
16848
|
const parsed = await new PostalMime().parse(rawMime);
|
|
16738
16849
|
if (parsed.text) {
|
|
16739
16850
|
const bodyPath = join5(emailDir, "body.txt");
|
|
16740
|
-
|
|
16851
|
+
writeFileSync4(bodyPath, parsed.text);
|
|
16741
16852
|
downloadedPaths.push(bodyPath);
|
|
16742
16853
|
}
|
|
16743
16854
|
if (parsed.html) {
|
|
16744
16855
|
const htmlPath = join5(emailDir, "body.html");
|
|
16745
|
-
|
|
16856
|
+
writeFileSync4(htmlPath, parsed.html);
|
|
16746
16857
|
downloadedPaths.push(htmlPath);
|
|
16747
16858
|
}
|
|
16748
16859
|
if (parsed.attachments && parsed.attachments.length > 0) {
|
|
@@ -16766,7 +16877,7 @@ function emailCommand() {
|
|
|
16766
16877
|
} else {
|
|
16767
16878
|
buf = Buffer.from(content);
|
|
16768
16879
|
}
|
|
16769
|
-
|
|
16880
|
+
writeFileSync4(attPath, buf);
|
|
16770
16881
|
downloadedPaths.push(attPath);
|
|
16771
16882
|
}
|
|
16772
16883
|
}
|
|
@@ -16797,7 +16908,7 @@ function emailCommand() {
|
|
|
16797
16908
|
process.exit(1);
|
|
16798
16909
|
}
|
|
16799
16910
|
});
|
|
16800
|
-
cmd.command("send").description("Send an email from the agent").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--to <addr>", "Recipient email address").requiredOption("--subject <s>", "Subject line").requiredOption("--body-file <path>", "Path to HTML body file").option("--in-reply-to <emailId>", "Email ID to reply to (sets threading headers)").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16911
|
+
cmd.command("send").description("Send an email from the agent").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--to <addr>", "Recipient email address").requiredOption("--subject <s>", "Subject line").requiredOption("--body-file <path>", "Path to HTML body file").option("--from <addr>", "Send from a specific email address (custom mailbox)").option("--in-reply-to <emailId>", "Email ID to reply to (sets threading headers)").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
|
|
16801
16912
|
const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
|
|
16802
16913
|
workspace: opts.workspace,
|
|
16803
16914
|
agentId: opts.agent_id
|
|
@@ -16805,7 +16916,7 @@ function emailCommand() {
|
|
|
16805
16916
|
const client = new APIClient(serverUrl, token, workspaceId);
|
|
16806
16917
|
let htmlBody;
|
|
16807
16918
|
try {
|
|
16808
|
-
htmlBody =
|
|
16919
|
+
htmlBody = readFileSync5(opts.bodyFile, "utf-8");
|
|
16809
16920
|
} catch (err) {
|
|
16810
16921
|
console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
|
|
16811
16922
|
process.exit(1);
|
|
@@ -16821,7 +16932,7 @@ function emailCommand() {
|
|
|
16821
16932
|
let bytes;
|
|
16822
16933
|
let size;
|
|
16823
16934
|
try {
|
|
16824
|
-
bytes =
|
|
16935
|
+
bytes = readFileSync5(path);
|
|
16825
16936
|
size = statSync2(path).size;
|
|
16826
16937
|
} catch (err) {
|
|
16827
16938
|
console.error(`Error: cannot read attachment "${path}": ${err instanceof Error ? err.message : err}`);
|
|
@@ -16858,7 +16969,8 @@ function emailCommand() {
|
|
|
16858
16969
|
subject: opts.subject,
|
|
16859
16970
|
htmlBody,
|
|
16860
16971
|
attachments,
|
|
16861
|
-
...inReplyTo ? { inReplyTo, references } : {}
|
|
16972
|
+
...inReplyTo ? { inReplyTo, references } : {},
|
|
16973
|
+
...opts.from ? { from: opts.from } : {}
|
|
16862
16974
|
});
|
|
16863
16975
|
console.log(`Sent email to ${res.to_email} (id: ${res.id})`);
|
|
16864
16976
|
} catch (err) {
|
|
@@ -17125,7 +17237,7 @@ ${result.output}`);
|
|
|
17125
17237
|
|
|
17126
17238
|
// commands/sync.ts
|
|
17127
17239
|
import { Command as Command9 } from "commander";
|
|
17128
|
-
import { readFileSync as
|
|
17240
|
+
import { readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
17129
17241
|
import { basename as basename2 } from "path";
|
|
17130
17242
|
var MIME_BY_EXT2 = {
|
|
17131
17243
|
".pdf": "application/pdf",
|
|
@@ -17176,7 +17288,7 @@ function syncCommand() {
|
|
|
17176
17288
|
try {
|
|
17177
17289
|
const stat = statSync3(opts.file);
|
|
17178
17290
|
size = stat.size;
|
|
17179
|
-
bytes =
|
|
17291
|
+
bytes = readFileSync6(opts.file);
|
|
17180
17292
|
} catch (err) {
|
|
17181
17293
|
console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
|
|
17182
17294
|
process.exit(1);
|
package/dist/session-runner.js
CHANGED
|
@@ -14,7 +14,6 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// daemon/session-runner.ts
|
|
17
|
-
import { createWriteStream } from "fs";
|
|
18
17
|
import { mkdir, writeFile, rm } from "fs/promises";
|
|
19
18
|
import path from "path";
|
|
20
19
|
|
|
@@ -13596,6 +13595,7 @@ var TaskAgentDataApiSchema = exports_external.object({
|
|
|
13596
13595
|
name: exports_external.string(),
|
|
13597
13596
|
runtime_config: exports_external.record(exports_external.string(), exports_external.unknown()).default({}),
|
|
13598
13597
|
email_handle: exports_external.string().nullable().optional(),
|
|
13598
|
+
email_addresses: exports_external.array(exports_external.string()).default([]),
|
|
13599
13599
|
user_email: exports_external.string().nullable().optional()
|
|
13600
13600
|
});
|
|
13601
13601
|
var TaskApiBaseSchema = exports_external.object({
|
|
@@ -13770,7 +13770,9 @@ var SendEmailRequestSchema = exports_external.object({
|
|
|
13770
13770
|
htmlBody: exports_external.string().default(""),
|
|
13771
13771
|
inReplyTo: exports_external.string().optional(),
|
|
13772
13772
|
references: exports_external.string().optional(),
|
|
13773
|
-
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
13773
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional(),
|
|
13774
|
+
customAccountId: exports_external.string().optional(),
|
|
13775
|
+
from: exports_external.string().email().optional()
|
|
13774
13776
|
});
|
|
13775
13777
|
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
13776
13778
|
status: exports_external.enum(["unread", "read", "archived"])
|
|
@@ -13788,6 +13790,48 @@ var EmailNotifyRequestSchema = exports_external.object({
|
|
|
13788
13790
|
inReplyTo: exports_external.string().optional().default(""),
|
|
13789
13791
|
references: exports_external.string().optional().default("")
|
|
13790
13792
|
});
|
|
13793
|
+
var CreateEmailAccountSchema = exports_external.object({
|
|
13794
|
+
emailAddress: exports_external.string().email("valid email required"),
|
|
13795
|
+
displayName: exports_external.string().default(""),
|
|
13796
|
+
imapHost: exports_external.string().min(1, "IMAP host is required"),
|
|
13797
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
13798
|
+
imapUsername: exports_external.string().min(1, "IMAP username is required"),
|
|
13799
|
+
imapPassword: exports_external.string().min(1, "IMAP password is required"),
|
|
13800
|
+
imapTls: exports_external.boolean().default(true),
|
|
13801
|
+
smtpHost: exports_external.string().min(1, "SMTP host is required"),
|
|
13802
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
13803
|
+
smtpUsername: exports_external.string().min(1, "SMTP username is required"),
|
|
13804
|
+
smtpPassword: exports_external.string().min(1, "SMTP password is required"),
|
|
13805
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1),
|
|
13806
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).default(60)
|
|
13807
|
+
});
|
|
13808
|
+
var UpdateEmailAccountSchema = exports_external.object({
|
|
13809
|
+
emailAddress: exports_external.string().email().optional(),
|
|
13810
|
+
displayName: exports_external.string().optional(),
|
|
13811
|
+
imapHost: exports_external.string().min(1).optional(),
|
|
13812
|
+
imapPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
13813
|
+
imapUsername: exports_external.string().min(1).optional(),
|
|
13814
|
+
imapPassword: exports_external.string().min(1).optional(),
|
|
13815
|
+
imapTls: exports_external.boolean().optional(),
|
|
13816
|
+
smtpHost: exports_external.string().min(1).optional(),
|
|
13817
|
+
smtpPort: exports_external.number().int().min(1).max(65535).optional(),
|
|
13818
|
+
smtpUsername: exports_external.string().min(1).optional(),
|
|
13819
|
+
smtpPassword: exports_external.string().min(1).optional(),
|
|
13820
|
+
smtpTls: exports_external.number().int().min(0).max(2).optional(),
|
|
13821
|
+
pollIntervalSeconds: exports_external.number().int().min(30).max(3600).optional()
|
|
13822
|
+
});
|
|
13823
|
+
var TestEmailConnectionSchema = exports_external.object({
|
|
13824
|
+
imapHost: exports_external.string().min(1),
|
|
13825
|
+
imapPort: exports_external.number().int().min(1).max(65535).default(993),
|
|
13826
|
+
imapUsername: exports_external.string().min(1),
|
|
13827
|
+
imapPassword: exports_external.string().min(1),
|
|
13828
|
+
imapTls: exports_external.boolean().default(true),
|
|
13829
|
+
smtpHost: exports_external.string().min(1),
|
|
13830
|
+
smtpPort: exports_external.number().int().min(1).max(65535).default(587),
|
|
13831
|
+
smtpUsername: exports_external.string().min(1),
|
|
13832
|
+
smtpPassword: exports_external.string().min(1),
|
|
13833
|
+
smtpTls: exports_external.number().int().min(0).max(2).default(1)
|
|
13834
|
+
});
|
|
13791
13835
|
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
13792
13836
|
name: exports_external.string().min(1, "name is required"),
|
|
13793
13837
|
slug: exports_external.string().min(1, "slug is required")
|
|
@@ -15401,6 +15445,37 @@ var artifact = sqliteTable("artifact", {
|
|
|
15401
15445
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15402
15446
|
}).onDelete("cascade")
|
|
15403
15447
|
]);
|
|
15448
|
+
var agentEmailAccount = sqliteTable("agent_email_account", {
|
|
15449
|
+
id: text("id").primaryKey().$defaultFn(() => "aea_" + nanoid3()),
|
|
15450
|
+
agentId: text("agent_id").notNull(),
|
|
15451
|
+
workspaceId: text("workspace_id").notNull(),
|
|
15452
|
+
emailAddress: text("email_address").notNull(),
|
|
15453
|
+
displayName: text("display_name").notNull().default(""),
|
|
15454
|
+
imapHost: text("imap_host").notNull(),
|
|
15455
|
+
imapPort: integer2("imap_port").notNull().default(993),
|
|
15456
|
+
imapUsername: text("imap_username").notNull(),
|
|
15457
|
+
imapPassword: text("imap_password").notNull(),
|
|
15458
|
+
imapTls: integer2("imap_tls", { mode: "boolean" }).notNull().default(true),
|
|
15459
|
+
smtpHost: text("smtp_host").notNull(),
|
|
15460
|
+
smtpPort: integer2("smtp_port").notNull().default(587),
|
|
15461
|
+
smtpUsername: text("smtp_username").notNull(),
|
|
15462
|
+
smtpPassword: text("smtp_password").notNull(),
|
|
15463
|
+
smtpTls: integer2("smtp_tls").notNull().default(1),
|
|
15464
|
+
pollIntervalSeconds: integer2("poll_interval_seconds").notNull().default(60),
|
|
15465
|
+
lastSyncedUid: text("last_synced_uid").notNull().default("0"),
|
|
15466
|
+
lastSyncedAt: text("last_synced_at"),
|
|
15467
|
+
status: text("status").notNull().default("active"),
|
|
15468
|
+
errorMessage: text("error_message").notNull().default(""),
|
|
15469
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
|
|
15470
|
+
updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15471
|
+
}, (t) => [
|
|
15472
|
+
index("idx_email_account_agent_ws").on(t.agentId, t.workspaceId),
|
|
15473
|
+
unique("email_account_agent_email").on(t.agentId, t.emailAddress),
|
|
15474
|
+
foreignKey({
|
|
15475
|
+
columns: [t.agentId, t.workspaceId],
|
|
15476
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15477
|
+
}).onDelete("cascade")
|
|
15478
|
+
]);
|
|
15404
15479
|
var machineToken = sqliteTable("machine_token", {
|
|
15405
15480
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15406
15481
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -16421,7 +16496,7 @@ function createBackend(provider, cliPath) {
|
|
|
16421
16496
|
|
|
16422
16497
|
// daemon/execenv/index.ts
|
|
16423
16498
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
16424
|
-
import { join as join3
|
|
16499
|
+
import { join as join3 } from "path";
|
|
16425
16500
|
|
|
16426
16501
|
// daemon/execenv/context.ts
|
|
16427
16502
|
import { createHash } from "crypto";
|
|
@@ -16499,9 +16574,18 @@ ${task.agent.instructions}
|
|
|
16499
16574
|
You can communicate with the world through Alook CLI.
|
|
16500
16575
|
Your alook agent id is '${task.agentId}'. remember this, most of alook cli will requires you input your agent id.
|
|
16501
16576
|
`;
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16577
|
+
const alookAddr = task.agent?.emailHandle ? toAlookAddress(task.agent.emailHandle) : null;
|
|
16578
|
+
const customAddrs = (task.agent?.emailAddresses ?? []).filter((a) => a !== alookAddr);
|
|
16579
|
+
if (alookAddr || customAddrs.length > 0) {
|
|
16580
|
+
const lines = [];
|
|
16581
|
+
if (alookAddr)
|
|
16582
|
+
lines.push(`- '${alookAddr}' (default, Alook platform address)`);
|
|
16583
|
+
for (const a of customAddrs)
|
|
16584
|
+
lines.push(`- '${a}' (custom IMAP/SMTP mailbox)`);
|
|
16585
|
+
content += `Your email addresses:
|
|
16586
|
+
${lines.join(`
|
|
16587
|
+
`)}
|
|
16588
|
+
${task.agent?.userEmail ? `Your owner's email address is '${task.agent.userEmail}'.` : ""}
|
|
16505
16589
|
|
|
16506
16590
|
### Emails
|
|
16507
16591
|
---
|
|
@@ -16519,8 +16603,9 @@ Before starting to process an email, mark it as read:
|
|
|
16519
16603
|
#### Sending a new email
|
|
16520
16604
|
Write the HTML body to a file first, then send it. The body is forwarded as-is (HTML).
|
|
16521
16605
|
- Run 'npx @alook/cli email send --agent_id ${task.agentId} --to <ADDRESS> --subject "<SUBJECT>" --body-file <PATH_TO_HTML>'
|
|
16606
|
+
- To send from a specific mailbox, add '--from <YOUR_EMAIL_ADDRESS>'. Without '--from', the default Alook address is used.
|
|
16522
16607
|
- Attach files with '--attachment <PATH>' — repeat the flag for multiple attachments. Each file is uploaded before sending.
|
|
16523
|
-
- Example: 'npx @alook/cli email send --agent_id ${task.agentId} --to foo@bar.com --subject "Weekly report" --body-file /tmp/body.html --
|
|
16608
|
+
- Example: 'npx @alook/cli email send --agent_id ${task.agentId} --to foo@bar.com --subject "Weekly report" --body-file /tmp/body.html --from alice@company.com --attachment /tmp/report.pdf'
|
|
16524
16609
|
|
|
16525
16610
|
#### Replying to an email
|
|
16526
16611
|
To reply to an email, add '--in-reply-to <EMAIL_ID>' to the send command. This sets the correct email threading headers so the recipient's email client groups the reply into the same conversation thread.
|
|
@@ -16708,10 +16793,13 @@ function useColor() {
|
|
|
16708
16793
|
}
|
|
16709
16794
|
function timestamp() {
|
|
16710
16795
|
const d = new Date;
|
|
16796
|
+
const Y = d.getFullYear();
|
|
16797
|
+
const M = String(d.getMonth() + 1).padStart(2, "0");
|
|
16798
|
+
const D = String(d.getDate()).padStart(2, "0");
|
|
16711
16799
|
const h = String(d.getHours()).padStart(2, "0");
|
|
16712
16800
|
const m = String(d.getMinutes()).padStart(2, "0");
|
|
16713
16801
|
const s = String(d.getSeconds()).padStart(2, "0");
|
|
16714
|
-
return `${h}:${m}:${s}`;
|
|
16802
|
+
return `${Y}-${M}-${D} ${h}:${m}:${s}`;
|
|
16715
16803
|
}
|
|
16716
16804
|
|
|
16717
16805
|
class Logger2 {
|
|
@@ -16896,7 +16984,7 @@ function updateEntry(timelineDir, taskId, updater) {
|
|
|
16896
16984
|
}
|
|
16897
16985
|
log.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
|
|
16898
16986
|
}
|
|
16899
|
-
function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey) {
|
|
16987
|
+
function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
|
|
16900
16988
|
return {
|
|
16901
16989
|
task_id: taskId,
|
|
16902
16990
|
context_key: contextKey ?? null,
|
|
@@ -16908,7 +16996,8 @@ function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, con
|
|
|
16908
16996
|
prompt,
|
|
16909
16997
|
agent_responses: [],
|
|
16910
16998
|
errmsg: null,
|
|
16911
|
-
provider: provider ?? null
|
|
16999
|
+
provider: provider ?? null,
|
|
17000
|
+
detailed_log: detailedLog ?? null
|
|
16912
17001
|
};
|
|
16913
17002
|
}
|
|
16914
17003
|
var DEFAULT_RESUME_MAX_AGE_MS = 3 * 60 * 60 * 1000;
|
|
@@ -16938,8 +17027,6 @@ function prepare(config2, task) {
|
|
|
16938
17027
|
const timelineDir = join3(workDir, ".context_timeline");
|
|
16939
17028
|
mkdirSync2(timelineDir, { recursive: true });
|
|
16940
17029
|
writeInstructionFileIfChanged(workDir, task);
|
|
16941
|
-
const logFile = join3(config2.workspacesRoot, task.workspaceId, task.agentId, "agent.log");
|
|
16942
|
-
mkdirSync2(dirname(logFile), { recursive: true });
|
|
16943
17030
|
const env = {
|
|
16944
17031
|
ALOOK_WORKSPACE_ID: task.workspaceId,
|
|
16945
17032
|
ALOOK_AGENT_ID: task.agentId,
|
|
@@ -16947,7 +17034,7 @@ function prepare(config2, task) {
|
|
|
16947
17034
|
ALOOK_CONVERSATION_ID: task.conversationId,
|
|
16948
17035
|
ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514"
|
|
16949
17036
|
};
|
|
16950
|
-
return { workDir,
|
|
17037
|
+
return { workDir, timelineDir, env };
|
|
16951
17038
|
}
|
|
16952
17039
|
|
|
16953
17040
|
// daemon/prompt.ts
|
|
@@ -16993,18 +17080,21 @@ async function downloadAttachments(client, token, workspaceId, taskId, attachmen
|
|
|
16993
17080
|
}
|
|
16994
17081
|
async function runSession(input) {
|
|
16995
17082
|
const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout } = input;
|
|
17083
|
+
log.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
|
|
16996
17084
|
const client = new DaemonClient(serverURL);
|
|
16997
17085
|
const backend = createBackend(provider, cliPath);
|
|
16998
|
-
const { workDir,
|
|
17086
|
+
const { workDir, timelineDir, env } = prepare({ workspacesRoot }, task);
|
|
16999
17087
|
const attachmentIds = task.context?.attachment_ids ?? [];
|
|
17000
17088
|
let attachments;
|
|
17001
17089
|
if (attachmentIds.length > 0) {
|
|
17090
|
+
log.info(`downloading ${attachmentIds.length} attachment(s)`);
|
|
17002
17091
|
try {
|
|
17003
17092
|
attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
|
|
17093
|
+
log.info(`attachments ready (${attachments.length} file(s))`);
|
|
17004
17094
|
} catch (e) {
|
|
17005
17095
|
await cleanupAttachments(task.id);
|
|
17006
17096
|
const errMsg = `failed to download attachments: ${e}`;
|
|
17007
|
-
log.error(
|
|
17097
|
+
log.error(errMsg);
|
|
17008
17098
|
await client.failTask(token, task.id, errMsg);
|
|
17009
17099
|
return;
|
|
17010
17100
|
}
|
|
@@ -17012,7 +17102,7 @@ async function runSession(input) {
|
|
|
17012
17102
|
const prompt = buildPrompt(task, attachments);
|
|
17013
17103
|
const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
|
|
17014
17104
|
if (resumeSessionId) {
|
|
17015
|
-
log.info(`
|
|
17105
|
+
log.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
|
|
17016
17106
|
}
|
|
17017
17107
|
const session2 = backend.execute(prompt, {
|
|
17018
17108
|
cwd: workDir,
|
|
@@ -17023,9 +17113,12 @@ async function runSession(input) {
|
|
|
17023
17113
|
});
|
|
17024
17114
|
const agentPid = session2.pid;
|
|
17025
17115
|
const earlySessionId = await session2.sessionId;
|
|
17026
|
-
|
|
17116
|
+
log.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
|
|
17117
|
+
log.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
|
|
17118
|
+
await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, earlySessionId, process.pid, provider, task.contextKey, input.logFilePath));
|
|
17027
17119
|
const pendingMessages = [];
|
|
17028
17120
|
let seq = 0;
|
|
17121
|
+
let toolCount = 0;
|
|
17029
17122
|
const BATCH_SIZE = Number(process.env.ALOOK_MESSAGE_BATCH_SIZE) || 20;
|
|
17030
17123
|
const FLUSH_INTERVAL_MS = Number(process.env.ALOOK_MESSAGE_FLUSH_INTERVAL_MS) || 100;
|
|
17031
17124
|
const flushMessages = async () => {
|
|
@@ -17035,29 +17128,16 @@ async function runSession(input) {
|
|
|
17035
17128
|
try {
|
|
17036
17129
|
await client.reportMessages(token, task.id, batch);
|
|
17037
17130
|
} catch (e) {
|
|
17038
|
-
log.debug(
|
|
17131
|
+
log.debug("message report failed", e);
|
|
17039
17132
|
}
|
|
17040
17133
|
};
|
|
17041
17134
|
const flushTimer = setInterval(flushMessages, FLUSH_INTERVAL_MS);
|
|
17042
|
-
let logStream;
|
|
17043
|
-
try {
|
|
17044
|
-
logStream = createWriteStream(logFile, { flags: "a" });
|
|
17045
|
-
logStream.write(JSON.stringify({
|
|
17046
|
-
ts: localISOString(),
|
|
17047
|
-
type: "text",
|
|
17048
|
-
role: "user",
|
|
17049
|
-
content: prompt
|
|
17050
|
-
}) + `
|
|
17051
|
-
`);
|
|
17052
|
-
} catch {
|
|
17053
|
-
logStream = undefined;
|
|
17054
|
-
}
|
|
17055
17135
|
let killed = false;
|
|
17056
17136
|
const onKill = async () => {
|
|
17057
17137
|
if (killed)
|
|
17058
17138
|
return;
|
|
17059
17139
|
killed = true;
|
|
17060
|
-
log.info(`
|
|
17140
|
+
log.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
|
|
17061
17141
|
if (agentPid) {
|
|
17062
17142
|
try {
|
|
17063
17143
|
process.kill(agentPid, "SIGTERM");
|
|
@@ -17067,7 +17147,6 @@ async function runSession(input) {
|
|
|
17067
17147
|
try {
|
|
17068
17148
|
await flushMessages();
|
|
17069
17149
|
} catch {}
|
|
17070
|
-
logStream?.end();
|
|
17071
17150
|
await cleanupAttachments(task.id);
|
|
17072
17151
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
17073
17152
|
entry.pid = null;
|
|
@@ -17095,21 +17174,14 @@ async function runSession(input) {
|
|
|
17095
17174
|
input: msg.input,
|
|
17096
17175
|
output: msg.output
|
|
17097
17176
|
});
|
|
17177
|
+
if (msg.type === "tool-use")
|
|
17178
|
+
toolCount++;
|
|
17179
|
+
log.info(JSON.stringify({ role: "assistant", ...msg }));
|
|
17098
17180
|
if (msg.type === "text" && msg.content) {
|
|
17099
17181
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
17100
17182
|
entry.agent_responses.push(msg.content);
|
|
17101
17183
|
});
|
|
17102
17184
|
}
|
|
17103
|
-
if (logStream) {
|
|
17104
|
-
try {
|
|
17105
|
-
logStream.write(JSON.stringify({
|
|
17106
|
-
ts: localISOString(),
|
|
17107
|
-
role: "assistant",
|
|
17108
|
-
...msg
|
|
17109
|
-
}) + `
|
|
17110
|
-
`);
|
|
17111
|
-
} catch {}
|
|
17112
|
-
}
|
|
17113
17185
|
if (pendingMessages.length >= BATCH_SIZE) {
|
|
17114
17186
|
await flushMessages();
|
|
17115
17187
|
}
|
|
@@ -17118,7 +17190,6 @@ async function runSession(input) {
|
|
|
17118
17190
|
await flushMessages();
|
|
17119
17191
|
} finally {
|
|
17120
17192
|
clearInterval(flushTimer);
|
|
17121
|
-
logStream?.end();
|
|
17122
17193
|
process.removeListener("SIGTERM", onKill);
|
|
17123
17194
|
process.removeListener("SIGINT", onKill);
|
|
17124
17195
|
}
|
|
@@ -17152,10 +17223,12 @@ async function runSession(input) {
|
|
|
17152
17223
|
if (result.sessionId)
|
|
17153
17224
|
body.session_id = result.sessionId;
|
|
17154
17225
|
await client.completeTask(token, task.id, body);
|
|
17155
|
-
|
|
17226
|
+
const dur = (result.durationMs / 1000).toFixed(1);
|
|
17227
|
+
log.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
|
|
17156
17228
|
} else {
|
|
17157
17229
|
await client.failTask(token, task.id, result.error || "unknown error");
|
|
17158
|
-
|
|
17230
|
+
const dur = (result.durationMs / 1000).toFixed(1);
|
|
17231
|
+
log.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
|
|
17159
17232
|
}
|
|
17160
17233
|
}
|
|
17161
17234
|
async function main() {
|