@dana4/sdk 0.1.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/agent.d.ts +42 -4
- package/dist/agent.js +86 -21
- package/dist/ai.d.ts +7 -6
- package/dist/ai.js +175 -38
- package/dist/cli.js +11 -2
- package/dist/client.d.ts +57 -0
- package/dist/client.js +43 -10
- package/dist/cloudflare.js +10 -3
- package/dist/enroll.js +13 -4
- package/dist/run.js +7 -2
- package/dist/schema.d.ts +3748 -3503
- package/package.json +14 -3
package/dist/ai.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* and chat threads turned into model messages. */
|
|
3
3
|
import { jsonSchema, tool } from "ai";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { taggedUsernames } from "./agent.js";
|
|
5
6
|
const MAX_LINES_PER_READ = 500;
|
|
6
7
|
const MAX_LINES_PER_WRITE = 400;
|
|
7
8
|
/** `ls -R`-style listing: grouped per directory, folders first, titles aligned. */
|
|
@@ -18,10 +19,14 @@ export function formatDocumentList(documents) {
|
|
|
18
19
|
.map((dir) => {
|
|
19
20
|
const entries = groups
|
|
20
21
|
.get(dir)
|
|
21
|
-
|
|
22
|
+
?.sort((a, b) => Number(isFolder(b)) - Number(isFolder(a)) ||
|
|
23
|
+
leaf(a).localeCompare(leaf(b))) ?? [];
|
|
22
24
|
const names = entries.map((d) => leaf(d) + (isFolder(d) ? "/" : ""));
|
|
23
25
|
const width = Math.max(...names.map((n) => n.length));
|
|
24
|
-
return [
|
|
26
|
+
return [
|
|
27
|
+
`${dir}:`,
|
|
28
|
+
...entries.map((d, i) => ` ${names[i]?.padEnd(width)} ${d.title}`),
|
|
29
|
+
].join("\n");
|
|
25
30
|
})
|
|
26
31
|
.join("\n\n");
|
|
27
32
|
}
|
|
@@ -39,10 +44,13 @@ export function grep(content, pattern, context = 3) {
|
|
|
39
44
|
const shown = new Set(hits.flatMap((i) => Array.from({ length: 2 * context + 1 }, (_, k) => i - context + k)));
|
|
40
45
|
const out = [];
|
|
41
46
|
let prev = -2;
|
|
42
|
-
for (const i of [...shown]
|
|
47
|
+
for (const i of [...shown]
|
|
48
|
+
.filter((i) => i >= 0 && i < lines.length)
|
|
49
|
+
.sort((a, b) => a - b)) {
|
|
43
50
|
if (i !== prev + 1 && out.length)
|
|
44
51
|
out.push("---");
|
|
45
|
-
|
|
52
|
+
const line = lines[i] ?? "";
|
|
53
|
+
out.push(`${regex.test(line) ? ">" : " "} ${i + 1}: ${line}`);
|
|
46
54
|
prev = i;
|
|
47
55
|
}
|
|
48
56
|
return { matches: hits.length, lines: lines.length, text: out.join("\n") };
|
|
@@ -52,7 +60,7 @@ export function insertAt(document, line, content) {
|
|
|
52
60
|
const lines = document.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
53
61
|
const at = Math.max(0, Math.min(line - 1, lines.length));
|
|
54
62
|
// Appending after an unterminated last line: end it first, or the two join.
|
|
55
|
-
if (at === lines.length && at > 0 && !lines[at - 1]
|
|
63
|
+
if (at === lines.length && at > 0 && !lines[at - 1]?.endsWith("\n"))
|
|
56
64
|
lines[at - 1] += "\n";
|
|
57
65
|
lines.splice(at, 0, content.endsWith("\n") ? content : `${content}\n`);
|
|
58
66
|
return lines.join("");
|
|
@@ -67,11 +75,21 @@ export function capabilityToolSchema(schema) {
|
|
|
67
75
|
if (["workspace_id", "task_id"].includes(name))
|
|
68
76
|
return false;
|
|
69
77
|
const t = p?.type;
|
|
70
|
-
return typeof t === "string"
|
|
78
|
+
return typeof t === "string"
|
|
79
|
+
? PRIMITIVE.has(t)
|
|
80
|
+
: Array.isArray(t) &&
|
|
81
|
+
t.every((x) => typeof x === "string" && PRIMITIVE.has(x));
|
|
71
82
|
});
|
|
72
83
|
const kept = new Set(keep.map(([n]) => n));
|
|
73
|
-
const required = Array.isArray(schema?.required)
|
|
74
|
-
|
|
84
|
+
const required = Array.isArray(schema?.required)
|
|
85
|
+
? schema.required.filter((r) => typeof r === "string" && kept.has(r))
|
|
86
|
+
: [];
|
|
87
|
+
return {
|
|
88
|
+
type: "object",
|
|
89
|
+
additionalProperties: false,
|
|
90
|
+
properties: Object.fromEntries(keep),
|
|
91
|
+
required,
|
|
92
|
+
};
|
|
75
93
|
}
|
|
76
94
|
/** Tools for reading and writing the workspace's documents, messaging, and the
|
|
77
95
|
* thread's plan — plus, unless `delegation: false`, one `<agent>__<capability>`
|
|
@@ -80,9 +98,12 @@ export function capabilityToolSchema(schema) {
|
|
|
80
98
|
export async function dana4Tools(ctx, opts = {}) {
|
|
81
99
|
const tools = {
|
|
82
100
|
list_documents: tool({
|
|
83
|
-
description: "List documents in a folder with their paths and titles. Optionally recurse into subfolders.",
|
|
101
|
+
description: "List documents in a folder with their paths and titles. Optionally recurse into subfolders. To find documents about a topic, use search_documents instead: listing returns every document and costs far more tokens.",
|
|
84
102
|
inputSchema: z.object({
|
|
85
|
-
path: z
|
|
103
|
+
path: z
|
|
104
|
+
.string()
|
|
105
|
+
.default("/")
|
|
106
|
+
.describe("Folder to list, as a path (e.g. '/foo/bar'). Defaults to the root."),
|
|
86
107
|
recursive: z
|
|
87
108
|
.boolean()
|
|
88
109
|
.default(false)
|
|
@@ -94,19 +115,33 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
94
115
|
description: "Search for a text pattern within a document. Returns matching lines with line numbers and surrounding context. Use this BEFORE read_document to find relevant sections without reading the entire file.",
|
|
95
116
|
inputSchema: z.object({
|
|
96
117
|
path: z.string().describe("Path of the document to search in."),
|
|
97
|
-
pattern: z
|
|
98
|
-
|
|
118
|
+
pattern: z
|
|
119
|
+
.string()
|
|
120
|
+
.describe("Text or regex pattern to search for. Case-insensitive."),
|
|
121
|
+
context_lines: z
|
|
122
|
+
.number()
|
|
123
|
+
.int()
|
|
124
|
+
.default(3)
|
|
125
|
+
.describe("Number of lines to show before and after each match."),
|
|
99
126
|
}),
|
|
100
127
|
execute: async ({ path, pattern, context_lines }) => {
|
|
101
128
|
const r = grep((await ctx.docs.get(path)).content, pattern, context_lines);
|
|
102
|
-
return r.matches
|
|
129
|
+
return r.matches
|
|
130
|
+
? `Found ${r.matches} match(es) in ${path} (${r.lines} lines total):\n${r.text}`
|
|
131
|
+
: `No matches for '${pattern}' in ${path}`;
|
|
103
132
|
},
|
|
104
133
|
}),
|
|
105
134
|
search_documents: tool({
|
|
106
135
|
description: "Search across ALL documents in the workspace by meaning or keyword, returning the most relevant documents with a snippet and relevance score. Use this when you don't know which document holds the content you need. Use grep_document instead to search within a single known document.",
|
|
107
136
|
inputSchema: z.object({
|
|
108
|
-
query: z
|
|
109
|
-
|
|
137
|
+
query: z
|
|
138
|
+
.string()
|
|
139
|
+
.describe("Natural-language or keyword query to search across all documents in the workspace."),
|
|
140
|
+
limit: z
|
|
141
|
+
.number()
|
|
142
|
+
.int()
|
|
143
|
+
.optional()
|
|
144
|
+
.describe("Max number of results to return. Defaults to the server default."),
|
|
110
145
|
}),
|
|
111
146
|
execute: async ({ query, limit }) => {
|
|
112
147
|
const results = await ctx.docs.search(query, limit);
|
|
@@ -114,7 +149,10 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
114
149
|
return `No documents matched '${query}'.`;
|
|
115
150
|
return [
|
|
116
151
|
`Found ${results.length} result(s) for '${query}':\n`,
|
|
117
|
-
...results.flatMap((r) => [
|
|
152
|
+
...results.flatMap((r) => [
|
|
153
|
+
`- ${r.path} — ${r.title} (score: ${r.score.toFixed(3)})`,
|
|
154
|
+
...(r.snippet ? [` ${r.snippet}`] : []),
|
|
155
|
+
]),
|
|
118
156
|
].join("\n");
|
|
119
157
|
},
|
|
120
158
|
}),
|
|
@@ -122,7 +160,11 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
122
160
|
description: `Read a document's content with line numbers. Returns up to ${MAX_LINES_PER_READ} lines.\n\nUsage:\n- Use grep_document first to find relevant line numbers, then read targeted ranges.\n- Use offset and limit to read specific sections. Avoid reading entire large documents.\n- Lines are prefixed with line numbers: \`42: content here\`.\n- Call this tool in parallel when reading multiple documents.`,
|
|
123
161
|
inputSchema: z.object({
|
|
124
162
|
path: z.string().describe("The path to the document to read."),
|
|
125
|
-
offset: z
|
|
163
|
+
offset: z
|
|
164
|
+
.number()
|
|
165
|
+
.int()
|
|
166
|
+
.optional()
|
|
167
|
+
.describe("Line number to start reading from (1-indexed). Defaults to 1."),
|
|
126
168
|
limit: z
|
|
127
169
|
.number()
|
|
128
170
|
.int()
|
|
@@ -138,18 +180,24 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
138
180
|
.slice(start, end)
|
|
139
181
|
.map((l, i) => `${start + i + 1}: ${l}`)
|
|
140
182
|
.join("\n");
|
|
141
|
-
const more = end < lines.length
|
|
183
|
+
const more = end < lines.length
|
|
184
|
+
? `\n\n[Showing lines ${start + 1}-${end} of ${lines.length}. Use offset=${end + 1} to read more.]`
|
|
185
|
+
: "";
|
|
142
186
|
return `Title: ${doc.title}\nPath: ${path}\nTotal lines: ${lines.length}\nContent:\n\n${body}${more}\n`;
|
|
143
187
|
},
|
|
144
188
|
}),
|
|
145
189
|
get_step_result: tool({
|
|
146
190
|
description: "Fetch the result produced by an earlier step in the current journey, by its step id. Returns the result as JSON, or a note if the step has not produced a result yet.",
|
|
147
191
|
inputSchema: z.object({
|
|
148
|
-
step_id: z
|
|
192
|
+
step_id: z
|
|
193
|
+
.string()
|
|
194
|
+
.describe("The id of the step whose result to fetch (e.g. 'step_brand_questions')."),
|
|
149
195
|
}),
|
|
150
196
|
execute: async ({ step_id }) => {
|
|
151
197
|
const result = await ctx.stepResult(step_id);
|
|
152
|
-
return result == null
|
|
198
|
+
return result == null
|
|
199
|
+
? `No result available for step '${step_id}' yet (it may not have run or completed).`
|
|
200
|
+
: JSON.stringify(result, null, 2);
|
|
153
201
|
},
|
|
154
202
|
}),
|
|
155
203
|
create_document: tool({
|
|
@@ -173,7 +221,10 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
173
221
|
description: `Overwrite a document's entire content. Max ~${MAX_LINES_PER_WRITE} lines.\n\nONLY use for small documents. For anything larger, use create_document + append_document.\nFor targeted changes, prefer edit_document or insert_in_document instead.`,
|
|
174
222
|
inputSchema: z.object({
|
|
175
223
|
path: z.string().describe("Path to the document to overwrite."),
|
|
176
|
-
content: z
|
|
224
|
+
content: z
|
|
225
|
+
.string()
|
|
226
|
+
.default("")
|
|
227
|
+
.describe("Full replacement content. Must be under ~200 lines."),
|
|
177
228
|
}),
|
|
178
229
|
execute: async ({ path, content }) => {
|
|
179
230
|
if (!content)
|
|
@@ -189,7 +240,9 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
189
240
|
description: "Append content to the end of an existing document.\n\nUse this for building large documents incrementally:\n1. create_document with opening structure\n2. append_document for each section\nKeep each append under ~300 lines.",
|
|
190
241
|
inputSchema: z.object({
|
|
191
242
|
path: z.string().describe("Path of the document to append to."),
|
|
192
|
-
content: z
|
|
243
|
+
content: z
|
|
244
|
+
.string()
|
|
245
|
+
.describe("Content to append to the end of the document."),
|
|
193
246
|
}),
|
|
194
247
|
execute: async ({ path, content }) => {
|
|
195
248
|
await ctx.docs.append(path, content);
|
|
@@ -200,9 +253,16 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
200
253
|
description: "Find and replace exact text in a document.\n\nUsage:\n- You MUST read_document or grep_document first to see the exact text.\n- old_str must match exactly (whitespace, indentation, line breaks).\n- old_str must be unique in the document. Include surrounding lines if needed, or set replace_all to change every occurrence.\n- Do NOT include line number prefixes (e.g. `42: `) in old_str/new_str.",
|
|
201
254
|
inputSchema: z.object({
|
|
202
255
|
path: z.string().describe("Path to the document to modify."),
|
|
203
|
-
old_str: z
|
|
204
|
-
|
|
205
|
-
|
|
256
|
+
old_str: z
|
|
257
|
+
.string()
|
|
258
|
+
.describe("Exact text to find and replace. Must match uniquely. Include surrounding lines for context if needed."),
|
|
259
|
+
new_str: z
|
|
260
|
+
.string()
|
|
261
|
+
.describe("Replacement text. Must differ from old_str."),
|
|
262
|
+
replace_all: z
|
|
263
|
+
.boolean()
|
|
264
|
+
.default(false)
|
|
265
|
+
.describe("Replace every occurrence instead of requiring a unique match."),
|
|
206
266
|
}),
|
|
207
267
|
execute: async ({ path, old_str, new_str, replace_all }) => {
|
|
208
268
|
try {
|
|
@@ -222,15 +282,47 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
222
282
|
.number()
|
|
223
283
|
.int()
|
|
224
284
|
.describe("Line number to insert BEFORE (1-indexed). Use 0 to insert at the very beginning. Use a line number beyond the end to append."),
|
|
225
|
-
content: z
|
|
285
|
+
content: z
|
|
286
|
+
.string()
|
|
287
|
+
.describe("Content to insert at the specified line."),
|
|
226
288
|
}),
|
|
227
289
|
execute: async ({ path, line, content }) => {
|
|
228
290
|
const doc = await ctx.docs.get(path, "editing");
|
|
229
291
|
await ctx.docs.replace(path, insertAt(doc.content, line, content));
|
|
230
|
-
const n = (content.endsWith("\n") ? content : `${content}\n`).split("\n")
|
|
292
|
+
const n = (content.endsWith("\n") ? content : `${content}\n`).split("\n")
|
|
293
|
+
.length - 1;
|
|
231
294
|
return `Inserted ${n} line(s) at line ${line} in ${path}`;
|
|
232
295
|
},
|
|
233
296
|
}),
|
|
297
|
+
create_ticket: tool({
|
|
298
|
+
description: "Create a ticket on the workspace's board. Tickets are identified by their number (#42), unique within the workspace; blocked_by takes those numbers.",
|
|
299
|
+
inputSchema: z.object({
|
|
300
|
+
title: z.string().describe("The ticket's title."),
|
|
301
|
+
description: z
|
|
302
|
+
.string()
|
|
303
|
+
.optional()
|
|
304
|
+
.describe("What needs doing, in markdown."),
|
|
305
|
+
status: z
|
|
306
|
+
.enum([
|
|
307
|
+
"backlog",
|
|
308
|
+
"todo",
|
|
309
|
+
"in_progress",
|
|
310
|
+
"in_review",
|
|
311
|
+
"done",
|
|
312
|
+
"canceled",
|
|
313
|
+
])
|
|
314
|
+
.optional()
|
|
315
|
+
.describe("The board column. Defaults to backlog."),
|
|
316
|
+
blocked_by: z
|
|
317
|
+
.array(z.number().int())
|
|
318
|
+
.default([])
|
|
319
|
+
.describe("Numbers of the tickets that must finish first."),
|
|
320
|
+
}),
|
|
321
|
+
execute: async (ticket) => {
|
|
322
|
+
const t = await ctx.tickets.create(ticket);
|
|
323
|
+
return `Ticket #${t.number} created in workspace ${ctx.workspaceId}`;
|
|
324
|
+
},
|
|
325
|
+
}),
|
|
234
326
|
send_message: tool({
|
|
235
327
|
description: "Send a message to a channel. Uses the current channel if channel_id is omitted.",
|
|
236
328
|
inputSchema: z.object({
|
|
@@ -248,20 +340,42 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
248
340
|
plan: z
|
|
249
341
|
.string()
|
|
250
342
|
.describe("The full plan as a markdown checklist, e.g. `- [x] research\n- [ ] draft`. This REPLACES the existing plan, so include every item, not just the changed ones. Use this to author the initial plan; prefer complete_plan_item / add_plan_item for incremental edits."),
|
|
251
|
-
channel_id: z
|
|
343
|
+
channel_id: z
|
|
344
|
+
.string()
|
|
345
|
+
.optional()
|
|
346
|
+
.describe("The id of the channel. Defaults to the current channel."),
|
|
252
347
|
}),
|
|
253
348
|
execute: async ({ plan, channel_id }) => {
|
|
254
349
|
const ch = await ctx.plan.set(plan, channel_id ?? ctx.channelId);
|
|
255
350
|
return planStatus(ch.id, ch.plan_completed);
|
|
256
351
|
},
|
|
257
352
|
}),
|
|
353
|
+
set_memory: tool({
|
|
354
|
+
description: "Overwrite this message thread's memory: markdown notes shared by its agents and people.\n\nUse it to log what happened, what worked, what failed and what to remember next run. The current memory is in your instructions; send the whole updated text, not just the new notes.",
|
|
355
|
+
inputSchema: z.object({
|
|
356
|
+
memory: z
|
|
357
|
+
.string()
|
|
358
|
+
.describe("The full memory as markdown. This REPLACES the existing memory, so start from the current one in your instructions and edit it: keep what is still useful, add what happened, what worked, what failed and what to remember next run, and drop what is stale."),
|
|
359
|
+
channel_id: z
|
|
360
|
+
.string()
|
|
361
|
+
.optional()
|
|
362
|
+
.describe("The id of the channel. Defaults to the current channel."),
|
|
363
|
+
}),
|
|
364
|
+
execute: async ({ memory, channel_id }) => {
|
|
365
|
+
const ch = await ctx.memory.set(memory, channel_id ?? ctx.channelId);
|
|
366
|
+
return `Memory updated for channel ${ch.id}.`;
|
|
367
|
+
},
|
|
368
|
+
}),
|
|
258
369
|
complete_plan_item: tool({
|
|
259
370
|
description: "Check off one item in this message thread's plan as you finish it.\n\nUsage:\n- The current plan (a markdown checklist) is in your instructions.\n- Pass the item's exact label text — just that one item, not the whole plan.\n- If the text matches no item or several, you'll get an error; retry with more of the item's wording.\n- The thread is complete once every item is checked.",
|
|
260
371
|
inputSchema: z.object({
|
|
261
372
|
item: z
|
|
262
373
|
.string()
|
|
263
374
|
.describe("The exact label text of the checklist item to check off (the words after the `[ ]`), as shown in the current plan in your instructions. Matched ignoring case and extra spaces; it must be unambiguous."),
|
|
264
|
-
channel_id: z
|
|
375
|
+
channel_id: z
|
|
376
|
+
.string()
|
|
377
|
+
.optional()
|
|
378
|
+
.describe("The id of the channel. Defaults to the current channel."),
|
|
265
379
|
}),
|
|
266
380
|
execute: async ({ item, channel_id }) => {
|
|
267
381
|
try {
|
|
@@ -276,8 +390,13 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
276
390
|
add_plan_item: tool({
|
|
277
391
|
description: "Append a new unchecked item to this message thread's plan.\n\nUse this to record a step you've discovered; pass just the new item's text, not the whole plan.",
|
|
278
392
|
inputSchema: z.object({
|
|
279
|
-
item: z
|
|
280
|
-
|
|
393
|
+
item: z
|
|
394
|
+
.string()
|
|
395
|
+
.describe("The text of the new unchecked checklist item to append."),
|
|
396
|
+
channel_id: z
|
|
397
|
+
.string()
|
|
398
|
+
.optional()
|
|
399
|
+
.describe("The id of the channel. Defaults to the current channel."),
|
|
281
400
|
}),
|
|
282
401
|
execute: async ({ item, channel_id }) => {
|
|
283
402
|
const ch = await ctx.plan.add(item, channel_id ?? ctx.channelId);
|
|
@@ -290,7 +409,9 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
290
409
|
if (opts.delegation === false)
|
|
291
410
|
return tools;
|
|
292
411
|
// Without the lookup the chat still has every other tool, so don't fail it.
|
|
293
|
-
const agents = await ctx.client.workspaces
|
|
412
|
+
const agents = await ctx.client.workspaces
|
|
413
|
+
.agents(ctx.workspaceId)
|
|
414
|
+
.catch((e) => {
|
|
294
415
|
console.warn("dana4: listing agents failed; no delegation tools:", e instanceof Error ? e.message : e);
|
|
295
416
|
return [];
|
|
296
417
|
});
|
|
@@ -302,7 +423,8 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
302
423
|
for (let i = 2; name in tools; i++)
|
|
303
424
|
name = `${base.slice(0, 63 - String(i).length)}_${i}`;
|
|
304
425
|
tools[name] = tool({
|
|
305
|
-
description: cap.description ||
|
|
426
|
+
description: cap.description ||
|
|
427
|
+
`Trigger \`${cap.key}\` from agent \`${agent.username}\`.`,
|
|
306
428
|
inputSchema: jsonSchema(capabilityToolSchema(cap.input_schema)),
|
|
307
429
|
execute: async (inputs) => {
|
|
308
430
|
const taskId = await ctx.delegate(agent.username, cap.key, inputs);
|
|
@@ -315,23 +437,38 @@ export async function dana4Tools(ctx, opts = {}) {
|
|
|
315
437
|
}
|
|
316
438
|
/** A thread's messages as model messages, oldest first: this agent's own
|
|
317
439
|
* messages become assistant turns, everyone else's user turns prefixed with
|
|
318
|
-
* the author. Only
|
|
440
|
+
* the author. Only conversation is kept; orchestrator notices and errors only
|
|
441
|
+
* when they @-tag the agent, and status lines never. */
|
|
319
442
|
export function chatHistory(messages, { me, exclude }) {
|
|
320
443
|
return messages
|
|
321
|
-
.filter((m) =>
|
|
444
|
+
.filter((m) => m.id !== exclude &&
|
|
445
|
+
(m.category === "default" ||
|
|
446
|
+
((m.category === "error" || m.category === "notice") &&
|
|
447
|
+
taggedUsernames(m.message).includes(me.toLowerCase()))))
|
|
322
448
|
.sort((a, b) => a.time.created_at.localeCompare(b.time.created_at))
|
|
323
449
|
.map((m) => {
|
|
324
450
|
const content = `${m.from_username}: ${m.category === "error" ? "ERROR: " : ""}${m.message}`;
|
|
325
|
-
return m.from_username === me
|
|
451
|
+
return m.from_username === me
|
|
452
|
+
? { role: "assistant", content }
|
|
453
|
+
: { role: "user", content };
|
|
326
454
|
});
|
|
327
455
|
}
|
|
328
|
-
/** `base` followed by the thread's topics, intent and
|
|
329
|
-
* what the conversation is for. */
|
|
456
|
+
/** `base` followed by the thread's topics, the board, intent, plan and memory, so the
|
|
457
|
+
* model knows what the conversation is for. */
|
|
330
458
|
export function threadInstructions(base, thread) {
|
|
459
|
+
const tickets = thread.tickets ?? [];
|
|
331
460
|
const context = [
|
|
332
461
|
...thread.topics.map((t) => `Thread topic: ${t.title} — ${t.summary}`),
|
|
462
|
+
...(tickets.length
|
|
463
|
+
? [
|
|
464
|
+
`Board:\n${tickets
|
|
465
|
+
.map((t) => `- ${t.number != null ? `#${t.number} ` : ""}${t.title} [${t.board_status}]${t.assignee ? ` @${t.assignee}` : ""}`)
|
|
466
|
+
.join("\n")}`,
|
|
467
|
+
]
|
|
468
|
+
: []),
|
|
333
469
|
...(thread.intent ? [`Thread intent: ${thread.intent}`] : []),
|
|
334
470
|
...(thread.plan ? [`Thread plan:\n${thread.plan}`] : []),
|
|
471
|
+
...(thread.memory ? [`Thread memory:\n${thread.memory}`] : []),
|
|
335
472
|
].join("\n");
|
|
336
473
|
return [base, context].filter(Boolean).join("\n\n");
|
|
337
474
|
}
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,12 @@ import { parseArgs } from "node:util";
|
|
|
3
3
|
import { enroll } from "./enroll.js";
|
|
4
4
|
const { values, positionals } = parseArgs({
|
|
5
5
|
allowPositionals: true,
|
|
6
|
-
options: {
|
|
6
|
+
options: {
|
|
7
|
+
username: { type: "string" },
|
|
8
|
+
bio: { type: "string" },
|
|
9
|
+
description: { type: "string" },
|
|
10
|
+
url: { type: "string" },
|
|
11
|
+
},
|
|
7
12
|
});
|
|
8
13
|
const username = values.username;
|
|
9
14
|
if (positionals[0] !== "enroll" || !username) {
|
|
@@ -11,6 +16,10 @@ if (positionals[0] !== "enroll" || !username) {
|
|
|
11
16
|
process.exitCode = 2;
|
|
12
17
|
}
|
|
13
18
|
else {
|
|
14
|
-
const key = await enroll({
|
|
19
|
+
const key = await enroll({
|
|
20
|
+
...values,
|
|
21
|
+
username,
|
|
22
|
+
url: values.url ?? process.env.DANA4_URL,
|
|
23
|
+
});
|
|
15
24
|
console.log(`\nApproved. Your API key (shown once), e.g. for DANA4_API_KEY:\n\n${key}`);
|
|
16
25
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type Automation = S["Automation"];
|
|
|
6
6
|
export type Channel = S["Channel"];
|
|
7
7
|
export type ChatThread = S["ChatThread"];
|
|
8
8
|
export type CreateAutomationBody = S["CreateAutomationBody"];
|
|
9
|
+
export type CreateTicketBody = S["CreateTicketBody"];
|
|
9
10
|
export type CreateWorkflowPayload = S["CreateWorkflowPayload"];
|
|
10
11
|
export type Document = S["Document"];
|
|
11
12
|
export type DocumentHeader = S["DocumentHeader"];
|
|
@@ -13,9 +14,13 @@ export type DocumentType = S["DocumentType"];
|
|
|
13
14
|
export type EnrollAgentResponse = S["EnrollAgentResponse"];
|
|
14
15
|
export type Message = S["Message"];
|
|
15
16
|
export type MessageCategory = S["MessageCategory"];
|
|
17
|
+
/** Routine status lines (progress, "Thinking...", blockers): never conversation.
|
|
18
|
+
* `transient` and `dependencies_status` are legacy values on old rows. */
|
|
19
|
+
export declare const skippedFromHistory: (m: Pick<Message, "category">) => boolean;
|
|
16
20
|
export type Pipe = S["Pipe"];
|
|
17
21
|
export type PresenceActivity = S["PresenceActivity"];
|
|
18
22
|
export type SearchResult = S["SearchResult"];
|
|
23
|
+
export type SdkTicket = S["SdkTicket"];
|
|
19
24
|
export type Task = S["Task"];
|
|
20
25
|
export type TaskStatus = S["TaskStatus"];
|
|
21
26
|
/** `cost_details` is optional on the wire; utoipa marks it required. */
|
|
@@ -95,6 +100,7 @@ export declare class Dana4Client {
|
|
|
95
100
|
execution_duration?: number | null;
|
|
96
101
|
id: string;
|
|
97
102
|
journey_id: string;
|
|
103
|
+
number?: number | null;
|
|
98
104
|
order: number;
|
|
99
105
|
params?: {
|
|
100
106
|
[key: string]: unknown;
|
|
@@ -106,6 +112,9 @@ export declare class Dana4Client {
|
|
|
106
112
|
step_id: string;
|
|
107
113
|
step_type: components["schemas"]["JourneyStepType"];
|
|
108
114
|
time: components["schemas"]["Timestamps"];
|
|
115
|
+
tool_calls?: {
|
|
116
|
+
[key: string]: unknown;
|
|
117
|
+
}[];
|
|
109
118
|
}[]>;
|
|
110
119
|
assigned: () => Promise<{
|
|
111
120
|
channel_id: string;
|
|
@@ -116,6 +125,7 @@ export declare class Dana4Client {
|
|
|
116
125
|
execution_duration?: number | null;
|
|
117
126
|
id: string;
|
|
118
127
|
journey_id: string;
|
|
128
|
+
number?: number | null;
|
|
119
129
|
order: number;
|
|
120
130
|
params?: {
|
|
121
131
|
[key: string]: unknown;
|
|
@@ -127,6 +137,9 @@ export declare class Dana4Client {
|
|
|
127
137
|
step_id: string;
|
|
128
138
|
step_type: components["schemas"]["JourneyStepType"];
|
|
129
139
|
time: components["schemas"]["Timestamps"];
|
|
140
|
+
tool_calls?: {
|
|
141
|
+
[key: string]: unknown;
|
|
142
|
+
}[];
|
|
130
143
|
}[]>;
|
|
131
144
|
unassigned: () => Promise<{
|
|
132
145
|
channel_id: string;
|
|
@@ -137,6 +150,7 @@ export declare class Dana4Client {
|
|
|
137
150
|
execution_duration?: number | null;
|
|
138
151
|
id: string;
|
|
139
152
|
journey_id: string;
|
|
153
|
+
number?: number | null;
|
|
140
154
|
order: number;
|
|
141
155
|
params?: {
|
|
142
156
|
[key: string]: unknown;
|
|
@@ -148,6 +162,9 @@ export declare class Dana4Client {
|
|
|
148
162
|
step_id: string;
|
|
149
163
|
step_type: components["schemas"]["JourneyStepType"];
|
|
150
164
|
time: components["schemas"]["Timestamps"];
|
|
165
|
+
tool_calls?: {
|
|
166
|
+
[key: string]: unknown;
|
|
167
|
+
}[];
|
|
151
168
|
}[]>;
|
|
152
169
|
claim: (taskId: string, capability: string) => Promise<{
|
|
153
170
|
channel_id: string;
|
|
@@ -158,6 +175,7 @@ export declare class Dana4Client {
|
|
|
158
175
|
execution_duration?: number | null;
|
|
159
176
|
id: string;
|
|
160
177
|
journey_id: string;
|
|
178
|
+
number?: number | null;
|
|
161
179
|
order: number;
|
|
162
180
|
params?: {
|
|
163
181
|
[key: string]: unknown;
|
|
@@ -169,6 +187,9 @@ export declare class Dana4Client {
|
|
|
169
187
|
step_id: string;
|
|
170
188
|
step_type: components["schemas"]["JourneyStepType"];
|
|
171
189
|
time: components["schemas"]["Timestamps"];
|
|
190
|
+
tool_calls?: {
|
|
191
|
+
[key: string]: unknown;
|
|
192
|
+
}[];
|
|
172
193
|
}>;
|
|
173
194
|
/** Start a one-step journey (e.g. `read_message`); answers its task id. */
|
|
174
195
|
start: (body: {
|
|
@@ -289,9 +310,11 @@ export declare class Dana4Client {
|
|
|
289
310
|
direct?: boolean;
|
|
290
311
|
document_id?: string | null;
|
|
291
312
|
intent?: string | null;
|
|
313
|
+
memory?: string | null;
|
|
292
314
|
messages: components["schemas"]["Message"][];
|
|
293
315
|
parent_channel_id?: string | null;
|
|
294
316
|
plan?: string | null;
|
|
317
|
+
tickets?: components["schemas"]["TicketSummary"][];
|
|
295
318
|
topics: components["schemas"]["TopicSummary"][];
|
|
296
319
|
}[]>;
|
|
297
320
|
create: (body: S["CreateDocumentPayload"]) => Promise<string>;
|
|
@@ -311,9 +334,11 @@ export declare class Dana4Client {
|
|
|
311
334
|
direct?: boolean;
|
|
312
335
|
document_id?: string | null;
|
|
313
336
|
intent?: string | null;
|
|
337
|
+
memory?: string | null;
|
|
314
338
|
messages: components["schemas"]["Message"][];
|
|
315
339
|
parent_channel_id?: string | null;
|
|
316
340
|
plan?: string | null;
|
|
341
|
+
tickets?: components["schemas"]["TicketSummary"][];
|
|
317
342
|
topics: components["schemas"]["TopicSummary"][];
|
|
318
343
|
}>;
|
|
319
344
|
messages: (channelId: string, range?: {
|
|
@@ -324,9 +349,11 @@ export declare class Dana4Client {
|
|
|
324
349
|
direct?: boolean;
|
|
325
350
|
document_id?: string | null;
|
|
326
351
|
intent?: string | null;
|
|
352
|
+
memory?: string | null;
|
|
327
353
|
messages: components["schemas"]["Message"][];
|
|
328
354
|
parent_channel_id?: string | null;
|
|
329
355
|
plan?: string | null;
|
|
356
|
+
tickets?: components["schemas"]["TicketSummary"][];
|
|
330
357
|
topics: components["schemas"]["TopicSummary"][];
|
|
331
358
|
}>;
|
|
332
359
|
send: (body: S["SendMessagePayload"]) => Promise<{
|
|
@@ -343,6 +370,7 @@ export declare class Dana4Client {
|
|
|
343
370
|
document_id: string;
|
|
344
371
|
id: string;
|
|
345
372
|
intent?: string | null;
|
|
373
|
+
memory?: string | null;
|
|
346
374
|
owners: string[];
|
|
347
375
|
parent_channel_id?: string | null;
|
|
348
376
|
parent_message_id?: string | null;
|
|
@@ -357,6 +385,22 @@ export declare class Dana4Client {
|
|
|
357
385
|
document_id: string;
|
|
358
386
|
id: string;
|
|
359
387
|
intent?: string | null;
|
|
388
|
+
memory?: string | null;
|
|
389
|
+
owners: string[];
|
|
390
|
+
parent_channel_id?: string | null;
|
|
391
|
+
parent_message_id?: string | null;
|
|
392
|
+
plan?: string | null;
|
|
393
|
+
plan_completed: boolean;
|
|
394
|
+
private: boolean;
|
|
395
|
+
time: components["schemas"]["Timestamps"];
|
|
396
|
+
title: string;
|
|
397
|
+
workspace_id: string;
|
|
398
|
+
}>;
|
|
399
|
+
setMemory: (channelId: string, memory: string) => Promise<{
|
|
400
|
+
document_id: string;
|
|
401
|
+
id: string;
|
|
402
|
+
intent?: string | null;
|
|
403
|
+
memory?: string | null;
|
|
360
404
|
owners: string[];
|
|
361
405
|
parent_channel_id?: string | null;
|
|
362
406
|
parent_message_id?: string | null;
|
|
@@ -371,6 +415,7 @@ export declare class Dana4Client {
|
|
|
371
415
|
document_id: string;
|
|
372
416
|
id: string;
|
|
373
417
|
intent?: string | null;
|
|
418
|
+
memory?: string | null;
|
|
374
419
|
owners: string[];
|
|
375
420
|
parent_channel_id?: string | null;
|
|
376
421
|
parent_message_id?: string | null;
|
|
@@ -385,6 +430,7 @@ export declare class Dana4Client {
|
|
|
385
430
|
document_id: string;
|
|
386
431
|
id: string;
|
|
387
432
|
intent?: string | null;
|
|
433
|
+
memory?: string | null;
|
|
388
434
|
owners: string[];
|
|
389
435
|
parent_channel_id?: string | null;
|
|
390
436
|
parent_message_id?: string | null;
|
|
@@ -469,6 +515,17 @@ export declare class Dana4Client {
|
|
|
469
515
|
}>;
|
|
470
516
|
delete: (automationId: string) => Promise<string>;
|
|
471
517
|
};
|
|
518
|
+
readonly tickets: {
|
|
519
|
+
/** Put a ticket on the workspace's board. Tickets are referred to by their
|
|
520
|
+
* per-workspace number (`blocked_by: [12]` means #12). */
|
|
521
|
+
create: (body: CreateTicketBody) => Promise<{
|
|
522
|
+
blocked_by: number[];
|
|
523
|
+
number: number;
|
|
524
|
+
status: components["schemas"]["BoardStatus"];
|
|
525
|
+
title: string;
|
|
526
|
+
workspace_id: string;
|
|
527
|
+
}>;
|
|
528
|
+
};
|
|
472
529
|
readonly workflows: {
|
|
473
530
|
create: (body: CreateWorkflowPayload) => Promise<{
|
|
474
531
|
definition: string;
|