@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/dist/client.js CHANGED
@@ -1,3 +1,8 @@
1
+ /** Routine status lines (progress, "Thinking...", blockers): never conversation.
2
+ * `transient` and `dependencies_status` are legacy values on old rows. */
3
+ export const skippedFromHistory = (m) => m.category === "skip_from_history" ||
4
+ m.category === "transient" ||
5
+ m.category === "dependencies_status";
1
6
  export const DEFAULT_URL = "https://app.dana4.io";
2
7
  /** A non-2xx answer from Dana4. `status` 401 means a revoked key or a workspace
3
8
  * the agent is not a member of; 409 on a document edit means a stale read. */
@@ -57,9 +62,13 @@ export class Dana4Client {
57
62
  active: () => this.request("GET", "/tasks/active"),
58
63
  assigned: () => this.request("GET", "/tasks/assigned"),
59
64
  unassigned: () => this.request("GET", "/tasks/unassigned"),
60
- claim: (taskId, capability) => this.request("POST", `/tasks/${taskId}/claim`, { body: { capability } }),
65
+ claim: (taskId, capability) => this.request("POST", `/tasks/${taskId}/claim`, {
66
+ body: { capability },
67
+ }),
61
68
  /** Start a one-step journey (e.g. `read_message`); answers its task id. */
62
- start: (body) => this.request("POST", "/tasks", { body: { params: null, ...body } }),
69
+ start: (body) => this.request("POST", "/tasks", {
70
+ body: { params: null, ...body },
71
+ }),
63
72
  update: (taskId, body) => this.request("PATCH", `/tasks/${taskId}`, { body }),
64
73
  /** Workspace params merged with the journey's params. */
65
74
  params: (taskId) => this.request("GET", `/tasks/${taskId}/params`),
@@ -73,23 +82,40 @@ export class Dana4Client {
73
82
  source: (documentId) => this.request("GET", `/documents/${documentId}/source`),
74
83
  search: (workspaceId, q, limit) => this.request("GET", `/workspaces/${workspaceId}/documents/search`, { query: { q, limit } }),
75
84
  /** Every thread on a document; the root discussion has no `parent_channel_id`. */
76
- messages: (documentId, range = {}) => this.request("GET", `/documents/${documentId}/messages`, { query: range }),
85
+ messages: (documentId, range = {}) => this.request("GET", `/documents/${documentId}/messages`, {
86
+ query: range,
87
+ }),
77
88
  create: (body) => this.request("POST", "/documents", { body }),
78
89
  replace: (body) => this.request("POST", "/documents/replace", { body }),
79
90
  append: (body) => this.request("POST", "/documents/append", { body }),
80
- edit: (body) => this.request("POST", "/documents/edit", { body }),
81
- presence: (documentId, activity) => this.request("PUT", `/documents/${documentId}/presence`, { body: { activity } }),
91
+ edit: (body) => this.request("POST", "/documents/edit", {
92
+ body,
93
+ }),
94
+ presence: (documentId, activity) => this.request("PUT", `/documents/${documentId}/presence`, {
95
+ body: { activity },
96
+ }),
82
97
  };
83
98
  chat = {
84
99
  /** The next channel with unread messages for this agent. Marks them read:
85
100
  * delivery is at-most-once. `channel_id` is "" when there is nothing. */
86
101
  take: () => this.request("POST", "/chats/take"),
87
- messages: (channelId, range = {}) => this.request("GET", `/channels/${channelId}/messages`, { query: range }),
102
+ messages: (channelId, range = {}) => this.request("GET", `/channels/${channelId}/messages`, {
103
+ query: range,
104
+ }),
88
105
  send: (body) => this.request("POST", "/messages", { body }),
89
106
  privateChannels: (workspaceId) => this.request("GET", `/workspaces/${workspaceId}/private-channels`),
90
- setPlan: (channelId, plan) => this.request("PUT", `/channels/${channelId}/plan`, { body: { plan } }),
91
- completePlanItem: (channelId, item) => this.request("POST", `/channels/${channelId}/plan/complete`, { body: { item } }),
92
- addPlanItem: (channelId, item) => this.request("POST", `/channels/${channelId}/plan/items`, { body: { item } }),
107
+ setPlan: (channelId, plan) => this.request("PUT", `/channels/${channelId}/plan`, {
108
+ body: { plan },
109
+ }),
110
+ setMemory: (channelId, memory) => this.request("PUT", `/channels/${channelId}/memory`, {
111
+ body: { memory },
112
+ }),
113
+ completePlanItem: (channelId, item) => this.request("POST", `/channels/${channelId}/plan/complete`, {
114
+ body: { item },
115
+ }),
116
+ addPlanItem: (channelId, item) => this.request("POST", `/channels/${channelId}/plan/items`, {
117
+ body: { item },
118
+ }),
93
119
  };
94
120
  workspaces = {
95
121
  list: () => this.request("GET", "/workspaces"),
@@ -104,6 +130,11 @@ export class Dana4Client {
104
130
  create: (body) => this.request("POST", "/automations", { body }),
105
131
  delete: (automationId) => this.request("DELETE", `/automations/${automationId}`),
106
132
  };
133
+ tickets = {
134
+ /** Put a ticket on the workspace's board. Tickets are referred to by their
135
+ * per-workspace number (`blocked_by: [12]` means #12). */
136
+ create: (body) => this.request("POST", "/tickets", { body }),
137
+ };
107
138
  workflows = {
108
139
  create: (body) => this.request("POST", "/workflows", { body }),
109
140
  };
@@ -117,7 +148,9 @@ export class Dana4Client {
117
148
  const put = await this.#fetch(url, { method: "PUT", body: data });
118
149
  if (!put.ok)
119
150
  throw new Dana4Error(put.status, await put.text(), "asset upload");
120
- const assetId = await this.request("POST", "/assets", { body: { task_id: taskId, key } });
151
+ const assetId = await this.request("POST", "/assets", {
152
+ body: { task_id: taskId, key },
153
+ });
121
154
  return { key, assetId, url: `dana4-asset://${key}` };
122
155
  },
123
156
  };
@@ -21,17 +21,24 @@ export class Dana4Agent extends Agent {
21
21
  pollInterval = 5;
22
22
  #runtime;
23
23
  get runtime() {
24
- this.#runtime ??= new AgentRuntime(this.agent, new Dana4Client({ apiKey: this.env.DANA4_API_KEY, url: this.env.DANA4_URL }));
24
+ this.#runtime ??= new AgentRuntime(this.agent, new Dana4Client({
25
+ apiKey: this.env.DANA4_API_KEY,
26
+ url: this.env.DANA4_URL,
27
+ }));
25
28
  return this.#runtime;
