@alook/cli 0.0.9 → 0.0.10
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 +168 -3
- package/dist/session-runner.js +158 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// src/index.ts
|
|
18
|
-
import { Command as
|
|
18
|
+
import { Command as Command10 } from "commander";
|
|
19
19
|
|
|
20
20
|
// commands/register.ts
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -13896,7 +13896,8 @@ var TaskApiBaseSchema = exports_external.object({
|
|
|
13896
13896
|
error: exports_external.string().nullable(),
|
|
13897
13897
|
created_at: exports_external.string(),
|
|
13898
13898
|
type: exports_external.string(),
|
|
13899
|
-
context_key: exports_external.string().nullable().optional()
|
|
13899
|
+
context_key: exports_external.string().nullable().optional(),
|
|
13900
|
+
context: exports_external.unknown().nullable().optional()
|
|
13900
13901
|
});
|
|
13901
13902
|
var TaskApiSchema = TaskApiBaseSchema.extend({
|
|
13902
13903
|
agent: TaskAgentDataApiSchema.nullable().optional()
|
|
@@ -14015,6 +14016,64 @@ var CalendarEventApiSchema = exports_external.object({
|
|
|
14015
14016
|
var AddWhitelistRequestSchema = exports_external.object({
|
|
14016
14017
|
email: exports_external.string().email()
|
|
14017
14018
|
});
|
|
14019
|
+
var RuntimeConfigSchema = exports_external.object({ model: exports_external.string().max(100).optional() }).passthrough().optional();
|
|
14020
|
+
var CreateAgentRequestSchema = exports_external.object({
|
|
14021
|
+
name: exports_external.string().min(1, "name is required"),
|
|
14022
|
+
description: exports_external.string().optional().default(""),
|
|
14023
|
+
instructions: exports_external.string().optional().default(""),
|
|
14024
|
+
runtime_id: exports_external.string().min(1, "runtime_id is required"),
|
|
14025
|
+
runtime_config: RuntimeConfigSchema,
|
|
14026
|
+
max_concurrent_tasks: exports_external.number().int().optional(),
|
|
14027
|
+
email_handle: exports_external.string().optional()
|
|
14028
|
+
});
|
|
14029
|
+
var UpdateAgentRequestSchema = exports_external.object({
|
|
14030
|
+
name: exports_external.string().min(1).optional(),
|
|
14031
|
+
description: exports_external.string().optional(),
|
|
14032
|
+
instructions: exports_external.string().optional(),
|
|
14033
|
+
runtime_id: exports_external.string().min(1).optional(),
|
|
14034
|
+
runtime_config: RuntimeConfigSchema
|
|
14035
|
+
}).refine((v) => v.name !== undefined || v.description !== undefined || v.instructions !== undefined || v.runtime_id !== undefined || v.runtime_config !== undefined, { message: "at least one field is required" });
|
|
14036
|
+
var CreateConversationRequestSchema = exports_external.object({
|
|
14037
|
+
agent_id: exports_external.string().min(1, "agent_id is required")
|
|
14038
|
+
});
|
|
14039
|
+
var CreateMessageRequestSchema = exports_external.object({
|
|
14040
|
+
content: exports_external.string().min(1, "content is required")
|
|
14041
|
+
});
|
|
14042
|
+
var EmailAttachmentSchema = exports_external.object({
|
|
14043
|
+
key: exports_external.string().min(1),
|
|
14044
|
+
filename: exports_external.string().min(1),
|
|
14045
|
+
size: exports_external.number().int().nonnegative().optional(),
|
|
14046
|
+
contentType: exports_external.string().min(1)
|
|
14047
|
+
});
|
|
14048
|
+
var SendEmailRequestSchema = exports_external.object({
|
|
14049
|
+
agentId: exports_external.string().min(1, "agentId is required"),
|
|
14050
|
+
to: exports_external.string().min(1, "to is required"),
|
|
14051
|
+
subject: exports_external.string().min(1, "subject is required"),
|
|
14052
|
+
htmlBody: exports_external.string().default(""),
|
|
14053
|
+
inReplyTo: exports_external.string().optional(),
|
|
14054
|
+
references: exports_external.string().optional(),
|
|
14055
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
14056
|
+
});
|
|
14057
|
+
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
14058
|
+
status: exports_external.enum(["unread", "read", "archived"])
|
|
14059
|
+
});
|
|
14060
|
+
var EmailNotifyRequestSchema = exports_external.object({
|
|
14061
|
+
agentId: exports_external.string().min(1),
|
|
14062
|
+
workspaceId: exports_external.string().min(1),
|
|
14063
|
+
r2Key: exports_external.string().min(1),
|
|
14064
|
+
from: exports_external.string().min(1),
|
|
14065
|
+
to: exports_external.string().optional(),
|
|
14066
|
+
subject: exports_external.string().min(1),
|
|
14067
|
+
isWhitelisted: exports_external.boolean(),
|
|
14068
|
+
forwarded: exports_external.boolean().optional().default(false),
|
|
14069
|
+
messageId: exports_external.string().optional().default(""),
|
|
14070
|
+
inReplyTo: exports_external.string().optional().default(""),
|
|
14071
|
+
references: exports_external.string().optional().default("")
|
|
14072
|
+
});
|
|
14073
|
+
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
14074
|
+
name: exports_external.string().min(1, "name is required"),
|
|
14075
|
+
slug: exports_external.string().min(1, "slug is required")
|
|
14076
|
+
});
|
|
14018
14077
|
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260418.1_@opentelemetry+api@1.9.1_bun-types@1.3.12_kysely@0.28.16/node_modules/drizzle-orm/entity.js
|
|
14019
14078
|
var entityKind = Symbol.for("drizzle:entityKind");
|
|
14020
14079
|
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
@@ -15521,6 +15580,7 @@ var message = sqliteTable("message", {
|
|
|
15521
15580
|
role: text("role").notNull(),
|
|
15522
15581
|
content: text("content").notNull().default(""),
|
|
15523
15582
|
taskId: text("task_id"),
|
|
15583
|
+
attachmentIds: text("attachment_ids"),
|
|
15524
15584
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15525
15585
|
});
|
|
15526
15586
|
var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
@@ -15605,6 +15665,24 @@ var calendarEvent = sqliteTable("calendar_event", {
|
|
|
15605
15665
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15606
15666
|
}).onDelete("cascade")
|
|
15607
15667
|
]);
|
|
15668
|
+
var artifact = sqliteTable("artifact", {
|
|
15669
|
+
id: text("id").primaryKey().$defaultFn(() => "art_" + nanoid3()),
|
|
15670
|
+
conversationId: text("conversation_id").notNull().references(() => conversation.id, { onDelete: "cascade" }),
|
|
15671
|
+
agentId: text("agent_id").notNull(),
|
|
15672
|
+
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
15673
|
+
filename: text("filename").notNull(),
|
|
15674
|
+
contentType: text("content_type").notNull().default("application/octet-stream"),
|
|
15675
|
+
size: integer2("size").notNull(),
|
|
15676
|
+
r2Key: text("r2_key").notNull(),
|
|
15677
|
+
source: text("source").notNull().default("agent"),
|
|
15678
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15679
|
+
}, (t) => [
|
|
15680
|
+
index("idx_artifact_conversation").on(t.conversationId),
|
|
15681
|
+
foreignKey({
|
|
15682
|
+
columns: [t.agentId, t.workspaceId],
|
|
15683
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15684
|
+
}).onDelete("cascade")
|
|
15685
|
+
]);
|
|
15608
15686
|
var machineToken = sqliteTable("machine_token", {
|
|
15609
15687
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15610
15688
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -15701,6 +15779,16 @@ class DaemonClient {
|
|
|
15701
15779
|
error: error48
|
|
15702
15780
|
});
|
|
15703
15781
|
}
|
|
15782
|
+
async getArtifactMeta(token, artifactId, workspaceId) {
|
|
15783
|
+
return this.request("GET", `/api/artifacts/${artifactId}?workspace_id=${encodeURIComponent(workspaceId)}`, token);
|
|
15784
|
+
}
|
|
15785
|
+
async downloadArtifact(token, artifactId, workspaceId) {
|
|
15786
|
+
const res = await fetch(`${this.baseURL}/api/artifacts/${artifactId}/content?workspace_id=${encodeURIComponent(workspaceId)}`, { headers: { Authorization: `Bearer ${token}` } });
|
|
15787
|
+
if (!res.ok) {
|
|
15788
|
+
throw new Error(`artifact download failed: HTTP ${res.status}`);
|
|
15789
|
+
}
|
|
15790
|
+
return res.arrayBuffer();
|
|
15791
|
+
}
|
|
15704
15792
|
reportMessages(token, taskId, messages) {
|
|
15705
15793
|
return this.request("POST", `/api/daemon/tasks/${taskId}/messages`, token, { messages });
|
|
15706
15794
|
}
|
|
@@ -15871,6 +15959,7 @@ function fromApiTask(api2) {
|
|
|
15871
15959
|
priority: api2.priority,
|
|
15872
15960
|
type: api2.type,
|
|
15873
15961
|
contextKey: api2.context_key ?? null,
|
|
15962
|
+
context: api2.context ?? undefined,
|
|
15874
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,
|
|
15875
15964
|
repos: undefined,
|
|
15876
15965
|
createdAt: api2.created_at
|
|
@@ -17034,8 +17123,83 @@ ${result.output}`);
|
|
|
17034
17123
|
return cmd;
|
|
17035
17124
|
}
|
|
17036
17125
|
|
|
17126
|
+
// commands/sync.ts
|
|
17127
|
+
import { Command as Command9 } from "commander";
|
|
17128
|
+
import { readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
17129
|
+
import { basename as basename2 } from "path";
|
|
17130
|
+
var MIME_BY_EXT2 = {
|
|
17131
|
+
".pdf": "application/pdf",
|
|
17132
|
+
".png": "image/png",
|
|
17133
|
+
".jpg": "image/jpeg",
|
|
17134
|
+
".jpeg": "image/jpeg",
|
|
17135
|
+
".gif": "image/gif",
|
|
17136
|
+
".txt": "text/plain",
|
|
17137
|
+
".html": "text/html",
|
|
17138
|
+
".json": "application/json",
|
|
17139
|
+
".csv": "text/csv",
|
|
17140
|
+
".md": "text/markdown",
|
|
17141
|
+
".ts": "text/typescript",
|
|
17142
|
+
".js": "text/javascript",
|
|
17143
|
+
".yaml": "text/yaml",
|
|
17144
|
+
".yml": "text/yaml",
|
|
17145
|
+
".svg": "image/svg+xml",
|
|
17146
|
+
".xml": "application/xml",
|
|
17147
|
+
".zip": "application/zip"
|
|
17148
|
+
};
|
|
17149
|
+
function guessContentType2(filename) {
|
|
17150
|
+
const idx = filename.lastIndexOf(".");
|
|
17151
|
+
if (idx < 0)
|
|
17152
|
+
return "application/octet-stream";
|
|
17153
|
+
const ext = filename.slice(idx).toLowerCase();
|
|
17154
|
+
return MIME_BY_EXT2[ext] ?? "application/octet-stream";
|
|
17155
|
+
}
|
|
17156
|
+
function resolveClientOpts3(command, agentId) {
|
|
17157
|
+
const parentOpts = command.parent?.parent?.opts() || {};
|
|
17158
|
+
const profile = parentOpts.profile;
|
|
17159
|
+
const cfg = loadCLIConfigForProfile(profile);
|
|
17160
|
+
const serverUrl = parentOpts.server || cfg.server_url;
|
|
17161
|
+
const workspaces = cfg.watched_workspaces || [];
|
|
17162
|
+
const ws = workspaces.find((w) => w.agent_ids?.includes(agentId));
|
|
17163
|
+
if (!ws || !ws.token) {
|
|
17164
|
+
console.error(`Error: no registered workspace contains agent ${agentId}. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
17165
|
+
process.exit(1);
|
|
17166
|
+
}
|
|
17167
|
+
return { serverUrl, token: ws.token, workspaceId: ws.id };
|
|
17168
|
+
}
|
|
17169
|
+
function syncCommand() {
|
|
17170
|
+
const cmd = new Command9("sync").description("File sync utilities");
|
|
17171
|
+
cmd.command("upload-artifact").description("Upload a file artifact to a conversation").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--conversation_id <id>", "Conversation ID").requiredOption("--file <path>", "Path to file to upload").action(async (opts, command) => {
|
|
17172
|
+
const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
|
|
17173
|
+
const client = new APIClient(serverUrl, token, workspaceId);
|
|
17174
|
+
let bytes;
|
|
17175
|
+
let size;
|
|
17176
|
+
try {
|
|
17177
|
+
const stat = statSync3(opts.file);
|
|
17178
|
+
size = stat.size;
|
|
17179
|
+
bytes = readFileSync5(opts.file);
|
|
17180
|
+
} catch (err) {
|
|
17181
|
+
console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
|
|
17182
|
+
process.exit(1);
|
|
17183
|
+
}
|
|
17184
|
+
const filename = basename2(opts.file);
|
|
17185
|
+
const contentType = guessContentType2(filename);
|
|
17186
|
+
const form = new FormData;
|
|
17187
|
+
form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
|
|
17188
|
+
form.append("agent_id", opts.agent_id);
|
|
17189
|
+
form.append("conversation_id", opts.conversation_id);
|
|
17190
|
+
try {
|
|
17191
|
+
const result = await client.postMultipart("/api/artifacts/upload", form);
|
|
17192
|
+
printJSON(result);
|
|
17193
|
+
} catch (err) {
|
|
17194
|
+
console.error(`Error uploading artifact: ${err.message}`);
|
|
17195
|
+
process.exit(1);
|
|
17196
|
+
}
|
|
17197
|
+
});
|
|
17198
|
+
return cmd;
|
|
17199
|
+
}
|
|
17200
|
+
|
|
17037
17201
|
// src/index.ts
|
|
17038
|
-
var program = new
|
|
17202
|
+
var program = new Command10;
|
|
17039
17203
|
program.name("alook").description("Alook CLI").option("--server <url>", "Server URL").option("--profile <name>", "Profile name");
|
|
17040
17204
|
program.addCommand(registerCommand());
|
|
17041
17205
|
program.addCommand(statusCommand());
|
|
@@ -17045,4 +17209,5 @@ program.addCommand(calendarCommand());
|
|
|
17045
17209
|
program.addCommand(configCommand());
|
|
17046
17210
|
program.addCommand(versionCommand());
|
|
17047
17211
|
program.addCommand(updateCommand());
|
|
17212
|
+
program.addCommand(syncCommand());
|
|
17048
17213
|
program.parse();
|
package/dist/session-runner.js
CHANGED
|
@@ -15,6 +15,8 @@ var __export = (target, all) => {
|
|
|
15
15
|
|
|
16
16
|
// daemon/session-runner.ts
|
|
17
17
|
import { createWriteStream } from "fs";
|
|
18
|
+
import { mkdir, writeFile, rm } from "fs/promises";
|
|
19
|
+
import path from "path";
|
|
18
20
|
|
|
19
21
|
// ../shared/src/constants.ts
|
|
20
22
|
var TASK_TYPES = {
|
|
@@ -13612,7 +13614,8 @@ var TaskApiBaseSchema = exports_external.object({
|
|
|
13612
13614
|
error: exports_external.string().nullable(),
|
|
13613
13615
|
created_at: exports_external.string(),
|
|
13614
13616
|
type: exports_external.string(),
|
|
13615
|
-
context_key: exports_external.string().nullable().optional()
|
|
13617
|
+
context_key: exports_external.string().nullable().optional(),
|
|
13618
|
+
context: exports_external.unknown().nullable().optional()
|
|
13616
13619
|
});
|
|
13617
13620
|
var TaskApiSchema = TaskApiBaseSchema.extend({
|
|
13618
13621
|
agent: TaskAgentDataApiSchema.nullable().optional()
|
|
@@ -13731,6 +13734,64 @@ var CalendarEventApiSchema = exports_external.object({
|
|
|
13731
13734
|
var AddWhitelistRequestSchema = exports_external.object({
|
|
13732
13735
|
email: exports_external.string().email()
|
|
13733
13736
|
});
|
|
13737
|
+
var RuntimeConfigSchema = exports_external.object({ model: exports_external.string().max(100).optional() }).passthrough().optional();
|
|
13738
|
+
var CreateAgentRequestSchema = exports_external.object({
|
|
13739
|
+
name: exports_external.string().min(1, "name is required"),
|
|
13740
|
+
description: exports_external.string().optional().default(""),
|
|
13741
|
+
instructions: exports_external.string().optional().default(""),
|
|
13742
|
+
runtime_id: exports_external.string().min(1, "runtime_id is required"),
|
|
13743
|
+
runtime_config: RuntimeConfigSchema,
|
|
13744
|
+
max_concurrent_tasks: exports_external.number().int().optional(),
|
|
13745
|
+
email_handle: exports_external.string().optional()
|
|
13746
|
+
});
|
|
13747
|
+
var UpdateAgentRequestSchema = exports_external.object({
|
|
13748
|
+
name: exports_external.string().min(1).optional(),
|
|
13749
|
+
description: exports_external.string().optional(),
|
|
13750
|
+
instructions: exports_external.string().optional(),
|
|
13751
|
+
runtime_id: exports_external.string().min(1).optional(),
|
|
13752
|
+
runtime_config: RuntimeConfigSchema
|
|
13753
|
+
}).refine((v) => v.name !== undefined || v.description !== undefined || v.instructions !== undefined || v.runtime_id !== undefined || v.runtime_config !== undefined, { message: "at least one field is required" });
|
|
13754
|
+
var CreateConversationRequestSchema = exports_external.object({
|
|
13755
|
+
agent_id: exports_external.string().min(1, "agent_id is required")
|
|
13756
|
+
});
|
|
13757
|
+
var CreateMessageRequestSchema = exports_external.object({
|
|
13758
|
+
content: exports_external.string().min(1, "content is required")
|
|
13759
|
+
});
|
|
13760
|
+
var EmailAttachmentSchema = exports_external.object({
|
|
13761
|
+
key: exports_external.string().min(1),
|
|
13762
|
+
filename: exports_external.string().min(1),
|
|
13763
|
+
size: exports_external.number().int().nonnegative().optional(),
|
|
13764
|
+
contentType: exports_external.string().min(1)
|
|
13765
|
+
});
|
|
13766
|
+
var SendEmailRequestSchema = exports_external.object({
|
|
13767
|
+
agentId: exports_external.string().min(1, "agentId is required"),
|
|
13768
|
+
to: exports_external.string().min(1, "to is required"),
|
|
13769
|
+
subject: exports_external.string().min(1, "subject is required"),
|
|
13770
|
+
htmlBody: exports_external.string().default(""),
|
|
13771
|
+
inReplyTo: exports_external.string().optional(),
|
|
13772
|
+
references: exports_external.string().optional(),
|
|
13773
|
+
attachments: exports_external.array(EmailAttachmentSchema).optional()
|
|
13774
|
+
});
|
|
13775
|
+
var UpdateEmailStatusRequestSchema = exports_external.object({
|
|
13776
|
+
status: exports_external.enum(["unread", "read", "archived"])
|
|
13777
|
+
});
|
|
13778
|
+
var EmailNotifyRequestSchema = exports_external.object({
|
|
13779
|
+
agentId: exports_external.string().min(1),
|
|
13780
|
+
workspaceId: exports_external.string().min(1),
|
|
13781
|
+
r2Key: exports_external.string().min(1),
|
|
13782
|
+
from: exports_external.string().min(1),
|
|
13783
|
+
to: exports_external.string().optional(),
|
|
13784
|
+
subject: exports_external.string().min(1),
|
|
13785
|
+
isWhitelisted: exports_external.boolean(),
|
|
13786
|
+
forwarded: exports_external.boolean().optional().default(false),
|
|
13787
|
+
messageId: exports_external.string().optional().default(""),
|
|
13788
|
+
inReplyTo: exports_external.string().optional().default(""),
|
|
13789
|
+
references: exports_external.string().optional().default("")
|
|
13790
|
+
});
|
|
13791
|
+
var CreateWorkspaceRequestSchema = exports_external.object({
|
|
13792
|
+
name: exports_external.string().min(1, "name is required"),
|
|
13793
|
+
slug: exports_external.string().min(1, "slug is required")
|
|
13794
|
+
});
|
|
13734
13795
|
// ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudflare+workers-types@4.20260418.1_@opentelemetry+api@1.9.1_bun-types@1.3.12_kysely@0.28.16/node_modules/drizzle-orm/entity.js
|
|
13735
13796
|
var entityKind = Symbol.for("drizzle:entityKind");
|
|
13736
13797
|
var hasOwnEntityKind = Symbol.for("drizzle:hasOwnEntityKind");
|
|
@@ -15237,6 +15298,7 @@ var message = sqliteTable("message", {
|
|
|
15237
15298
|
role: text("role").notNull(),
|
|
15238
15299
|
content: text("content").notNull().default(""),
|
|
15239
15300
|
taskId: text("task_id"),
|
|
15301
|
+
attachmentIds: text("attachment_ids"),
|
|
15240
15302
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15241
15303
|
});
|
|
15242
15304
|
var agentTaskQueue = sqliteTable("agent_task_queue", {
|
|
@@ -15321,6 +15383,24 @@ var calendarEvent = sqliteTable("calendar_event", {
|
|
|
15321
15383
|
foreignColumns: [agent.id, agent.workspaceId]
|
|
15322
15384
|
}).onDelete("cascade")
|
|
15323
15385
|
]);
|
|
15386
|
+
var artifact = sqliteTable("artifact", {
|
|
15387
|
+
id: text("id").primaryKey().$defaultFn(() => "art_" + nanoid3()),
|
|
15388
|
+
conversationId: text("conversation_id").notNull().references(() => conversation.id, { onDelete: "cascade" }),
|
|
15389
|
+
agentId: text("agent_id").notNull(),
|
|
15390
|
+
workspaceId: text("workspace_id").notNull().references(() => workspace.id, { onDelete: "cascade" }),
|
|
15391
|
+
filename: text("filename").notNull(),
|
|
15392
|
+
contentType: text("content_type").notNull().default("application/octet-stream"),
|
|
15393
|
+
size: integer2("size").notNull(),
|
|
15394
|
+
r2Key: text("r2_key").notNull(),
|
|
15395
|
+
source: text("source").notNull().default("agent"),
|
|
15396
|
+
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
15397
|
+
}, (t) => [
|
|
15398
|
+
index("idx_artifact_conversation").on(t.conversationId),
|
|
15399
|
+
foreignKey({
|
|
15400
|
+
columns: [t.agentId, t.workspaceId],
|
|
15401
|
+
foreignColumns: [agent.id, agent.workspaceId]
|
|
15402
|
+
}).onDelete("cascade")
|
|
15403
|
+
]);
|
|
15324
15404
|
var machineToken = sqliteTable("machine_token", {
|
|
15325
15405
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
15326
15406
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -15406,6 +15486,16 @@ class DaemonClient {
|
|
|
15406
15486
|
error: error48
|
|
15407
15487
|
});
|
|
15408
15488
|
}
|
|
15489
|
+
async getArtifactMeta(token, artifactId, workspaceId) {
|
|
15490
|
+
return this.request("GET", `/api/artifacts/${artifactId}?workspace_id=${encodeURIComponent(workspaceId)}`, token);
|
|
15491
|
+
}
|
|
15492
|
+
async downloadArtifact(token, artifactId, workspaceId) {
|
|
15493
|
+
const res = await fetch(`${this.baseURL}/api/artifacts/${artifactId}/content?workspace_id=${encodeURIComponent(workspaceId)}`, { headers: { Authorization: `Bearer ${token}` } });
|
|
15494
|
+
if (!res.ok) {
|
|
15495
|
+
throw new Error(`artifact download failed: HTTP ${res.status}`);
|
|
15496
|
+
}
|
|
15497
|
+
return res.arrayBuffer();
|
|
15498
|
+
}
|
|
15409
15499
|
reportMessages(token, taskId, messages) {
|
|
15410
15500
|
return this.request("POST", `/api/daemon/tasks/${taskId}/messages`, token, { messages });
|
|
15411
15501
|
}
|
|
@@ -16442,6 +16532,19 @@ To reply to an email, add '--in-reply-to <EMAIL_ID>' to the send command. This s
|
|
|
16442
16532
|
`;
|
|
16443
16533
|
}
|
|
16444
16534
|
content += `
|
|
16535
|
+
### Artifacts
|
|
16536
|
+
Upload files for your owner to review in the app.
|
|
16537
|
+
- Your current conversation id is available via env var: $ALOOK_CONVERSATION_ID
|
|
16538
|
+
- Run 'npx @alook/cli sync upload-artifact --agent_id ${task.agentId} --conversation_id $ALOOK_CONVERSATION_ID --file <PATH>'
|
|
16539
|
+
- Use this after generating plans, reports, or any file the owner should review.
|
|
16540
|
+
---
|
|
16541
|
+
|
|
16542
|
+
### Attachments
|
|
16543
|
+
When your task includes attachments, their local paths are listed in the prompt JSON under "attachments".
|
|
16544
|
+
Use your Read tool to open them. Images and PDFs are read visually.
|
|
16545
|
+
---
|
|
16546
|
+
`;
|
|
16547
|
+
content += `
|
|
16445
16548
|
### Calendar
|
|
16446
16549
|
You have your own calendar to setup daily routines and reminders.
|
|
16447
16550
|
Schedule future tasks for yourself. At the scheduled time, a new task is dispatched to you with the event as the prompt (task type 'calendar_event').
|
|
@@ -16848,17 +16951,65 @@ function prepare(config2, task) {
|
|
|
16848
16951
|
}
|
|
16849
16952
|
|
|
16850
16953
|
// daemon/prompt.ts
|
|
16851
|
-
function buildPrompt(task) {
|
|
16852
|
-
|
|
16954
|
+
function buildPrompt(task, attachments) {
|
|
16955
|
+
const obj = { type: task.type, instruction: task.prompt };
|
|
16956
|
+
if (attachments && attachments.length > 0) {
|
|
16957
|
+
obj.attachments = attachments.map((a) => ({
|
|
16958
|
+
path: a.path,
|
|
16959
|
+
content_type: a.content_type,
|
|
16960
|
+
filename: a.filename
|
|
16961
|
+
}));
|
|
16962
|
+
}
|
|
16963
|
+
return JSON.stringify(obj);
|
|
16853
16964
|
}
|
|
16854
16965
|
|
|
16855
16966
|
// daemon/session-runner.ts
|
|
16967
|
+
var ATTACHMENTS_BASE = "/tmp/alook-attachments";
|
|
16968
|
+
function sanitizeFilename(name) {
|
|
16969
|
+
return path.basename(name).replace(/[/\\]/g, "_").replace(/\.\./g, "_").slice(0, 255) || "file";
|
|
16970
|
+
}
|
|
16971
|
+
async function cleanupAttachments(taskId) {
|
|
16972
|
+
try {
|
|
16973
|
+
await rm(path.join(ATTACHMENTS_BASE, taskId), { recursive: true, force: true });
|
|
16974
|
+
} catch {}
|
|
16975
|
+
}
|
|
16976
|
+
async function downloadAttachments(client, token, workspaceId, taskId, attachmentIds) {
|
|
16977
|
+
const dir = path.join(ATTACHMENTS_BASE, taskId);
|
|
16978
|
+
await mkdir(dir, { recursive: true });
|
|
16979
|
+
const attachments = [];
|
|
16980
|
+
for (const artId of attachmentIds) {
|
|
16981
|
+
const meta3 = await client.getArtifactMeta(token, artId, workspaceId);
|
|
16982
|
+
const content = await client.downloadArtifact(token, artId, workspaceId);
|
|
16983
|
+
const filename = sanitizeFilename(meta3.filename);
|
|
16984
|
+
const localPath = path.join(dir, `${artId}_${filename}`);
|
|
16985
|
+
await writeFile(localPath, Buffer.from(content));
|
|
16986
|
+
attachments.push({
|
|
16987
|
+
path: localPath,
|
|
16988
|
+
content_type: meta3.content_type,
|
|
16989
|
+
filename: meta3.filename
|
|
16990
|
+
});
|
|
16991
|
+
}
|
|
16992
|
+
return attachments;
|
|
16993
|
+
}
|
|
16856
16994
|
async function runSession(input) {
|
|
16857
16995
|
const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout } = input;
|
|
16858
16996
|
const client = new DaemonClient(serverURL);
|
|
16859
16997
|
const backend = createBackend(provider, cliPath);
|
|
16860
|
-
const prompt = buildPrompt(task);
|
|
16861
16998
|
const { workDir, logFile, timelineDir, env } = prepare({ workspacesRoot }, task);
|
|
16999
|
+
const attachmentIds = task.context?.attachment_ids ?? [];
|
|
17000
|
+
let attachments;
|
|
17001
|
+
if (attachmentIds.length > 0) {
|
|
17002
|
+
try {
|
|
17003
|
+
attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
|
|
17004
|
+
} catch (e) {
|
|
17005
|
+
await cleanupAttachments(task.id);
|
|
17006
|
+
const errMsg = `failed to download attachments: ${e}`;
|
|
17007
|
+
log.error(`Task ${task.id} ${errMsg}`);
|
|
17008
|
+
await client.failTask(token, task.id, errMsg);
|
|
17009
|
+
return;
|
|
17010
|
+
}
|
|
17011
|
+
}
|
|
17012
|
+
const prompt = buildPrompt(task, attachments);
|
|
16862
17013
|
const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
|
|
16863
17014
|
if (resumeSessionId) {
|
|
16864
17015
|
log.info(`Task ${task.id} resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
|
|
@@ -16917,6 +17068,7 @@ async function runSession(input) {
|
|
|
16917
17068
|
await flushMessages();
|
|
16918
17069
|
} catch {}
|
|
16919
17070
|
logStream?.end();
|
|
17071
|
+
await cleanupAttachments(task.id);
|
|
16920
17072
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
16921
17073
|
entry.pid = null;
|
|
16922
17074
|
entry.status = "killed";
|
|
@@ -16979,6 +17131,7 @@ async function runSession(input) {
|
|
|
16979
17131
|
process.removeListener("SIGINT", onKill);
|
|
16980
17132
|
if (killed)
|
|
16981
17133
|
return;
|
|
17134
|
+
await cleanupAttachments(task.id);
|
|
16982
17135
|
if (result.status === "completed") {
|
|
16983
17136
|
updateEntry(timelineDir, task.id, (entry) => {
|
|
16984
17137
|
entry.session_id = result.sessionId || null;
|
|
@@ -17024,6 +17177,7 @@ async function main() {
|
|
|
17024
17177
|
await runSession(input);
|
|
17025
17178
|
} catch (e) {
|
|
17026
17179
|
log.error(`session-runner: unhandled error for task ${input.task.id}`, e);
|
|
17180
|
+
await cleanupAttachments(input.task.id);
|
|
17027
17181
|
try {
|
|
17028
17182
|
await client.failTask(input.token, input.task.id, `session-runner crash: ${e}`);
|
|
17029
17183
|
} catch {}
|