weifuwu 0.10.0 → 0.12.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 +163 -134
- package/dist/agent/run.d.ts +1 -1
- package/dist/agent/types.d.ts +2 -2
- package/dist/ai/workflow.d.ts +14 -0
- package/dist/ai.d.ts +5 -17
- package/dist/deploy/types.d.ts +1 -1
- package/dist/graphql.d.ts +3 -1
- package/dist/health.d.ts +6 -0
- package/dist/i18n.d.ts +6 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +947 -840
- package/dist/mailer.d.ts +20 -0
- package/dist/opencode/rest.d.ts +1 -1
- package/dist/opencode/run.d.ts +1 -1
- package/dist/opencode/tools/index.d.ts +1 -1
- package/dist/opencode/ws.d.ts +1 -1
- package/dist/postgres/schema/columns.d.ts +1 -0
- package/dist/postgres/schema/index.d.ts +2 -2
- package/dist/postgres/schema/table.d.ts +27 -0
- package/dist/postgres/types.d.ts +4 -0
- package/dist/serve.d.ts +4 -0
- package/dist/types.d.ts +2 -0
- package/dist/user/oauth2.d.ts +2 -1
- package/dist/vendor.d.ts +0 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
weifuwu doesn't invent its own request/response abstraction. `Request` and `Response` are the same objects you use in `fetch()` — what you learn in the browser applies directly on the server. `ctx` is the only framework object, and it only carries what the router parsed for you (`params`, `query`).
|
|
8
8
|
|
|
9
|
-
Everything follows the same `(req, ctx) => Response` contract. The Router handles HTTP routing and WebSocket. All other features — auth, validation, database, GraphQL, AI
|
|
9
|
+
Everything follows the same `(req, ctx) => Response` contract. The Router handles HTTP routing and WebSocket. All other features — auth, validation, database, GraphQL, AI — are standalone modules you import and mount with `app.use()`.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
@@ -17,9 +17,9 @@ Everything follows the same `(req, ctx) => Response` contract. The Router handle
|
|
|
17
17
|
- **React SSR + Hydration** — `tsx({ dir })` — page.tsx / load.ts / layout.tsx / route.ts / not-found.tsx
|
|
18
18
|
- **WebSocket** — `router.ws()` with upgrade middleware (auth before connect)
|
|
19
19
|
- **GraphQL** — `graphql(handler)` sub-Router with GraphiQL IDE
|
|
20
|
-
- **AI streaming** — `
|
|
21
|
-
- **
|
|
22
|
-
- **AI Agent** — `agent()` — server-side AI agents with chat/
|
|
20
|
+
- **AI streaming** — `aiStream(handler)` sub-Router via Vercel AI SDK
|
|
21
|
+
- **DAG workflow tool** — `runWorkflow()` — multi-step execution engine as a single AI SDK `Tool`
|
|
22
|
+
- **AI Agent** — `agent()` — server-side AI agents with chat/tool-use/knowledge types, OpenAI-compatible, Ollama-ready
|
|
23
23
|
- **Messaging** — `messager()` — real-time chat with channels, WebSocket, agent routing, webhook support
|
|
24
24
|
- **Tenant BaaS** — `tenant()` — multi-tenant dynamic tables, auto REST + GraphQL, row-level isolation, pgvector/HNSW
|
|
25
25
|
- **Redis** — `redis()` — ioredis client, `ctx.redis`, middleware
|
|
@@ -278,6 +278,50 @@ await users.createIndex('embedding', { // pgvector HNSW
|
|
|
278
278
|
await users.drop({ cascade: true })
|
|
279
279
|
```
|
|
280
280
|
|
|
281
|
+
### Type-safe CRUD with BoundTable
|
|
282
|
+
|
|
283
|
+
Two usage paths — use `pg.table()` when you have a `pg` handle, or `pgTable()` with explicit `sql`:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
// pg.table() — auto-binds sql, no need to pass it
|
|
287
|
+
const users = pg.table('_users', {
|
|
288
|
+
id: serial('id').primaryKey(),
|
|
289
|
+
name: text('name').notNull(),
|
|
290
|
+
email: text('email').unique(),
|
|
291
|
+
active: boolean('active').default(true),
|
|
292
|
+
createdAt: timestamptz('created_at').default(sql`NOW()`),
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
// INSERT ... RETURNING * — auto-strips serial id
|
|
296
|
+
const user = await users.insert({ name: 'Alice', email: 'alice@test.com' })
|
|
297
|
+
// → { id: 1, name: 'Alice', email: 'alice@test.com', active: true, ... }
|
|
298
|
+
|
|
299
|
+
// SELECT ... WHERE id = ? LIMIT 1
|
|
300
|
+
const found = await users.findById(1)
|
|
301
|
+
|
|
302
|
+
// SELECT ... WHERE ... [ORDER BY ...] [LIMIT ...] [OFFSET ...]
|
|
303
|
+
const admins = await users.find({ role: 'admin' })
|
|
304
|
+
const sorted = await users.find({ active: true }, { orderBy: { name: 'asc' } })
|
|
305
|
+
const page = await users.find(undefined, { limit: 10, offset: 0 })
|
|
306
|
+
const filtered = await users.find({ role: 'admin' }, { orderBy: { name: 'desc' }, limit: 5 })
|
|
307
|
+
|
|
308
|
+
// UPDATE ... SET ... WHERE ... RETURNING *
|
|
309
|
+
const updated = await users.update({ id: 1 }, { name: 'Bob' })
|
|
310
|
+
// With SQL expressions:
|
|
311
|
+
await users.update({ id: 1 }, { name: 'Bob', updated_at: sql`NOW()` })
|
|
312
|
+
|
|
313
|
+
// DELETE ... WHERE ... RETURNING 1
|
|
314
|
+
const ok = await users.delete({ id: 1 })
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
When using `pgTable()` directly (without `pg`), pass `sql` as the first argument:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
const t = pgTable('_users', { ... })
|
|
321
|
+
await t.insert(ctx.sql, { name: 'Alice' })
|
|
322
|
+
await t.find(ctx.sql, { role: 'admin' }, { orderBy: { name: 'asc' } })
|
|
323
|
+
```
|
|
324
|
+
|
|
281
325
|
### Complex queries use raw SQL
|
|
282
326
|
|
|
283
327
|
```ts
|
|
@@ -690,7 +734,7 @@ await fetch('http://localhost/api/sys/tenants/invite', {
|
|
|
690
734
|
|
|
691
735
|
## AI Agent
|
|
692
736
|
|
|
693
|
-
Server-side AI agents with OpenAI-compatible API. Built-in chat,
|
|
737
|
+
Server-side AI agents with OpenAI-compatible API. Built-in chat, tool-use (tool-calling), and knowledge (RAG) types. Works out of the box with Ollama or any OpenAI-compatible provider.
|
|
694
738
|
|
|
695
739
|
```ts
|
|
696
740
|
import { agent } from 'weifuwu'
|
|
@@ -704,7 +748,7 @@ app.use('/api', agents.router())
|
|
|
704
748
|
| Type | Description | Execution |
|
|
705
749
|
|------|-------------|-----------|
|
|
706
750
|
| `chat` | Pure conversation | `streamText()` / `generateText()` |
|
|
707
|
-
| `
|
|
751
|
+
| `tool-use` | Tool-calling agent | `streamText({ tools })` |
|
|
708
752
|
|
|
709
753
|
### Knowledge (RAG)
|
|
710
754
|
|
|
@@ -807,7 +851,7 @@ GraphQL endpoint with GraphiQL IDE. Mount as a sub-Router:
|
|
|
807
851
|
import { serve, Router, graphql } from 'weifuwu'
|
|
808
852
|
|
|
809
853
|
const app = new Router()
|
|
810
|
-
|
|
854
|
+
const gql = graphql(() => ({
|
|
811
855
|
schema: `
|
|
812
856
|
type Query { hello: String }
|
|
813
857
|
type Mutation { setMessage(msg: String!): String }
|
|
@@ -817,7 +861,8 @@ app.use('/graphql', graphql(() => ({
|
|
|
817
861
|
Mutation: { setMessage: (_, { msg }) => msg },
|
|
818
862
|
},
|
|
819
863
|
graphiql: true,
|
|
820
|
-
}))
|
|
864
|
+
}))
|
|
865
|
+
app.use('/graphql', gql.router())
|
|
821
866
|
|
|
822
867
|
serve(app.handler(), { port: 3000 })
|
|
823
868
|
```
|
|
@@ -829,30 +874,31 @@ The handler receives `(req, ctx)` so you can customize the schema based on the r
|
|
|
829
874
|
Server-sent event streaming via the Vercel AI SDK:
|
|
830
875
|
|
|
831
876
|
```ts
|
|
832
|
-
import { serve, Router,
|
|
877
|
+
import { serve, Router, aiStream } from 'weifuwu'
|
|
833
878
|
import { openai } from '@ai-sdk/openai'
|
|
834
879
|
|
|
835
880
|
const app = new Router()
|
|
836
|
-
|
|
881
|
+
const chat = await aiStream(async (req, ctx) => {
|
|
837
882
|
const { messages } = await req.json()
|
|
838
883
|
return { model: openai('gpt-4o'), messages }
|
|
839
|
-
})
|
|
884
|
+
})
|
|
885
|
+
app.use('/chat', chat.router())
|
|
840
886
|
|
|
841
887
|
serve(app.handler(), { port: 3000 })
|
|
842
888
|
```
|
|
843
889
|
|
|
844
|
-
##
|
|
890
|
+
## runWorkflow
|
|
845
891
|
|
|
846
|
-
|
|
892
|
+
Multi-step DAG execution engine — packaged as a single AI SDK `Tool`. Use it with `streamText()` or `generateText()` when the LLM needs conditional logic, loops, or multi-step tool orchestration.
|
|
847
893
|
|
|
848
894
|
```ts
|
|
849
|
-
import {
|
|
895
|
+
import { tool, streamText } from 'ai'
|
|
896
|
+
import { runWorkflow } from 'weifuwu'
|
|
850
897
|
import { z } from 'zod'
|
|
851
898
|
|
|
852
|
-
// 1. Define tools (business capabilities)
|
|
853
899
|
const tools = {
|
|
854
900
|
queryUser: tool({
|
|
855
|
-
description: 'Query user info
|
|
901
|
+
description: 'Query user info',
|
|
856
902
|
inputSchema: z.object({ userId: z.string() }),
|
|
857
903
|
execute: async ({ userId }) => ({ id: userId, email: 'user@test.com', name: 'Test' }),
|
|
858
904
|
}),
|
|
@@ -861,139 +907,57 @@ const tools = {
|
|
|
861
907
|
inputSchema: z.object({ to: z.string(), subject: z.string() }),
|
|
862
908
|
execute: async ({ to, subject }) => ({ sent: true }),
|
|
863
909
|
}),
|
|
910
|
+
runWF: runWorkflow({ tools: { queryUser, sendEmail } }),
|
|
864
911
|
}
|
|
865
912
|
|
|
866
|
-
//
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
// POST /agent { nodes: [...] } → 200 { workflow: {...}, result: ... }
|
|
870
|
-
|
|
871
|
-
// With SSE streaming:
|
|
872
|
-
app.use('/agent-stream', workflow(() => ({ tools, stream: true })))
|
|
873
|
-
// POST /agent-stream { nodes: [...] }
|
|
874
|
-
// → 200 { workflowId: "xxx", eventsUrl: "/xxx/events" }
|
|
875
|
-
// GET /agent-stream/:workflowId/events
|
|
876
|
-
// → SSE: workflow-start → node-start → node-end → complete
|
|
877
|
-
|
|
878
|
-
// With LLM model (generates workflow from goal):
|
|
879
|
-
app.use('/agent-llm', workflow(() => ({
|
|
913
|
+
// Use in any streamText call — the LLM can decide when to trigger a workflow
|
|
914
|
+
const result = await streamText({
|
|
915
|
+
model,
|
|
880
916
|
tools,
|
|
881
|
-
|
|
882
|
-
})))
|
|
883
|
-
// POST /agent-llm { goal: "给用户123发欢迎邮件" }
|
|
884
|
-
// ← LLM generates → executes → returns result
|
|
885
|
-
```
|
|
886
|
-
|
|
887
|
-
### Tool
|
|
888
|
-
|
|
889
|
-
```ts
|
|
890
|
-
import { tool } from 'weifuwu'
|
|
891
|
-
import { z } from 'zod'
|
|
892
|
-
|
|
893
|
-
const myTool = tool({
|
|
894
|
-
description: '做什么的,返回什么',
|
|
895
|
-
inputSchema: z.object({ key: z.string() }),
|
|
896
|
-
execute: async (input, ctx) => {
|
|
897
|
-
return { result: input.key }
|
|
898
|
-
},
|
|
899
|
-
})
|
|
900
|
-
```
|
|
901
|
-
|
|
902
|
-
`ctx.onStream` 用于流式推送(如 LLM token 输出):
|
|
903
|
-
|
|
904
|
-
```ts
|
|
905
|
-
const llmTool = tool({
|
|
906
|
-
description: '生成文本',
|
|
907
|
-
inputSchema: z.object({ prompt: z.string() }),
|
|
908
|
-
execute: async (input, ctx) => {
|
|
909
|
-
const stream = await openai.chat.completions.create({ ... })
|
|
910
|
-
let full = ''
|
|
911
|
-
for await (const chunk of stream) {
|
|
912
|
-
full += chunk.choices[0]?.delta?.content || ''
|
|
913
|
-
ctx.onStream?.({ type: 'llm-stream', chunk, accumulated: full })
|
|
914
|
-
}
|
|
915
|
-
return { text: full }
|
|
916
|
-
},
|
|
917
|
+
messages: [{ role: 'user', content: '查询用户123,如果存在则发送欢迎邮件' }],
|
|
917
918
|
})
|
|
918
919
|
```
|
|
919
920
|
|
|
920
|
-
###
|
|
921
|
+
### Node types
|
|
921
922
|
|
|
922
|
-
7 built-in node types:
|
|
923
|
+
7 built-in node types for defining the execution graph:
|
|
923
924
|
|
|
924
925
|
| Node | Purpose | Input |
|
|
925
926
|
|------|---------|-------|
|
|
926
|
-
| `call` | Call a
|
|
927
|
-
| `set` |
|
|
927
|
+
| `call` | Call a registered AI SDK Tool | `{ tool: "name", args: {...} }` |
|
|
928
|
+
| `set` | Assign a variable | `{ name: "x", value: 42 }` |
|
|
928
929
|
| `get` | Read a variable | `{ name: "x" }` |
|
|
929
930
|
| `eval` | Evaluate an expression | `{ expression: "$var.x + 1" }` |
|
|
930
931
|
| `if` | Conditional branch | `{ conditions: [{ test: ..., body: [nodes] }] }` |
|
|
931
932
|
| `while` | Loop | `{ condition: "$var.i < 5" }, body: [nodes]` |
|
|
932
933
|
| `http` | HTTP request | `{ url: "https://...", method: "GET" }` |
|
|
933
934
|
|
|
934
|
-
###
|
|
935
|
+
### Reference syntax
|
|
935
936
|
|
|
936
937
|
| Pattern | Meaning | Example |
|
|
937
938
|
|---------|---------|---------|
|
|
938
939
|
| `$var.x` | Variable `x` | `$var.counter` |
|
|
939
940
|
| `$nodes.u.output` | Full output of node `u` | `$nodes.u.output` |
|
|
940
941
|
| `$nodes.u.output.field` | Specific field | `$nodes.u.output.email` |
|
|
941
|
-
| `$input.userId` |
|
|
942
|
-
| `42`, `true`, `"hello"` | Literal values | Passed as-is |
|
|
943
|
-
|
|
944
|
-
### Engine API
|
|
945
|
-
|
|
946
|
-
For programmatic use outside of Router:
|
|
947
|
-
|
|
948
|
-
```ts
|
|
949
|
-
import { createWorkflowEngine, createSSEManager } from 'weifuwu'
|
|
950
|
-
|
|
951
|
-
const sse = createSSEManager()
|
|
952
|
-
const engine = createWorkflowEngine({ tools, sseManager: sse })
|
|
953
|
-
|
|
954
|
-
// Sync execution
|
|
955
|
-
const result = await engine.execute({ nodes: [...] })
|
|
942
|
+
| `$input.userId` | Input param | `$input.userId` |
|
|
956
943
|
|
|
957
|
-
|
|
958
|
-
engine.runAsync('wf-1', { nodes: [...] })
|
|
959
|
-
```
|
|
944
|
+
### LLM generation
|
|
960
945
|
|
|
961
|
-
|
|
946
|
+
Pass a `model` to `runWorkflow` — the LLM generates the workflow JSON from a goal:
|
|
962
947
|
|
|
963
948
|
```ts
|
|
964
|
-
const
|
|
965
|
-
|
|
949
|
+
const runWF = runWorkflow({
|
|
950
|
+
tools: { queryUser, sendEmail },
|
|
951
|
+
model: openai('gpt-4o'),
|
|
952
|
+
})
|
|
966
953
|
|
|
967
|
-
const
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
// event: llm-stream — { nodeId, chunk, accumulated }
|
|
972
|
-
// event: complete — { result, duration }
|
|
973
|
-
// event: error — { error }
|
|
954
|
+
const result = await streamText({
|
|
955
|
+
model,
|
|
956
|
+
tools: { runWF },
|
|
957
|
+
})
|
|
974
958
|
```
|
|
975
959
|
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
Define reusable sub-workflows in the `functions` field:
|
|
979
|
-
|
|
980
|
-
```json
|
|
981
|
-
{
|
|
982
|
-
"functions": {
|
|
983
|
-
"double": {
|
|
984
|
-
"inputSchema": { "type": "object", "properties": { "x": { "type": "number" } } },
|
|
985
|
-
"workflow": {
|
|
986
|
-
"nodes": [
|
|
987
|
-
{ "id": "calc", "tool": "eval", "input": { "expression": "$input.x * 2" } }
|
|
988
|
-
]
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
},
|
|
992
|
-
"nodes": [
|
|
993
|
-
{ "id": "call_double", "tool": "call", "input": { "function": "double", "args": { "x": 21 } } }
|
|
994
|
-
]
|
|
995
|
-
}
|
|
996
|
-
```
|
|
960
|
+
The LLM calls `runWF` with a goal, and `runWorkflow` internally calls `generateText` to produce the workflow nodes, then executes them.
|
|
997
961
|
|
|
998
962
|
## React pages with tsx()
|
|
999
963
|
|
|
@@ -1191,17 +1155,81 @@ export default function NotFound() {
|
|
|
1191
1155
|
}
|
|
1192
1156
|
```
|
|
1193
1157
|
|
|
1158
|
+
## Health check
|
|
1159
|
+
|
|
1160
|
+
```ts
|
|
1161
|
+
import { serve, Router, health } from 'weifuwu'
|
|
1162
|
+
|
|
1163
|
+
const app = new Router()
|
|
1164
|
+
app.use(health()) // GET /health → 200
|
|
1165
|
+
app.use(health({ path: '/healthz' })) // custom path
|
|
1166
|
+
app.use(health({
|
|
1167
|
+
check: async () => { await db.sql`SELECT 1` }, // fail → 503
|
|
1168
|
+
}))
|
|
1169
|
+
serve(app.handler(), { port: 3000 })
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
Returns a `Router` — mount with `app.use()`.
|
|
1173
|
+
|
|
1174
|
+
## Internationalization
|
|
1175
|
+
|
|
1176
|
+
```ts
|
|
1177
|
+
import { i18n } from 'weifuwu'
|
|
1178
|
+
|
|
1179
|
+
app.use(i18n({ dir: './locales', defaultLocale: 'en' }))
|
|
1180
|
+
|
|
1181
|
+
// In any handler after i18n middleware:
|
|
1182
|
+
app.get('/hello', (req, ctx) => {
|
|
1183
|
+
const msg = ctx.t('greeting', { name: 'World' })
|
|
1184
|
+
return Response.json({ message: msg, locale: ctx.locale })
|
|
1185
|
+
})
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
Locale detection: `Cookie: locale=zh` → `Accept-Language: zh-CN` → `defaultLocale`.
|
|
1189
|
+
|
|
1190
|
+
## Email
|
|
1191
|
+
|
|
1192
|
+
```ts
|
|
1193
|
+
import { mailer } from 'weifuwu'
|
|
1194
|
+
|
|
1195
|
+
// SMTP transport
|
|
1196
|
+
const mail = mailer({
|
|
1197
|
+
transport: 'smtp://user:pass@smtp.example.com',
|
|
1198
|
+
from: 'noreply@example.com',
|
|
1199
|
+
})
|
|
1200
|
+
await mail.send({ to: 'user@example.com', subject: 'Welcome', html: '<h1>Hi!</h1>' })
|
|
1201
|
+
await mail.close()
|
|
1202
|
+
|
|
1203
|
+
// Custom transport (Resend, SES, SendGrid, etc.)
|
|
1204
|
+
const mail2 = mailer({
|
|
1205
|
+
send: async (msg) => { await resend.emails.send(msg) },
|
|
1206
|
+
})
|
|
1207
|
+
await mail2.send({ to: 'user@example.com', subject: 'Hi', text: 'Hello' })
|
|
1208
|
+
await mail2.close()
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
## Test utilities
|
|
1212
|
+
|
|
1213
|
+
```ts
|
|
1214
|
+
import { createTestServer } from 'weifuwu'
|
|
1215
|
+
|
|
1216
|
+
const { server, url } = await createTestServer(app.handler())
|
|
1217
|
+
const res = await fetch(`${url}/api/users`)
|
|
1218
|
+
assert.equal(res.status, 200)
|
|
1219
|
+
server.stop()
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1194
1222
|
## Usage within a full app
|
|
1195
1223
|
|
|
1196
1224
|
```ts
|
|
1197
|
-
import { serve, Router,
|
|
1198
|
-
import { tsx } from 'weifuwu/tsx'
|
|
1225
|
+
import { serve, Router, aiStream, graphql } from 'weifuwu'
|
|
1199
1226
|
|
|
1200
1227
|
const app = new Router()
|
|
1201
1228
|
app.use('/', await tsx({ dir: './pages/' }))
|
|
1202
|
-
|
|
1203
|
-
app.use('/
|
|
1204
|
-
|
|
1229
|
+
const chat = await aiStream(async (req) => ({ model: openai('gpt-4o'), messages: (await req.json()).messages }))
|
|
1230
|
+
app.use('/chat', chat.router())
|
|
1231
|
+
const gql = graphql(() => ({ schema: `type Query { hello: String }`, resolvers: { Query: { hello: () => 'world' } } }))
|
|
1232
|
+
app.use('/graphql', gql.router())
|
|
1205
1233
|
app.ws('/chat', { message(ws, _, data) { ws.send(data) } })
|
|
1206
1234
|
|
|
1207
1235
|
serve(app.handler(), { websocket: app.websocketHandler() })
|
|
@@ -1334,7 +1362,7 @@ Returns `TenantModule` — `{ migrate, middleware, router, graphql, close }`.
|
|
|
1334
1362
|
| `model` | env `OPENAI_MODEL` → Ollama | `LanguageModel` from ai SDK |
|
|
1335
1363
|
| `embeddingModel` | env `OPENAI_EMBEDDING_MODEL` → Ollama | `EmbeddingModel` for knowledge RAG |
|
|
1336
1364
|
| `embeddingDimension` | `1024` | Vector dimension for pgvector |
|
|
1337
|
-
| `tools` | — | Tools for
|
|
1365
|
+
| `tools` | — | Tools for tool-use agents (ai SDK `Tool` objects) |
|
|
1338
1366
|
|
|
1339
1367
|
Returns `AgentModule` — `{ migrate, router, run, addKnowledge, close }`.
|
|
1340
1368
|
|
|
@@ -1418,12 +1446,12 @@ serve(app.handler(), { websocket: app.websocketHandler() })
|
|
|
1418
1446
|
| `queue(options?)` | Redis-backed job queue — immediate, delayed, cron scheduling |
|
|
1419
1447
|
| `user(options)` | Built-in authentication (password + OAuth2 Server + JWT, middleware) |
|
|
1420
1448
|
| `tenant(options)` | Multi-tenant BaaS — dynamic tables, REST + GraphQL auto-generation, row-level isolation |
|
|
1421
|
-
| `agent(options)` | AI Agent — chat/
|
|
1449
|
+
| `agent(options)` | AI Agent — chat/tool-use/knowledge, Ollama-ready, programmatic API |
|
|
1422
1450
|
| `messager(options)` | Real-time messaging — channels, WebSocket, agent routing, webhooks |
|
|
1423
1451
|
| `opencode(options)` | AI programming assistant — chat agents with tools, skills, permissions, isolated workspaces |
|
|
1424
1452
|
| `graphql(handler)` | GraphQL endpoint (GET/POST + GraphiQL) |
|
|
1425
|
-
| `
|
|
1426
|
-
| `
|
|
1453
|
+
| `aiStream(handler)` | AI streaming endpoint (POST) |
|
|
1454
|
+
| `runWorkflow(options)` | DAG execution engine as an AI SDK `Tool` — use with `streamText()` |
|
|
1427
1455
|
|
|
1428
1456
|
### Deploy
|
|
1429
1457
|
|
|
@@ -1441,13 +1469,14 @@ serve(app.handler(), { websocket: app.websocketHandler() })
|
|
|
1441
1469
|
| `setCookie(res, name, value, options?)` | Set cookie (returns new Response) |
|
|
1442
1470
|
| `deleteCookie(res, name)` | Delete cookie (returns new Response) |
|
|
1443
1471
|
| `useTsx()` | Hook returning `{ params, query, user, parsed }` from `TsxContext` |
|
|
1444
|
-
| `
|
|
1445
|
-
| `
|
|
1446
|
-
| `
|
|
1447
|
-
| `pgTable(name, columns)` | Type-safe table schema definition with DDL generation |
|
|
1472
|
+
| `runWorkflow(options)` | Create a DAG execution AI SDK `Tool` — `{ tools?, model?, maxSteps? }` |
|
|
1473
|
+
| `pgTable(name, columns)` | Type-safe table schema definition with DDL + CRUD |
|
|
1474
|
+
| `pg.table(name, columns)` | Pre-bound table (no `sql` parameter needed for CRUD) |
|
|
1448
1475
|
| `serial()`, `uuid()`, `text()`, `integer()`, `boolean()`, `timestamptz()`, `jsonb()`, `textArray()`, `vector()` | Column type builders |
|
|
1449
|
-
| `sql(strings, ...)` | SQL expression literal for
|
|
1476
|
+
| `sql(strings, ...)` | SQL expression literal for defaults and SET values (e.g. `sql\`NOW()\``) |
|
|
1450
1477
|
| `PgModule` | Base class for database-backed modules (provides `sql`, `close()`) |
|
|
1478
|
+
| `BoundTable` | Table with pre-bound `sql` — returned by `pg.table()` |
|
|
1479
|
+
| `FindOptions` | Query options: `{ orderBy?, limit?, offset? }` for `find()` |
|
|
1451
1480
|
|
|
1452
1481
|
Import `useTsx` and `TsxContext` from `'weifuwu'`.
|
|
1453
1482
|
|
package/dist/agent/run.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type LanguageModel, type EmbeddingModel, type Tool } from 'ai';
|
|
2
2
|
import type { Sql } from '../vendor.ts';
|
|
3
3
|
import type { RunParams, RunResult, KnowledgeDoc } from './types.ts';
|
|
4
4
|
interface RunnerDeps {
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { LanguageModel, EmbeddingModel, Tool } from '
|
|
1
|
+
import type { LanguageModel, EmbeddingModel, Tool } from 'ai';
|
|
2
2
|
export interface AgentConfig {
|
|
3
3
|
id: number;
|
|
4
4
|
tenant_id: string | null;
|
|
5
5
|
name: string;
|
|
6
6
|
description: string;
|
|
7
|
-
type: 'chat' | '
|
|
7
|
+
type: 'chat' | 'tool-use';
|
|
8
8
|
model: string;
|
|
9
9
|
system_prompt: string;
|
|
10
10
|
owner_id: number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LanguageModel } from 'ai';
|
|
2
|
+
export declare function runWorkflow(opts?: {
|
|
3
|
+
tools?: Record<string, any>;
|
|
4
|
+
model?: LanguageModel;
|
|
5
|
+
maxSteps?: number;
|
|
6
|
+
}): import("ai").Tool<{
|
|
7
|
+
goal: string;
|
|
8
|
+
nodes?: any[];
|
|
9
|
+
}, {
|
|
10
|
+
result: unknown;
|
|
11
|
+
nodeOutputs: {
|
|
12
|
+
[k: string]: unknown;
|
|
13
|
+
};
|
|
14
|
+
}>;
|
package/dist/ai.d.ts
CHANGED
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
import type { Context } from './types.ts';
|
|
2
2
|
import { Router } from './router.ts';
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
maxTokens?: number;
|
|
9
|
-
temperature?: number;
|
|
10
|
-
[key: string]: unknown;
|
|
11
|
-
};
|
|
12
|
-
export type AIHandler = (req: Request, ctx: Context) => StreamTextParams | Promise<StreamTextParams>;
|
|
13
|
-
export declare const _ai: {
|
|
14
|
-
streamText: (params: StreamTextParams) => {
|
|
15
|
-
toTextStreamResponse: () => Response;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
export declare function ai(handler: AIHandler): Promise<Router>;
|
|
19
|
-
export {};
|
|
3
|
+
export type AIHandler = (req: Request, ctx: Context) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
4
|
+
export declare const _ai: Record<string, any>;
|
|
5
|
+
export declare function aiStream(handler: AIHandler): Promise<{
|
|
6
|
+
router(): Router;
|
|
7
|
+
}>;
|
package/dist/deploy/types.d.ts
CHANGED
package/dist/graphql.d.ts
CHANGED
|
@@ -9,4 +9,6 @@ export interface GraphQLOptions {
|
|
|
9
9
|
graphiql?: boolean;
|
|
10
10
|
}
|
|
11
11
|
export type GraphQLHandler = (req: Request, ctx: Context) => GraphQLOptions | Promise<GraphQLOptions>;
|
|
12
|
-
export declare function graphql(handler: GraphQLHandler):
|
|
12
|
+
export declare function graphql(handler: GraphQLHandler): {
|
|
13
|
+
router(): Router;
|
|
14
|
+
};
|
package/dist/health.d.ts
ADDED
package/dist/i18n.d.ts
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { Context, Handler, Middleware, ErrorHandler } from './types.ts';
|
|
2
|
-
export { serve } from './serve.ts';
|
|
2
|
+
export { serve, createTestServer } from './serve.ts';
|
|
3
3
|
export type { ServeOptions, Server } from './serve.ts';
|
|
4
4
|
export { Router } from './router.ts';
|
|
5
5
|
export type { WebSocketHandler } from './router.ts';
|
|
@@ -21,10 +21,9 @@ export { compress } from './compress.ts';
|
|
|
21
21
|
export type { CompressOptions } from './compress.ts';
|
|
22
22
|
export { graphql } from './graphql.ts';
|
|
23
23
|
export type { GraphQLOptions, GraphQLHandler } from './graphql.ts';
|
|
24
|
-
export {
|
|
24
|
+
export { aiStream } from './ai.ts';
|
|
25
25
|
export type { AIHandler } from './ai.ts';
|
|
26
|
-
export {
|
|
27
|
-
export type { Tool, Workflow, WorkflowEngine, WorkflowState, SSEEvent, WorkflowOptions, WorkflowHandler } from './workflow/index.ts';
|
|
26
|
+
export { runWorkflow } from './ai/workflow.ts';
|
|
28
27
|
export { postgres } from './postgres/index.ts';
|
|
29
28
|
export type { PostgresOptions, PostgresClient } from './postgres/types.ts';
|
|
30
29
|
export { user } from './user/index.ts';
|
|
@@ -43,3 +42,9 @@ export { deploy, defineConfig } from './deploy/index.ts';
|
|
|
43
42
|
export type { DeployConfig, AppConfig, DeployServer, AppStatus } from './deploy/types.ts';
|
|
44
43
|
export { opencode } from './opencode/index.ts';
|
|
45
44
|
export type { OpencodeOptions, OpencodeModule, SkillDef, OpencodePermissions, Session as OpencodeSession } from './opencode/types.ts';
|
|
45
|
+
export { health } from './health.ts';
|
|
46
|
+
export type { HealthOptions } from './health.ts';
|
|
47
|
+
export { i18n } from './i18n.ts';
|
|
48
|
+
export type { I18nOptions } from './i18n.ts';
|
|
49
|
+
export { mailer } from './mailer.ts';
|
|
50
|
+
export type { MailerOptions, MailOptions, Mailer } from './mailer.ts';
|