26
29
  }
27
30
  async onStart() {
28
31
  // Idempotent: one schedule however often the object wakes.
29
32
  await this.scheduleEvery(this.pollInterval, "poll");
30
- await this.runtime.register().catch((e) => console.error("dana4: register failed:", e));
33
+ await this.runtime
34
+ .register()
35
+ .catch((e) => console.error("dana4: register failed:", e));
31
36
  // A fresh instance runs no tasks yet, so any still active were stranded by
32
37
  // an eviction, e.g. between `tasks/take` and their fiber's first stash.
33
38
  // Fibers recovered just before this already re-queued theirs (idempotent).
34
- await this.runtime.requeueActive().catch((e) => console.error("dana4: re-queuing failed:", e));
39
+ await this.runtime
40
+ .requeueActive()
41
+ .catch((e) => console.error("dana4: re-queuing failed:", e));
35
42
  }
36
43
  /** One round: take work, run each item in its own fiber. Overlapping rounds
37
44
  * are skipped by the scheduler, and fibers aren't awaited, so a long task
package/dist/enroll.js CHANGED
@@ -1,16 +1,25 @@
1
- import { DEFAULT_URL, Dana4Error } from "./client.js";
1
+ import { Dana4Error, DEFAULT_URL } from "./client.js";
2
2
  /** Get an API key for a new agent through the device flow. `onLink` gets the
3
3
  * link (and code) for a person to open; once they sign in and approve, the
4
4
  * agent exists, owned by them, in the workspaces they picked, and this answers
5
5
  * its key. The key is shown once: store it (e.g. as `DANA4_API_KEY`). */
6
6
  export async function enroll(opts) {
7
7
  const base = `${(opts.url ?? DEFAULT_URL).replace(/\/+$/, "")}/api-sdk/v1/agents/enroll`;
8
- const post = (path, body) => fetch(base + path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
9
- const r = await post("", { username: opts.username, bio: opts.bio, description: opts.description });
8
+ const post = (path, body) => fetch(base + path, {
9
+ method: "POST",
10
+ headers: { "Content-Type": "application/json" },
11
+ body: JSON.stringify(body),
12
+ });
13
+ const r = await post("", {
14
+ username: opts.username,
15
+ bio: opts.bio,
16
+ description: opts.description,
17
+ });
10
18
  if (!r.ok)
11
19
  throw new Dana4Error(r.status, await r.text(), "enroll");
12
20
  const start = (await r.json());
13
- (opts.onLink ?? ((link, code) => console.log(`To connect @${opts.username}, open\n\n ${link}\n\nand check the code ${code}. Waiting for approval...`)))(start.verification_uri_complete, start.user_code);
21
+ (opts.onLink ??
22
+ ((link, code) => console.log(`To connect @${opts.username}, open\n\n ${link}\n\nand check the code ${code}. Waiting for approval...`)))(start.verification_uri_complete, start.user_code);
14
23
  const deadline = Date.now() + start.expires_in * 1000;
15
24
  while (Date.now() < deadline) {
16
25
  await new Promise((resolve) => setTimeout(resolve, start.interval * 1000));
package/dist/run.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { AgentRuntime } from "./agent.js";
2
2
  import { Dana4Client } from "./client.js";
3
- const env = (name) => globalThis.process?.env[name];
3
+ const env = (name) => globalThis
4
+ .process?.env[name];
4
5
  /** Run an agent as a long-lived process (Node, Bun, Deno): register, re-queue
5
6
  * tasks a previous crash left open, then poll every `interval` seconds until
6
7
  * `signal` aborts. Work runs concurrently, so a long task never delays chat.
@@ -8,7 +9,11 @@ const env = (name) => globalThis.process?.env[name];
8
9
  * `apiKey` and `url` default to `DANA4_API_KEY` and `DANA4_URL`. */
9
10
  export async function run(agent, opts = {}) {
10
11
  const { interval = 5, signal, log = console, ...client } = opts;
11
- const rt = new AgentRuntime(agent, new Dana4Client({ apiKey: client.apiKey ?? env("DANA4_API_KEY") ?? "", url: client.url ?? env("DANA4_URL"), fetch: client.fetch }), log);
12
+ const rt = new AgentRuntime(agent, new Dana4Client({
13
+ apiKey: client.apiKey ?? env("DANA4_API_KEY") ?? "",
14
+ url: client.url ?? env("DANA4_URL"),
15
+ fetch: client.fetch,
16
+ }), log);
12
17
  log.info(`dana4: connected as @${await rt.register()}`);
13
18
  await rt.requeueActive();
14
19
  while (!signal?.aborted) {