@personaai/runtime 0.15.1 → 0.16.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 +17 -7
- package/dist/index.cjs +95 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -9
- package/dist/index.d.ts +18 -9
- package/dist/index.js +95 -2
- package/dist/index.js.map +1 -1
- package/package.json +67 -72
- package/dist/docs/.nojekyll +0 -1
package/README.md
CHANGED
|
@@ -5,12 +5,13 @@ shared engine every framework adapter (`@personaai/adapters/express`, `@personaa
|
|
|
5
5
|
to be a thin translation layer over — see
|
|
6
6
|
[the SDK Ecosystem plan](https://github.com/hasanraiyan/agent-marketplace/blob/feat/ai/product-research/11-sdk-new/package-ecosystem.md).
|
|
7
7
|
|
|
8
|
-
**v0.
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
**v0.16.0.** New opt-in outbound messaging: `POST /messages` (plain SMS/WhatsApp send) and
|
|
9
|
+
`POST /messages/agent` (the Agent composes the reply), both behind `capabilities.messages` — off by
|
|
10
|
+
default because a send targets any E.164 number the caller names and spends this Project's Twilio
|
|
11
|
+
balance. Also includes `/memory` and `/memory/file`'s `scope: "workspace"` for an Agent's own
|
|
12
|
+
`/workspace/` files, full Workflows engine support
|
|
11
13
|
(`POST /workflows/:id/stream`, `GET /workflows`, `POST /workflows/runs/:runId/cancel`,
|
|
12
|
-
`GET /workflows/runs/:runId/resume`), `
|
|
13
|
-
`beforeWorkflowNode`/`afterWorkflowNode` lifecycle hooks. Unified adapter [`@personaai/adapters`](https://persona.hasanraiyan.me/guides/express/quickstart) provides `express`/`nextjs`/`nestjs` bindings. For non-covered hosts, see
|
|
14
|
+
`GET /workflows/runs/:runId/resume`), and `beforeWorkflowNode`/`afterWorkflowNode` lifecycle hooks. Unified adapter [`@personaai/adapters`](https://persona.hasanraiyan.me/guides/express/quickstart) provides `express`/`nextjs`/`nestjs` bindings. For non-covered hosts, see
|
|
14
15
|
[Quickstart](#quickstart) for how to run it directly against raw Node `http`, and
|
|
15
16
|
[Not yet implemented](#not-yet-implemented) for what's missing before it's a complete Level 2
|
|
16
17
|
runtime.
|
|
@@ -176,6 +177,8 @@ how to enable them safely.
|
|
|
176
177
|
| `GET` | `/workflows/:id/mermaid` | `workflowsWrite` | `client.workflows.getMermaid(id)` → `{mermaid}` |
|
|
177
178
|
| `GET` | `/workflows/:id/runs` | `workflowsWrite` | `client.workflows.listRuns(id, params)` |
|
|
178
179
|
| `GET` | `/workflows/runs/:runId` | `workflowsWrite` | `client.workflows.getRun(runId)` |
|
|
180
|
+
| `POST` | `/messages` | `messages` | `client.messages.send({to, body?, channel?, mediaUrl?, contentSid?, contentVariables?})` → `{channel, to, from, messageSids, status, parts}`. `to` is any E.164 number; the channel is inferred from a `whatsapp:` prefix unless given. A body is required unless `contentSid` supplies an approved WhatsApp template. |
|
|
181
|
+
| `POST` | `/messages/agent` | `messages` | `client.messages.sendFromAgent({agentId, to, prompt, channel?, displayName?})` — runs the Agent on the conversation shared by all channels for that number, then delivers its reply. `422` for guarded (`interruptOn`) Agents, same as voice. |
|
|
179
182
|
|
|
180
183
|
A disabled capability's routes are simply absent from the route table — a request to one 404s
|
|
181
184
|
(or, where an always-on route shares the same path with a different method, e.g. `POST /agents`
|
|
@@ -192,9 +195,15 @@ oversight:
|
|
|
192
195
|
user `resolveUser` returns.
|
|
193
196
|
- **Opt-in via `capabilities`**: Project-level configuration — LLM provider credentials, skill
|
|
194
197
|
authoring, knowledge base and vector store management, security audit logs, an agent-building
|
|
195
|
-
co-pilot, workflow canvas builder/publishing,
|
|
198
|
+
co-pilot, workflow canvas builder/publishing, full Agent/MCP-server CRUD, and outbound
|
|
199
|
+
SMS/WhatsApp. **Every one of these defaults to `false`.** Upgrading
|
|
196
200
|
this package never silently exposes new surface to whoever `resolveUser` accepts.
|
|
197
201
|
|
|
202
|
+
`messages` is the one opt-in flag that isn't configuration: it's a per-request action, like
|
|
203
|
+
`voice/sessions`. It's still off by default because a send reaches any number the caller names
|
|
204
|
+
and spends this Project's Twilio balance — whoever `resolveUser` accepts would be able to text
|
|
205
|
+
arbitrary people, which is a materially larger blast radius than an end-user-scoped chat run.
|
|
206
|
+
|
|
198
207
|
```ts
|
|
199
208
|
createRuntime({
|
|
200
209
|
// ...
|
|
@@ -208,6 +217,7 @@ createRuntime({
|
|
|
208
217
|
auditLogs: false, // default
|
|
209
218
|
architect: false, // default
|
|
210
219
|
workflowsWrite: false, // default — authoring and version snapshots
|
|
220
|
+
messages: false, // default — sends spend the Project's Twilio balance
|
|
211
221
|
},
|
|
212
222
|
});
|
|
213
223
|
```
|
|
@@ -420,7 +430,7 @@ modes (`mode: 'development' | 'production'`, default `'production'` unless
|
|
|
420
430
|
|
|
421
431
|
## Not yet implemented
|
|
422
432
|
|
|
423
|
-
This is v0.
|
|
433
|
+
This is v0.16.0. Every SDK resource now has a route (see [Routes](#routes)); what's left is either a
|
|
424
434
|
genuine unclosed gap or an intentional package boundary, not an oversight:
|
|
425
435
|
|
|
426
436
|
- **Multi-instance reconnect/resume** — see
|
package/dist/index.cjs
CHANGED
|
@@ -159,7 +159,7 @@ function evictStaleRuns(runs, now, graceMs = DEFAULT_RUN_GRACE_MS, maxTracked =
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
// src/version.ts
|
|
162
|
-
var RUNTIME_VERSION = "0.
|
|
162
|
+
var RUNTIME_VERSION = "0.16.0";
|
|
163
163
|
|
|
164
164
|
// src/routes/health.ts
|
|
165
165
|
var alwaysOnCapabilities = {
|
|
@@ -878,6 +878,92 @@ var createVoiceSession = async (request, ctx) => {
|
|
|
878
878
|
return json(201, ticket);
|
|
879
879
|
};
|
|
880
880
|
|
|
881
|
+
// src/routes/messages.ts
|
|
882
|
+
var MESSAGE_CHANNELS = /* @__PURE__ */ new Set(["sms", "whatsapp"]);
|
|
883
|
+
function optionalChannel(body) {
|
|
884
|
+
const value = body.channel;
|
|
885
|
+
if (value === void 0) return void 0;
|
|
886
|
+
if (typeof value !== "string" || !MESSAGE_CHANNELS.has(value)) {
|
|
887
|
+
throw new RuntimeHttpError(400, "INVALID_REQUEST", '"channel" must be "sms" or "whatsapp".');
|
|
888
|
+
}
|
|
889
|
+
return value;
|
|
890
|
+
}
|
|
891
|
+
function optionalStringField(body, field) {
|
|
892
|
+
const value = body[field];
|
|
893
|
+
if (value === void 0) return void 0;
|
|
894
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
895
|
+
throw new RuntimeHttpError(400, "INVALID_REQUEST", `"${field}" must be a non-empty string.`);
|
|
896
|
+
}
|
|
897
|
+
return value;
|
|
898
|
+
}
|
|
899
|
+
function optionalMediaUrl(body) {
|
|
900
|
+
const value = body.mediaUrl;
|
|
901
|
+
if (value === void 0) return void 0;
|
|
902
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
903
|
+
if (Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.length > 0)) {
|
|
904
|
+
return value;
|
|
905
|
+
}
|
|
906
|
+
throw new RuntimeHttpError(
|
|
907
|
+
400,
|
|
908
|
+
"INVALID_REQUEST",
|
|
909
|
+
'"mediaUrl" must be a string or an array of strings.'
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
function optionalContentVariables(body) {
|
|
913
|
+
const value = body.contentVariables;
|
|
914
|
+
if (value === void 0) return void 0;
|
|
915
|
+
if (typeof value === "string") return value;
|
|
916
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
917
|
+
return value;
|
|
918
|
+
}
|
|
919
|
+
throw new RuntimeHttpError(
|
|
920
|
+
400,
|
|
921
|
+
"INVALID_REQUEST",
|
|
922
|
+
'"contentVariables" must be an object or a JSON string.'
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
var sendMessage = async (request, ctx) => {
|
|
926
|
+
const body = requireBodyObject(request.body);
|
|
927
|
+
const to = requireStringField(body, "to");
|
|
928
|
+
const channel = optionalChannel(body);
|
|
929
|
+
const text = optionalStringField(body, "body");
|
|
930
|
+
const mediaUrl = optionalMediaUrl(body);
|
|
931
|
+
const contentSid = optionalStringField(body, "contentSid");
|
|
932
|
+
const contentVariables = optionalContentVariables(body);
|
|
933
|
+
if (text === void 0 && contentSid === void 0) {
|
|
934
|
+
throw new RuntimeHttpError(
|
|
935
|
+
400,
|
|
936
|
+
"INVALID_REQUEST",
|
|
937
|
+
'"body" is required unless "contentSid" is provided.'
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
const delivery = await ctx.client.messages.send({
|
|
941
|
+
to,
|
|
942
|
+
...channel ? { channel } : {},
|
|
943
|
+
...text ? { body: text } : {},
|
|
944
|
+
...mediaUrl ? { mediaUrl } : {},
|
|
945
|
+
...contentSid ? { contentSid } : {},
|
|
946
|
+
...contentVariables ? { contentVariables } : {}
|
|
947
|
+
});
|
|
948
|
+
return json(200, delivery);
|
|
949
|
+
};
|
|
950
|
+
var sendAgentMessage = async (request, ctx) => {
|
|
951
|
+
const body = requireBodyObject(request.body);
|
|
952
|
+
const agentId = requireStringField(body, "agentId");
|
|
953
|
+
const to = requireStringField(body, "to");
|
|
954
|
+
const prompt = requireStringField(body, "prompt");
|
|
955
|
+
const channel = optionalChannel(body);
|
|
956
|
+
const displayName = optionalStringField(body, "displayName");
|
|
957
|
+
const delivery = await ctx.client.messages.sendFromAgent({
|
|
958
|
+
agentId,
|
|
959
|
+
to,
|
|
960
|
+
prompt,
|
|
961
|
+
...channel ? { channel } : {},
|
|
962
|
+
...displayName ? { displayName } : {}
|
|
963
|
+
});
|
|
964
|
+
return json(200, delivery);
|
|
965
|
+
};
|
|
966
|
+
|
|
881
967
|
// src/routes/agents.ts
|
|
882
968
|
var listAgents = async (request, ctx) => {
|
|
883
969
|
const items = await ctx.client.agents.list({
|
|
@@ -1607,7 +1693,8 @@ function resolveCapabilities(capabilities) {
|
|
|
1607
1693
|
rcpSources: capabilities?.rcpSources ?? false,
|
|
1608
1694
|
auditLogs: capabilities?.auditLogs ?? false,
|
|
1609
1695
|
architect: capabilities?.architect ?? false,
|
|
1610
|
-
workflowsWrite: capabilities?.workflowsWrite ?? false
|
|
1696
|
+
workflowsWrite: capabilities?.workflowsWrite ?? false,
|
|
1697
|
+
messages: capabilities?.messages ?? false
|
|
1611
1698
|
};
|
|
1612
1699
|
}
|
|
1613
1700
|
function buildRoutes(capabilities) {
|
|
@@ -1698,6 +1785,12 @@ function buildRoutes(capabilities) {
|
|
|
1698
1785
|
handler: cancelWorkflowRun
|
|
1699
1786
|
}
|
|
1700
1787
|
];
|
|
1788
|
+
if (capabilities.messages) {
|
|
1789
|
+
routes.push(
|
|
1790
|
+
{ method: "POST", pattern: ["messages"], handler: sendMessage },
|
|
1791
|
+
{ method: "POST", pattern: ["messages", "agent"], handler: sendAgentMessage }
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1701
1794
|
if (capabilities.agentsWrite) {
|
|
1702
1795
|
routes.push(
|
|
1703
1796
|
{ method: "POST", pattern: ["agents"], handler: createAgent },
|