howone 0.1.25 → 0.1.27
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/package.json +1 -1
- package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/07-ai-action-calls.md +102 -48
- package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/03-ai-sdk-handoff.md +19 -4
- package/templates/vite/package.json +1 -1
- package/templates/vite/src/lib/sdk.ts +1 -1
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/01-architect/01-app-generation.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/01-architect/02-manifest-codegen.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/01-schema-design.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/02-schema-operations.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/03-data-access-patterns.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/04-query-dsl-and-responses.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/05-ai-persistence-patterns.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/01-client-setup.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/02-entity-operations.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/03-auth.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/04-react-integration.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/05-file-upload.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/06-raw-http.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/08-extension-boundaries.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/01-ai-capability-architecture.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/02-workflow-contract-rules.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/04-service-capability-catalog.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/05-workflow-operations.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/06-ai-feature-playbooks.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/SKILL.md +0 -0
- /package/templates/vite/.howone/skills/{howone-sdk → howone}/agents/openai.yaml +0 -0
package/package.json
CHANGED
|
@@ -62,17 +62,23 @@ type AiActionConfig<TInput, TOutput> = {
|
|
|
62
62
|
```ts
|
|
63
63
|
type AiResult = {
|
|
64
64
|
success: boolean
|
|
65
|
-
|
|
65
|
+
/** Terminal outcome of the run */
|
|
66
|
+
outcome: 'success' | 'credit_insufficient' | 'run_error' | null
|
|
67
|
+
finalResult: Record<string, unknown> | null // the workflow output payload (from run_complete)
|
|
68
|
+
/** Accumulated state data from state_update / state_snapshot events */
|
|
69
|
+
stateData: Record<string, unknown>
|
|
66
70
|
nodeExecutions: Array<{
|
|
67
71
|
nodeName: string
|
|
68
|
-
|
|
72
|
+
agentName?: string
|
|
69
73
|
timestamp: number
|
|
70
74
|
}>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
toolExecutions: Array<{
|
|
76
|
+
toolCallId: string
|
|
77
|
+
toolName: string
|
|
78
|
+
args?: Record<string, unknown>
|
|
79
|
+
result?: unknown
|
|
80
|
+
durationMs?: number
|
|
81
|
+
cost?: number
|
|
76
82
|
timestamp: number
|
|
77
83
|
}>
|
|
78
84
|
totalDuration: number
|
|
@@ -92,14 +98,43 @@ type AiSession = {
|
|
|
92
98
|
|
|
93
99
|
### AiEvent (SSE events)
|
|
94
100
|
|
|
101
|
+
All events share a common base, then carry a typed `payload`:
|
|
102
|
+
|
|
95
103
|
```ts
|
|
96
104
|
type AiEvent = {
|
|
97
|
-
type: string
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
type: string // see channel catalog below
|
|
106
|
+
id: string
|
|
107
|
+
run_id: string
|
|
108
|
+
workflow_id: string
|
|
109
|
+
timestamp: string // ISO 8601 UTC
|
|
110
|
+
seq: number // monotonic ordering within the run
|
|
111
|
+
// Context fields — present when applicable
|
|
112
|
+
node_name?: string
|
|
113
|
+
node_status?: 'pending' | 'running' | 'completed' | 'failed'
|
|
114
|
+
action_step?: number
|
|
115
|
+
agent_name?: string
|
|
116
|
+
action_name?: string
|
|
117
|
+
agent_loop_step?: number
|
|
118
|
+
message_id?: string
|
|
119
|
+
tool_call_id?: string
|
|
120
|
+
payload?: Record<string, unknown>
|
|
100
121
|
}
|
|
101
122
|
```
|
|
102
123
|
|
|
124
|
+
**SSE Channels and event types:**
|
|
125
|
+
|
|
126
|
+
| Channel | Key event types |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `lifecycle` | `run_start`, `run_complete`, `credit_insufficient`, `run_error` |
|
|
129
|
+
| `node` | `node_scheduled`, `node_start`, `node_complete`, `node_failed` |
|
|
130
|
+
| `action` | `action_scheduled`, `action_start`, `action_complete` |
|
|
131
|
+
| `messages` | `ai_message_start`, `ai_message_chunk`, `ai_message_end`, `action_output` |
|
|
132
|
+
| `tools` | `tool_call_start`, `tool_call_end`, `tool_call_error` |
|
|
133
|
+
| `state` | `state_update`, `state_snapshot` |
|
|
134
|
+
| `metadata` | `progress` |
|
|
135
|
+
|
|
136
|
+
Stream terminates after exactly one of: `run_complete`, `credit_insufficient`, or `run_error`.
|
|
137
|
+
|
|
103
138
|
---
|
|
104
139
|
|
|
105
140
|
## Defining AI Actions
|
|
@@ -195,17 +230,17 @@ When an action omits `outputSchema`, `run()` returns the raw `AiResult` executio
|
|
|
195
230
|
|
|
196
231
|
```ts
|
|
197
232
|
const result = await howone.ai.generateStory.run(input, {
|
|
198
|
-
|
|
199
|
-
console.log('chunk:',
|
|
233
|
+
onMessageChunk: (text) => {
|
|
234
|
+
console.log('chunk:', text)
|
|
200
235
|
},
|
|
201
|
-
onNodeStart: (
|
|
202
|
-
console.log(`Node ${
|
|
236
|
+
onNodeStart: (event) => {
|
|
237
|
+
console.log(`Node ${event.node_name} started`)
|
|
203
238
|
},
|
|
204
|
-
|
|
205
|
-
console.log(
|
|
239
|
+
onStateUpdate: (delta) => {
|
|
240
|
+
console.log('State delta:', delta)
|
|
206
241
|
},
|
|
207
|
-
onProgress: (
|
|
208
|
-
setProgress(
|
|
242
|
+
onProgress: (percent) => {
|
|
243
|
+
setProgress(percent)
|
|
209
244
|
},
|
|
210
245
|
onError: (error) => {
|
|
211
246
|
console.error('SSE error:', error)
|
|
@@ -237,8 +272,8 @@ try {
|
|
|
237
272
|
```ts
|
|
238
273
|
function startStream(input: GenerateStoryInput) {
|
|
239
274
|
const session = howone.ai.generateStory.stream(input, {
|
|
240
|
-
|
|
241
|
-
setOutput(prev => prev +
|
|
275
|
+
onMessageChunk: (text) => {
|
|
276
|
+
setOutput(prev => prev + text)
|
|
242
277
|
},
|
|
243
278
|
onComplete: (result) => {
|
|
244
279
|
console.log('Done:', result.finalResult)
|
|
@@ -267,17 +302,27 @@ const result = await session.result
|
|
|
267
302
|
async function consumeEvents(input: GenerateStoryInput) {
|
|
268
303
|
for await (const event of howone.ai.generateStory.events(input)) {
|
|
269
304
|
switch (event.type) {
|
|
270
|
-
case '
|
|
271
|
-
|
|
305
|
+
case 'ai_message_chunk':
|
|
306
|
+
// streaming LLM text delta
|
|
307
|
+
setOutput(prev => prev + (event.payload?.content_block?.text ?? event.payload?.content ?? ''))
|
|
272
308
|
break
|
|
273
309
|
case 'node_start':
|
|
274
|
-
console.log('Node started:', event.
|
|
310
|
+
console.log('Node started:', event.node_name)
|
|
311
|
+
break
|
|
312
|
+
case 'tool_call_end':
|
|
313
|
+
console.log('Tool result:', event.tool_call_id, event.payload?.result)
|
|
275
314
|
break
|
|
276
|
-
case '
|
|
277
|
-
console.log('
|
|
315
|
+
case 'state_update':
|
|
316
|
+
console.log('State delta:', event.payload?.delta)
|
|
278
317
|
break
|
|
279
|
-
case '
|
|
280
|
-
console.log('Final result:', event.
|
|
318
|
+
case 'run_complete':
|
|
319
|
+
console.log('Final result:', event.payload?.result)
|
|
320
|
+
break
|
|
321
|
+
case 'credit_insufficient':
|
|
322
|
+
showCreditError(event.payload?.details?.reason)
|
|
323
|
+
break
|
|
324
|
+
case 'run_error':
|
|
325
|
+
showExecutionError(event.payload?.details?.reason)
|
|
281
326
|
break
|
|
282
327
|
}
|
|
283
328
|
}
|
|
@@ -352,37 +397,43 @@ export const analyzeDataInputSchema = z.object({
|
|
|
352
397
|
|
|
353
398
|
```ts
|
|
354
399
|
type SSEExecutionOptions = {
|
|
355
|
-
// Called for every
|
|
356
|
-
onEvent?: (event:
|
|
400
|
+
// Called for every parsed event with its SSE channel
|
|
401
|
+
onEvent?: (event: AiEvent, channel: string) => void
|
|
357
402
|
|
|
358
|
-
//
|
|
359
|
-
|
|
403
|
+
// Lifecycle
|
|
404
|
+
onRunStart?: (event: RunStartEvent) => void
|
|
405
|
+
onRunComplete?: (event: RunCompleteEvent, result: AiResult) => void
|
|
406
|
+
/** Credits / quota exhausted — show top-up UI, NOT a generic error */
|
|
407
|
+
onCreditInsufficient?: (event: CreditInsufficientEvent) => void
|
|
408
|
+
/** Workflow logic failed — show retry/support UI */
|
|
409
|
+
onRunError?: (event: RunErrorEvent) => void
|
|
360
410
|
|
|
361
|
-
//
|
|
362
|
-
|
|
411
|
+
// Nodes
|
|
412
|
+
onNodeStart?: (event: NodeStartEvent) => void
|
|
413
|
+
onNodeComplete?: (event: NodeCompleteEvent) => void
|
|
363
414
|
|
|
364
|
-
//
|
|
365
|
-
|
|
415
|
+
// Messages — streaming LLM text
|
|
416
|
+
onMessageChunk?: (text: string, event: AiMessageChunkEvent) => void
|
|
417
|
+
onMessageEnd?: (event: AiMessageEndEvent) => void
|
|
366
418
|
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
cost: number
|
|
372
|
-
totalCost: number
|
|
373
|
-
timestamp: number
|
|
374
|
-
}) => void
|
|
419
|
+
// Tools
|
|
420
|
+
onToolCallStart?: (event: ToolCallStartEvent) => void
|
|
421
|
+
onToolCallEnd?: (event: ToolCallEndEvent) => void
|
|
422
|
+
onToolCallError?: (event: ToolCallErrorEvent) => void
|
|
375
423
|
|
|
376
|
-
//
|
|
377
|
-
|
|
424
|
+
// State — live output panel updates
|
|
425
|
+
onStateUpdate?: (delta: Record<string, unknown>, event: StateUpdateEvent) => void
|
|
378
426
|
|
|
379
|
-
//
|
|
427
|
+
// Progress percent 0-100
|
|
428
|
+
onProgress?: (percent: number, message?: string) => void
|
|
429
|
+
|
|
430
|
+
// Internal transport log
|
|
380
431
|
onLog?: (message: string) => void
|
|
381
432
|
|
|
382
|
-
// Called
|
|
433
|
+
// Called on any error (credit or execution)
|
|
383
434
|
onError?: (error: Error) => void
|
|
384
435
|
|
|
385
|
-
// Called when the
|
|
436
|
+
// Called when the stream closes (success or error)
|
|
386
437
|
onComplete?: (result: AiResult) => void
|
|
387
438
|
|
|
388
439
|
// Abort signal — connect to an AbortController for cancellation
|
|
@@ -397,6 +448,9 @@ type SSEExecutionOptions = {
|
|
|
397
448
|
}
|
|
398
449
|
```
|
|
399
450
|
|
|
451
|
+
> `onCreditInsufficient` and `onRunError` are **mutually exclusive** terminal events.
|
|
452
|
+
> Do not use a generic `onError` to distinguish them — use the dedicated callbacks.
|
|
453
|
+
|
|
400
454
|
---
|
|
401
455
|
|
|
402
456
|
## AiSchemaValidationError
|
|
@@ -117,8 +117,11 @@ Use `.stream()` when UI needs live output or cancellation:
|
|
|
117
117
|
|
|
118
118
|
```ts
|
|
119
119
|
const session = howone.ai.generateStory.stream(input, {
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
onMessageChunk: (text) => setDraft((prev) => prev + text),
|
|
121
|
+
onStateUpdate: (delta) => updateLivePanel(delta),
|
|
122
|
+
onProgress: (percent) => setProgress(percent),
|
|
123
|
+
onCreditInsufficient: (event) => showCreditError(event.payload?.details?.reason),
|
|
124
|
+
onRunError: (event) => showExecutionError(event.payload?.details?.reason),
|
|
122
125
|
onError: (error) => setError(error.message),
|
|
123
126
|
onComplete: (result) => setRawResult(result),
|
|
124
127
|
})
|
|
@@ -131,8 +134,20 @@ Use `.events()` when code wants an async iterable:
|
|
|
131
134
|
|
|
132
135
|
```ts
|
|
133
136
|
for await (const event of howone.ai.generateStory.events(input)) {
|
|
134
|
-
if (event.type === '
|
|
135
|
-
appendText(String(event.
|
|
137
|
+
if (event.type === 'ai_message_chunk') {
|
|
138
|
+
appendText(String(event.payload?.content_block?.text ?? event.payload?.content ?? ''))
|
|
139
|
+
}
|
|
140
|
+
if (event.type === 'state_update') {
|
|
141
|
+
updateLivePanel(event.payload?.delta ?? {})
|
|
142
|
+
}
|
|
143
|
+
if (event.type === 'run_complete') {
|
|
144
|
+
setFinalResult(event.payload?.result)
|
|
145
|
+
}
|
|
146
|
+
if (event.type === 'credit_insufficient') {
|
|
147
|
+
showCreditError(event.payload?.details?.reason)
|
|
148
|
+
}
|
|
149
|
+
if (event.type === 'run_error') {
|
|
150
|
+
showExecutionError(event.payload?.details?.reason)
|
|
136
151
|
}
|
|
137
152
|
}
|
|
138
153
|
```
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@base-ui/react": "^1.4.1",
|
|
16
16
|
"@fontsource-variable/inter": "^5.2.8",
|
|
17
|
-
"@howone/sdk": "2.0.0-beta.
|
|
17
|
+
"@howone/sdk": "2.0.0-beta.20",
|
|
18
18
|
"@tailwindcss/vite": "^4.2.1",
|
|
19
19
|
"class-variance-authority": "^0.7.1",
|
|
20
20
|
"clsx": "^2.1.1",
|
|
@@ -22,7 +22,7 @@ export const ai = defineAiActions({
|
|
|
22
22
|
// Do not paste JSON Schema objects from .howone/ai/manifest.json here directly.
|
|
23
23
|
// With outputSchema configured, howone.ai.<action>.run() returns the validated finalResult payload.
|
|
24
24
|
// generateImage: defineAiAction("generateImage", {
|
|
25
|
-
// workflowId: "<workflow-
|
|
25
|
+
// workflowId: "<workflow-config-id>", // config_id for this capability
|
|
26
26
|
// inputSchema: generateImageInputSchema,
|
|
27
27
|
// outputSchema: generateImageOutputSchema,
|
|
28
28
|
// }),
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/01-architect/01-app-generation.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/01-architect/02-manifest-codegen.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/01-schema-design.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/02-schema-operations.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/02-database/03-data-access-patterns.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/03-sdk/08-extension-boundaries.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/01-ai-capability-architecture.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/02-workflow-contract-rules.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/04-service-capability-catalog.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/05-workflow-operations.md
RENAMED
|
File without changes
|
/package/templates/vite/.howone/skills/{howone-sdk → howone}/04-ai/06-ai-feature-playbooks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|