@dana4/sdk 0.1.0 → 0.5.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/dist/ai.js CHANGED
@@ -18,10 +18,14 @@ export function formatDocumentList(documents) {
18
18
  .map((dir) => {
19
19
  const entries = groups
20
20
  .get(dir)
21
- .sort((a, b) => Number(isFolder(b)) - Number(isFolder(a)) || leaf(a).localeCompare(leaf(b)));
21
+ ?.sort((a, b) => Number(isFolder(b)) - Number(isFolder(a)) ||
22
+ leaf(a).localeCompare(leaf(b))) ?? [];
22
23
  const names = entries.map((d) => leaf(d) + (isFolder(d) ? "/" : ""));
23
24
  const width = Math.max(...names.map((n) => n.length));
24
- return [`${dir}:`, ...entries.map((d, i) => ` ${names[i].padEnd(width)} ${d.title}`)].join("\n");
25
+ return [
26
+ `${dir}:`,
27
+ ...entries.map((d, i) => ` ${names[i]?.padEnd(width)} ${d.title}`),
28
+ ].join("\n");
25
29
  })
26
30
  .join("\n\n");
27
31
  }
@@ -39,10 +43,13 @@ export function grep(content, pattern, context = 3) {
39
43
  const shown = new Set(hits.flatMap((i) => Array.from({ length: 2 * context + 1 }, (_, k) => i - context + k)));
40
44
  const out = [];
41
45
  let prev = -2;
42
- for (const i of [...shown].filter((i) => i >= 0 && i < lines.length).sort((a, b) => a - b)) {
46
+ for (const i of [...shown]
47
+ .filter((i) => i >= 0 && i < lines.length)
48
+ .sort((a, b) => a - b)) {
43
49
  if (i !== prev + 1 && out.length)
44
50
  out.push("---");
45
- out.push(`${regex.test(lines[i]) ? ">" : " "} ${i + 1}: ${lines[i]}`);
51
+ const line = lines[i] ?? "";
52
+ out.push(`${regex.test(line) ? ">" : " "} ${i + 1}: ${line}`);
46
53
  prev = i;
47
54
  }
48
55
  return { matches: hits.length, lines: lines.length, text: out.join("\n") };
@@ -52,7 +59,7 @@ export function insertAt(document, line, content) {
52
59
  const lines = document.match(/[^\n]*\n|[^\n]+$/g) ?? [];
53
60
  const at = Math.max(0, Math.min(line - 1, lines.length));
54
61
  // Appending after an unterminated last line: end it first, or the two join.
55
- if (at === lines.length && at > 0 && !lines[at - 1].endsWith("\n"))
62
+ if (at === lines.length && at > 0 && !lines[at - 1]?.endsWith("\n"))
56
63
  lines[at - 1] += "\n";
57
64
  lines.splice(at, 0, content.endsWith("\n") ? content : `${content}\n`);
58
65
  return lines.join("");
@@ -67,11 +74,21 @@ export function capabilityToolSchema(schema) {
67
74
  if (["workspace_id", "task_id"].includes(name))
68
75
  return false;
69
76
  const t = p?.type;
70
- return typeof t === "string" ? PRIMITIVE.has(t) : Array.isArray(t) && t.every((x) => typeof x === "string" && PRIMITIVE.has(x));
77
+ return typeof t === "string"
78
+ ? PRIMITIVE.has(t)
79
+ : Array.isArray(t) &&
80
+ t.every((x) => typeof x === "string" && PRIMITIVE.has(x));
71
81
  });
72
82
  const kept = new Set(keep.map(([n]) => n));
73
- const required = Array.isArray(schema?.required) ? schema.required.filter((r) => typeof r === "string" && kept.has(r)) : [];
74
- return { type: "object", additionalProperties: false, properties: Object.fromEntries(keep), required };
83
+ const required = Array.isArray(schema?.required)
84
+ ? schema.required.filter((r) => typeof r === "string" && kept.has(r))
85
+ : [];
86
+ return {
87
+ type: "object",
88
+ additionalProperties: false,
89
+ properties: Object.fromEntries(keep),
90
+ required,
91
+ };
75
92
  }
76
93
  /** Tools for reading and writing the workspace's documents, messaging, and the
77
94
  * thread's plan — plus, unless `delegation: false`, one `<agent>__<capability>`
@@ -80,9 +97,12 @@ export function capabilityToolSchema(schema) {
80
97
  export async function dana4Tools(ctx, opts = {}) {
81
98
  const tools = {
82
99
  list_documents: tool({
83
- description: "List documents in a folder with their paths and titles. Optionally recurse into subfolders.",
100
+ 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
101
  inputSchema: z.object({
85
- path: z.string().default("/").describe("Folder to list, as a path (e.g. '/foo/bar'). Defaults to the root."),
102
+ path: z
103
+ .string()
104
+ .default("/")
105
+ .describe("Folder to list, as a path (e.g. '/foo/bar'). Defaults to the root."),
86
106
  recursive: z
87
107
  .boolean()
88
108
  .default(false)
@@ -94,19 +114,33 @@ export async function dana4Tools(ctx, opts = {}) {
94
114
  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
115
  inputSchema: z.object({
96
116
  path: z.string().describe("Path of the document to search in."),
97
- pattern: z.string().describe("Text or regex pattern to search for. Case-insensitive."),
98
- context_lines: z.number().int().default(3).describe("Number of lines to show before and after each match."),
117
+ pattern: z
118
+ .string()
119
+ .describe("Text or regex pattern to search for. Case-insensitive."),
120
+ context_lines: z
121
+ .number()
122
+ .int()
123
+ .default(3)
124
+ .describe("Number of lines to show before and after each match."),
99
125
  }),
100
126
  execute: async ({ path, pattern, context_lines }) => {
101
127
  const r = grep((await ctx.docs.get(path)).content, pattern, context_lines);
102
- return r.matches ? `Found ${r.matches} match(es) in ${path} (${r.lines} lines total):\n${r.text}` : `No matches for '${pattern}' in ${path}`;
128
+ return r.matches
129
+ ? `Found ${r.matches} match(es) in ${path} (${r.lines} lines total):\n${r.text}`
130
+ : `No matches for '${pattern}' in ${path}`;
103
131
  },
104
132
  }),
105
133
  search_documents: tool({
106
134
  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
135
  inputSchema: z.object({
108
- query: z.string().describe("Natural-language or keyword query to search across all documents in the workspace."),
109
- limit: z.number().int().optional().describe("Max number of results to return. Defaults to the server default."),
136
+ query: z
137
+ .string()
138
+ .describe("Natural-language or keyword query to search across all documents in the workspace."),
139
+ limit: z
140
+ .number()
141
+ .int()
142
+ .optional()
143
+ .describe("Max number of results to return. Defaults to the server default."),
110
144
  }),
111
145
  execute: async ({ query, limit }) => {
112
146
  const results = await ctx.docs.search(query, limit);
@@ -114,7 +148,10 @@ export async function dana4Tools(ctx, opts = {}) {
114
148
  return `No documents matched '${query}'.`;
115
149
  return [
116
150
  `Found ${results.length} result(s) for '${query}':\n`,
117
- ...results.flatMap((r) => [`- ${r.path} — ${r.title} (score: ${r.score.toFixed(3)})`, ...(r.snippet ? [` ${r.snippet}`] : [])]),
151
+ ...results.flatMap((r) => [
152
+ `- ${r.path} — ${r.title} (score: ${r.score.toFixed(3)})`,
153
+ ...(r.snippet ? [` ${r.snippet}`] : []),
154
+ ]),
118
155
  ].join("\n");
119
156
  },
120
157
  }),
@@ -122,7 +159,11 @@ export async function dana4Tools(ctx, opts = {}) {
122
159
  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
160
  inputSchema: z.object({
124
161
  path: z.string().describe("The path to the document to read."),
125
- offset: z.number().int().optional().describe("Line number to start reading from (1-indexed). Defaults to 1."),
162
+ offset: z
163
+ .number()
164
+ .int()
165
+ .optional()
166
+ .describe("Line number to start reading from (1-indexed). Defaults to 1."),
126
167
  limit: z
127
168
  .number()
128
169
  .int()
@@ -138,18 +179,24 @@ export async function dana4Tools(ctx, opts = {}) {
138
179
  .slice(start, end)
139
180
  .map((l, i) => `${start + i + 1}: ${l}`)
140
181
  .join("\n");
141
- const more = end < lines.length ? `\n\n[Showing lines ${start + 1}-${end} of ${lines.length}. Use offset=${end + 1} to read more.]` : "";
182
+ const more = end < lines.length
183
+ ? `\n\n[Showing lines ${start + 1}-${end} of ${lines.length}. Use offset=${end + 1} to read more.]`
184
+ : "";
142
185
  return `Title: ${doc.title}\nPath: ${path}\nTotal lines: ${lines.length}\nContent:\n\n${body}${more}\n`;
143
186
  },
144
187
  }),
145
188
  get_step_result: tool({
146
189
  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
190
  inputSchema: z.object({
148
- step_id: z.string().describe("The id of the step whose result to fetch (e.g. 'step_brand_questions')."),
191
+ step_id: z
192
+ .string()
193
+ .describe("The id of the step whose result to fetch (e.g. 'step_brand_questions')."),
149
194
  }),
150
195
  execute: async ({ step_id }) => {
151
196
  const result = await ctx.stepResult(step_id);
152
- return result == null ? `No result available for step '${step_id}' yet (it may not have run or completed).` : JSON.stringify(result, null, 2);
197
+ return result == null
198
+ ? `No result available for step '${step_id}' yet (it may not have run or completed).`
199
+ : JSON.stringify(result, null, 2);
153
200
  },
154
201
  }),
155
202
  create_document: tool({
@@ -173,7 +220,10 @@ export async function dana4Tools(ctx, opts = {}) {
173
220
  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
221
  inputSchema: z.object({
175
222
  path: z.string().describe("Path to the document to overwrite."),
176
- content: z.string().default("").describe("Full replacement content. Must be under ~200 lines."),
223
+ content: z
224
+ .string()
225
+ .default("")
226
+ .describe("Full replacement content. Must be under ~200 lines."),
177
227
  }),
178
228
  execute: async ({ path, content }) => {
179
229
  if (!content)
@@ -189,7 +239,9 @@ export async function dana4Tools(ctx, opts = {}) {
189
239
  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
240
  inputSchema: z.object({
191
241
  path: z.string().describe("Path of the document to append to."),
192
- content: z.string().describe("Content to append to the end of the document."),
242
+ content: z
243
+ .string()
244
+ .describe("Content to append to the end of the document."),
193
245
  }),
194
246
  execute: async ({ path, content }) => {
195
247
  await ctx.docs.append(path, content);
@@ -200,9 +252,16 @@ export async function dana4Tools(ctx, opts = {}) {
200
252
  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
253
  inputSchema: z.object({
202
254
  path: z.string().describe("Path to the document to modify."),
203
- old_str: z.string().describe("Exact text to find and replace. Must match uniquely. Include surrounding lines for context if needed."),
204
- new_str: z.string().describe("Replacement text. Must differ from old_str."),
205
- replace_all: z.boolean().default(false).describe("Replace every occurrence instead of requiring a unique match."),
255
+ old_str: z
256
+ .string()
257
+ .describe("Exact text to find and replace. Must match uniquely. Include surrounding lines for context if needed."),
258
+ new_str: z
259
+ .string()
260
+ .describe("Replacement text. Must differ from old_str."),
261
+ replace_all: z
262
+ .boolean()
263
+ .default(false)
264
+ .describe("Replace every occurrence instead of requiring a unique match."),
206
265
  }),
207
266
  execute: async ({ path, old_str, new_str, replace_all }) => {
208
267
  try {
@@ -222,15 +281,47 @@ export async function dana4Tools(ctx, opts = {}) {
222
281
  .number()
223
282
  .int()
224
283
  .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.string().describe("Content to insert at the specified line."),
284
+ content: z
285
+ .string()
286
+ .describe("Content to insert at the specified line."),
226
287
  }),
227
288
  execute: async ({ path, line, content }) => {
228
289
  const doc = await ctx.docs.get(path, "editing");
229
290
  await ctx.docs.replace(path, insertAt(doc.content, line, content));
230
- const n = (content.endsWith("\n") ? content : `${content}\n`).split("\n").length - 1;
291
+ const n = (content.endsWith("\n") ? content : `${content}\n`).split("\n")
292
+ .length - 1;
231
293
  return `Inserted ${n} line(s) at line ${line} in ${path}`;
232
294
  },
233
295
  }),
296
+ create_ticket: tool({
297
+ 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.",
298
+ inputSchema: z.object({
299
+ title: z.string().describe("The ticket's title."),
300
+ description: z
301
+ .string()
302
+ .optional()
303
+ .describe("What needs doing, in markdown."),
304
+ status: z
305
+ .enum([
306
+ "backlog",
307
+ "todo",
308
+ "in_progress",
309
+ "in_review",
310
+ "done",
311
+ "canceled",
312
+ ])
313
+ .optional()
314
+ .describe("The board column. Defaults to backlog."),
315
+ blocked_by: z
316
+ .array(z.number().int())
317
+ .default([])
318
+ .describe("Numbers of the tickets that must finish first."),
319
+ }),
320
+ execute: async (ticket) => {
321
+ const t = await ctx.tickets.create(ticket);
322
+ return `Ticket #${t.number} created in workspace ${ctx.workspaceId}`;
323
+ },
324
+ }),
234
325
  send_message: tool({
235
326
  description: "Send a message to a channel. Uses the current channel if channel_id is omitted.",
236
327
  inputSchema: z.object({
@@ -248,20 +339,42 @@ export async function dana4Tools(ctx, opts = {}) {
248
339
  plan: z
249
340
  .string()
250
341
  .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.string().optional().describe("The id of the channel. Defaults to the current channel."),
342
+ channel_id: z
343
+ .string()
344
+ .optional()
345
+ .describe("The id of the channel. Defaults to the current channel."),
252
346
  }),
253
347
  execute: async ({ plan, channel_id }) => {
254
348
  const ch = await ctx.plan.set(plan, channel_id ?? ctx.channelId);
255
349
  return planStatus(ch.id, ch.plan_completed);
256
350
  },
257
351
  }),
352
+ set_memory: tool({
353
+ 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.",
354
+ inputSchema: z.object({
355
+ memory: z
356
+ .string()
357
+ .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."),
358
+ channel_id: z
359
+ .string()
360
+ .optional()
361
+ .describe("The id of the channel. Defaults to the current channel."),
362
+ }),
363
+ execute: async ({ memory, channel_id }) => {
364
+ const ch = await ctx.memory.set(memory, channel_id ?? ctx.channelId);
365
+ return `Memory updated for channel ${ch.id}.`;
366
+ },
367
+ }),
258
368
  complete_plan_item: tool({
259
369
  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
370
  inputSchema: z.object({
261
371
  item: z
262
372
  .string()
263
373
  .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.string().optional().describe("The id of the channel. Defaults to the current channel."),
374
+ channel_id: z
375
+ .string()
376
+ .optional()
377
+ .describe("The id of the channel. Defaults to the current channel."),
265
378
  }),
266
379
  execute: async ({ item, channel_id }) => {
267
380
  try {
@@ -276,8 +389,13 @@ export async function dana4Tools(ctx, opts = {}) {
276
389
  add_plan_item: tool({
277
390
  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
391
  inputSchema: z.object({
279
- item: z.string().describe("The text of the new unchecked checklist item to append."),
280
- channel_id: z.string().optional().describe("The id of the channel. Defaults to the current channel."),
392
+ item: z
393
+ .string()
394
+ .describe("The text of the new unchecked checklist item to append."),
395
+ channel_id: z
396
+ .string()
397
+ .optional()
398
+ .describe("The id of the channel. Defaults to the current channel."),
281
399
  }),
282
400
  execute: async ({ item, channel_id }) => {
283
401
  const ch = await ctx.plan.add(item, channel_id ?? ctx.channelId);
@@ -290,7 +408,9 @@ export async function dana4Tools(ctx, opts = {}) {
290
408
  if (opts.delegation === false)
291
409
  return tools;
292
410
  // Without the lookup the chat still has every other tool, so don't fail it.
293
- const agents = await ctx.client.workspaces.agents(ctx.workspaceId).catch((e) => {
411
+ const agents = await ctx.client.workspaces
412
+ .agents(ctx.workspaceId)
413
+ .catch((e) => {
294
414
  console.warn("dana4: listing agents failed; no delegation tools:", e instanceof Error ? e.message : e);
295
415
  return [];
296
416
  });
@@ -302,7 +422,8 @@ export async function dana4Tools(ctx, opts = {}) {
302
422
  for (let i = 2; name in tools; i++)
303
423
  name = `${base.slice(0, 63 - String(i).length)}_${i}`;
304
424
  tools[name] = tool({
305
- description: cap.description || `Trigger \`${cap.key}\` from agent \`${agent.username}\`.`,
425
+ description: cap.description ||
426
+ `Trigger \`${cap.key}\` from agent \`${agent.username}\`.`,
306
427
  inputSchema: jsonSchema(capabilityToolSchema(cap.input_schema)),
307
428
  execute: async (inputs) => {
308
429
  const taskId = await ctx.delegate(agent.username, cap.key, inputs);
@@ -318,20 +439,32 @@ export async function dana4Tools(ctx, opts = {}) {
318
439
  * the author. Only conversational messages (and errors) are kept. */
319
440
  export function chatHistory(messages, { me, exclude }) {
320
441
  return messages
321
- .filter((m) => (m.category === "default" || m.category === "error") && m.id !== exclude)
442
+ .filter((m) => (m.category === "default" || m.category === "error") &&
443
+ m.id !== exclude)
322
444
  .sort((a, b) => a.time.created_at.localeCompare(b.time.created_at))
323
445
  .map((m) => {
324
446
  const content = `${m.from_username}: ${m.category === "error" ? "ERROR: " : ""}${m.message}`;
325
- return m.from_username === me ? { role: "assistant", content } : { role: "user", content };
447
+ return m.from_username === me
448
+ ? { role: "assistant", content }
449
+ : { role: "user", content };
326
450
  });
327
451
  }
328
- /** `base` followed by the thread's topics, intent and plan, so the model knows
329
- * what the conversation is for. */
452
+ /** `base` followed by the thread's topics, the board, intent, plan and memory, so the
453
+ * model knows what the conversation is for. */
330
454
  export function threadInstructions(base, thread) {
455
+ const tickets = thread.tickets ?? [];
331
456
  const context = [
332
457
  ...thread.topics.map((t) => `Thread topic: ${t.title} — ${t.summary}`),
458
+ ...(tickets.length
459
+ ? [
460
+ `Board:\n${tickets
461
+ .map((t) => `- ${t.number != null ? `#${t.number} ` : ""}${t.title} [${t.board_status}]${t.assignee ? ` @${t.assignee}` : ""}`)
462
+ .join("\n")}`,
463
+ ]
464
+ : []),
333
465
  ...(thread.intent ? [`Thread intent: ${thread.intent}`] : []),
334
466
  ...(thread.plan ? [`Thread plan:\n${thread.plan}`] : []),
467
+ ...(thread.memory ? [`Thread memory:\n${thread.memory}`] : []),
335
468
  ].join("\n");
336
469
  return [base, context].filter(Boolean).join("\n\n");
337
470
  }
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: { username: { type: "string" }, bio: { type: "string" }, description: { type: "string" }, url: { type: "string" } },
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({ ...values, username, url: values.url ?? process.env.DANA4_URL });
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"];
@@ -16,6 +17,7 @@ export type MessageCategory = S["MessageCategory"];
16
17
  export type Pipe = S["Pipe"];
17
18
  export type PresenceActivity = S["PresenceActivity"];
18
19
  export type SearchResult = S["SearchResult"];
20
+ export type SdkTicket = S["SdkTicket"];
19
21
  export type Task = S["Task"];
20
22
  export type TaskStatus = S["TaskStatus"];
21
23
  /** `cost_details` is optional on the wire; utoipa marks it required. */
@@ -95,6 +97,7 @@ export declare class Dana4Client {
95
97
  execution_duration?: number | null;
96
98
  id: string;
97
99
  journey_id: string;
100
+ number?: number | null;
98
101
  order: number;
99
102
  params?: {
100
103
  [key: string]: unknown;
@@ -106,6 +109,9 @@ export declare class Dana4Client {
106
109
  step_id: string;
107
110
  step_type: components["schemas"]["JourneyStepType"];
108
111
  time: components["schemas"]["Timestamps"];
112
+ tool_calls?: {
113
+ [key: string]: unknown;
114
+ }[];
109
115
  }[]>;
110
116
  assigned: () => Promise<{
111
117
  channel_id: string;
@@ -116,6 +122,7 @@ export declare class Dana4Client {
116
122
  execution_duration?: number | null;
117
123
  id: string;
118
124
  journey_id: string;
125
+ number?: number | null;
119
126
  order: number;
120
127
  params?: {
121
128
  [key: string]: unknown;
@@ -127,6 +134,9 @@ export declare class Dana4Client {
127
134
  step_id: string;
128
135
  step_type: components["schemas"]["JourneyStepType"];
129
136
  time: components["schemas"]["Timestamps"];
137
+ tool_calls?: {
138
+ [key: string]: unknown;
139
+ }[];
130
140
  }[]>;
131
141
  unassigned: () => Promise<{
132
142
  channel_id: string;
@@ -137,6 +147,7 @@ export declare class Dana4Client {
137
147
  execution_duration?: number | null;
138
148
  id: string;
139
149
  journey_id: string;
150
+ number?: number | null;
140
151
  order: number;
141
152
  params?: {
142
153
  [key: string]: unknown;
@@ -148,6 +159,9 @@ export declare class Dana4Client {
148
159
  step_id: string;
149
160
  step_type: components["schemas"]["JourneyStepType"];
150
161
  time: components["schemas"]["Timestamps"];
162
+ tool_calls?: {
163
+ [key: string]: unknown;
164
+ }[];
151
165
  }[]>;
152
166
  claim: (taskId: string, capability: string) => Promise<{
153
167
  channel_id: string;
@@ -158,6 +172,7 @@ export declare class Dana4Client {
158
172
  execution_duration?: number | null;
159
173
  id: string;
160
174
  journey_id: string;
175
+ number?: number | null;
161
176
  order: number;
162
177
  params?: {
163
178
  [key: string]: unknown;
@@ -169,6 +184,9 @@ export declare class Dana4Client {
169
184
  step_id: string;
170
185
  step_type: components["schemas"]["JourneyStepType"];
171
186
  time: components["schemas"]["Timestamps"];
187
+ tool_calls?: {
188
+ [key: string]: unknown;
189
+ }[];
172
190
  }>;
173
191
  /** Start a one-step journey (e.g. `read_message`); answers its task id. */
174
192
  start: (body: {
@@ -289,9 +307,11 @@ export declare class Dana4Client {
289
307
  direct?: boolean;
290
308
  document_id?: string | null;
291
309
  intent?: string | null;
310
+ memory?: string | null;
292
311
  messages: components["schemas"]["Message"][];
293
312
  parent_channel_id?: string | null;
294
313
  plan?: string | null;
314
+ tickets?: components["schemas"]["TicketSummary"][];
295
315
  topics: components["schemas"]["TopicSummary"][];
296
316
  }[]>;
297
317
  create: (body: S["CreateDocumentPayload"]) => Promise<string>;
@@ -311,9 +331,11 @@ export declare class Dana4Client {
311
331
  direct?: boolean;
312
332
  document_id?: string | null;
313
333
  intent?: string | null;
334
+ memory?: string | null;
314
335
  messages: components["schemas"]["Message"][];
315
336
  parent_channel_id?: string | null;
316
337
  plan?: string | null;
338
+ tickets?: components["schemas"]["TicketSummary"][];
317
339
  topics: components["schemas"]["TopicSummary"][];
318
340
  }>;
319
341
  messages: (channelId: string, range?: {
@@ -324,9 +346,11 @@ export declare class Dana4Client {
324
346
  direct?: boolean;
325
347
  document_id?: string | null;
326
348
  intent?: string | null;
349
+ memory?: string | null;
327
350
  messages: components["schemas"]["Message"][];
328
351
  parent_channel_id?: string | null;
329
352
  plan?: string | null;
353
+ tickets?: components["schemas"]["TicketSummary"][];
330
354
  topics: components["schemas"]["TopicSummary"][];
331
355
  }>;
332
356
  send: (body: S["SendMessagePayload"]) => Promise<{
@@ -343,6 +367,7 @@ export declare class Dana4Client {
343
367
  document_id: string;
344
368
  id: string;
345
369
  intent?: string | null;
370
+ memory?: string | null;
346
371
  owners: string[];
347
372
  parent_channel_id?: string | null;
348
373
  parent_message_id?: string | null;
@@ -357,6 +382,22 @@ export declare class Dana4Client {
357
382
  document_id: string;
358
383
  id: string;
359
384
  intent?: string | null;
385
+ memory?: string | null;
386
+ owners: string[];
387
+ parent_channel_id?: string | null;
388
+ parent_message_id?: string | null;
389
+ plan?: string | null;
390
+ plan_completed: boolean;
391
+ private: boolean;
392
+ time: components["schemas"]["Timestamps"];
393
+ title: string;
394
+ workspace_id: string;
395
+ }>;
396
+ setMemory: (channelId: string, memory: string) => Promise<{
397
+ document_id: string;
398
+ id: string;
399
+ intent?: string | null;
400
+ memory?: string | null;
360
401
  owners: string[];
361
402
  parent_channel_id?: string | null;
362
403
  parent_message_id?: string | null;
@@ -371,6 +412,7 @@ export declare class Dana4Client {
371
412
  document_id: string;
372
413
  id: string;
373
414
  intent?: string | null;
415
+ memory?: string | null;
374
416
  owners: string[];
375
417
  parent_channel_id?: string | null;
376
418
  parent_message_id?: string | null;
@@ -385,6 +427,7 @@ export declare class Dana4Client {
385
427
  document_id: string;
386
428
  id: string;
387
429
  intent?: string | null;
430
+ memory?: string | null;
388
431
  owners: string[];
389
432
  parent_channel_id?: string | null;
390
433
  parent_message_id?: string | null;
@@ -469,6 +512,17 @@ export declare class Dana4Client {
469
512
  }>;
470
513
  delete: (automationId: string) => Promise<string>;
471
514
  };
515
+ readonly tickets: {
516
+ /** Put a ticket on the workspace's board. Tickets are referred to by their
517
+ * per-workspace number (`blocked_by: [12]` means #12). */
518
+ create: (body: CreateTicketBody) => Promise<{
519
+ blocked_by: number[];
520
+ number: number;
521
+ status: components["schemas"]["BoardStatus"];
522
+ title: string;
523
+ workspace_id: string;
524
+ }>;
525
+ };
472
526
  readonly workflows: {
473
527
  create: (body: CreateWorkflowPayload) => Promise<{
474
528
  definition: string;