veryfront 0.1.364 → 0.1.366

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-request-protocol.d.ts","sourceRoot":"","sources":["../../../src/src/agent/input-request-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ import { z } from "zod";
2
+ import { HumanInputFieldSchema, HumanInputRequestSchema } from "./human-input.js";
3
+ export const formInputToolInputSchema = HumanInputRequestSchema.omit({ metadata: true });
4
+ export const inputResponseValuesSchema = z.record(z.string(), z.union([z.string(), z.boolean(), z.number(), z.null()]));
5
+ export const createInputRequestRequestSchema = z.object({
6
+ run_id: z.string().min(1),
7
+ tool_call_id: z.string().min(1),
8
+ kind: z.literal("form"),
9
+ requested_responder_type: z.literal("human"),
10
+ title: z.string(),
11
+ description: z.string().optional(),
12
+ fields: z.array(HumanInputFieldSchema).min(1),
13
+ expires_at: z.string().datetime({ offset: true }),
14
+ metadata: z.record(z.string(), z.unknown()).optional(),
15
+ });
16
+ export const inputResponseRestSchema = z
17
+ .object({
18
+ id: z.string().uuid(),
19
+ input_request_id: z.string().uuid(),
20
+ conversation_id: z.string().uuid(),
21
+ run_id: z.string().min(1),
22
+ actor_type: z.string(),
23
+ actor_id: z.string(),
24
+ values: inputResponseValuesSchema,
25
+ created_at: z.string(),
26
+ })
27
+ .passthrough()
28
+ .transform((value) => ({
29
+ id: value.id,
30
+ inputRequestId: value.input_request_id,
31
+ conversationId: value.conversation_id,
32
+ runId: value.run_id,
33
+ actorType: value.actor_type,
34
+ actorId: value.actor_id,
35
+ values: value.values,
36
+ createdAt: value.created_at,
37
+ }));
38
+ export const inputRequestRestSchema = z
39
+ .object({
40
+ id: z.string().uuid(),
41
+ conversation_id: z.string().uuid(),
42
+ run_id: z.string().min(1),
43
+ tool_call_id: z.string().min(1),
44
+ kind: z.literal("form"),
45
+ status: z.enum(["open", "submitted", "cancelled", "expired"]),
46
+ requested_responder_type: z.enum(["human", "agent", "system"]),
47
+ title: z.string(),
48
+ description: z.string().nullable(),
49
+ fields: z.array(HumanInputFieldSchema),
50
+ recommendations: z.record(z.string(), z.unknown()).nullable().optional(),
51
+ metadata: z.record(z.string(), z.unknown()).nullable().optional(),
52
+ created_at: z.string(),
53
+ expires_at: z.string().nullable(),
54
+ submitted_at: z.string().nullable().optional(),
55
+ cancelled_at: z.string().nullable().optional(),
56
+ expired_at: z.string().nullable().optional(),
57
+ latest_response: inputResponseRestSchema.nullable().optional(),
58
+ })
59
+ .passthrough()
60
+ .transform((value) => ({
61
+ id: value.id,
62
+ conversationId: value.conversation_id,
63
+ runId: value.run_id,
64
+ toolCallId: value.tool_call_id,
65
+ kind: value.kind,
66
+ status: value.status,
67
+ requestedResponderType: value.requested_responder_type,
68
+ title: value.title,
69
+ description: value.description,
70
+ fields: value.fields,
71
+ recommendations: value.recommendations ?? null,
72
+ metadata: value.metadata ?? null,
73
+ createdAt: value.created_at,
74
+ expiresAt: value.expires_at,
75
+ submittedAt: value.submitted_at ?? null,
76
+ cancelledAt: value.cancelled_at ?? null,
77
+ expiredAt: value.expired_at ?? null,
78
+ latestResponse: value.latest_response ?? null,
79
+ }));
80
+ export const createInputRequestResponseSchema = inputRequestRestSchema;
81
+ export const getInputRequestResponseSchema = inputRequestRestSchema;
82
+ export const inputRequestOutputSchema = z.object({
83
+ id: z.string().uuid(),
84
+ conversationId: z.string().uuid(),
85
+ runId: z.string().min(1),
86
+ toolCallId: z.string().min(1),
87
+ kind: z.literal("form"),
88
+ status: z.enum(["open", "submitted", "cancelled", "expired"]),
89
+ requestedResponderType: z.enum(["human", "agent", "system"]),
90
+ title: z.string(),
91
+ description: z.string().nullable(),
92
+ fields: z.array(HumanInputFieldSchema),
93
+ recommendations: z.record(z.string(), z.unknown()).nullable(),
94
+ metadata: z.record(z.string(), z.unknown()).nullable(),
95
+ createdAt: z.string(),
96
+ expiresAt: z.string().nullable(),
97
+ submittedAt: z.string().nullable(),
98
+ cancelledAt: z.string().nullable(),
99
+ expiredAt: z.string().nullable(),
100
+ latestResponse: inputResponseRestSchema.nullable(),
101
+ });
102
+ export const inputRequestLifecycleDataEventSchema = z.object({
103
+ type: z.literal("veryfront.input_request.lifecycle"),
104
+ data: z.object({
105
+ action: z.enum(["created", "updated"]),
106
+ inputRequest: inputRequestOutputSchema,
107
+ }),
108
+ name: z.literal("veryfront.input_request.lifecycle"),
109
+ value: z.object({
110
+ action: z.enum(["created", "updated"]),
111
+ inputRequest: inputRequestOutputSchema,
112
+ }),
113
+ });
114
+ export async function createInputRequest(input) {
115
+ const requestBody = createInputRequestRequestSchema.parse({
116
+ run_id: input.runId,
117
+ tool_call_id: input.toolCallId,
118
+ kind: "form",
119
+ requested_responder_type: "human",
120
+ title: input.form.title,
121
+ ...(input.form.description ? { description: input.form.description } : {}),
122
+ fields: input.form.fields,
123
+ expires_at: input.expiresAt,
124
+ ...(input.form.submitLabel ? { metadata: { submitLabel: input.form.submitLabel } } : {}),
125
+ });
126
+ const response = await fetch(`${input.apiUrl}/conversations/${input.conversationId}/input-requests`, {
127
+ method: "POST",
128
+ headers: {
129
+ Authorization: `Bearer ${input.authToken}`,
130
+ "Content-Type": "application/json",
131
+ },
132
+ body: JSON.stringify(requestBody),
133
+ signal: AbortSignal.timeout(15_000),
134
+ });
135
+ if (!response.ok) {
136
+ const detail = await response.text().catch(() => "");
137
+ throw new Error(detail || `Failed to create durable input request (HTTP ${response.status})`);
138
+ }
139
+ return createInputRequestResponseSchema.parse(await response.json());
140
+ }
141
+ export async function getInputRequest(input) {
142
+ const response = await fetch(`${input.apiUrl}/conversations/${input.conversationId}/input-requests/${input.inputRequestId}`, {
143
+ method: "GET",
144
+ headers: {
145
+ Authorization: `Bearer ${input.authToken}`,
146
+ },
147
+ signal: AbortSignal.timeout(15_000),
148
+ });
149
+ if (!response.ok) {
150
+ const detail = await response.text().catch(() => "");
151
+ throw new Error(detail || `Failed to fetch durable input request (HTTP ${response.status})`);
152
+ }
153
+ return getInputRequestResponseSchema.parse(await response.json());
154
+ }
155
+ export function buildInputRequestLifecycleDataEvent(input) {
156
+ return inputRequestLifecycleDataEventSchema.parse({
157
+ type: "veryfront.input_request.lifecycle",
158
+ data: {
159
+ action: input.action,
160
+ inputRequest: input.inputRequest,
161
+ },
162
+ name: "veryfront.input_request.lifecycle",
163
+ value: {
164
+ action: input.action,
165
+ inputRequest: input.inputRequest,
166
+ },
167
+ });
168
+ }
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.364";
1
+ export declare const VERSION = "0.1.366";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.364";
3
+ export const VERSION = "0.1.366";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.364",
3
+ "version": "0.1.366",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.364",
3
+ "version": "0.1.366",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -0,0 +1,118 @@
1
+ import * as dntShim from "../../_dnt.shims.js";
2
+ import { tool, type ToolExecutionContext } from "../tool/index.js";
3
+ import { containsExactArtifactPathValue } from "./slash-command-artifact-policy.js";
4
+ import {
5
+ buildInputRequestLifecycleDataEvent,
6
+ createInputRequest,
7
+ type FormInputToolInput,
8
+ formInputToolInputSchema,
9
+ getInputRequest,
10
+ type InputRequestOutput,
11
+ } from "./input-request-protocol.js";
12
+ import { executeDurableHumanInputFlow, type HumanInputResult } from "./human-input.js";
13
+
14
+ const INPUT_REQUEST_TIMEOUT_MS = 5 * 60_000;
15
+ const INPUT_REQUEST_POLL_INTERVAL_MS = 500;
16
+
17
+ export interface HostedFormInputToolContext {
18
+ authToken: string;
19
+ conversationId?: string;
20
+ parentRunId?: string;
21
+ slashCommandArtifactPathSeen?: boolean;
22
+ }
23
+
24
+ export function createHostedFormInputTool(context: HostedFormInputToolContext, apiUrl: string) {
25
+ return tool({
26
+ description:
27
+ "Display a durable structured form to collect user input. Use this when you need a concrete choice or structured values before continuing. The request is persisted as an input_request and the tool waits until the user submits or the request expires.",
28
+ inputSchema: formInputToolInputSchema,
29
+ execute: async (input, execOptions) =>
30
+ executeDurableFormInputFlow(context, apiUrl, input, execOptions),
31
+ });
32
+ }
33
+
34
+ async function executeDurableFormInputFlow(
35
+ context: HostedFormInputToolContext,
36
+ apiUrl: string,
37
+ input: FormInputToolInput,
38
+ execContext?: ToolExecutionContext,
39
+ ) {
40
+ if (!context.conversationId) {
41
+ throw new Error("form_input requires a durable conversation context");
42
+ }
43
+ if (!context.parentRunId) {
44
+ throw new Error("form_input requires a durable run context");
45
+ }
46
+
47
+ const conversationId = context.conversationId;
48
+ const parentRunId = context.parentRunId;
49
+ const toolCallId =
50
+ typeof execContext?.toolCallId === "string" && execContext.toolCallId.length > 0
51
+ ? execContext.toolCallId
52
+ : `form_input-${dntShim.crypto.randomUUID()}`;
53
+
54
+ const { result, createdRequest } = await executeDurableHumanInputFlow({
55
+ runId: parentRunId,
56
+ threadId: conversationId,
57
+ toolCallId,
58
+ request: input,
59
+ timeoutMs: INPUT_REQUEST_TIMEOUT_MS + 5_000,
60
+ pollIntervalMs: INPUT_REQUEST_POLL_INTERVAL_MS,
61
+ onRequest: async (pendingRequest) => {
62
+ const created = await createInputRequest({
63
+ authToken: context.authToken,
64
+ apiUrl,
65
+ conversationId,
66
+ runId: parentRunId,
67
+ toolCallId,
68
+ form: pendingRequest.request,
69
+ expiresAt: new Date(Date.now() + INPUT_REQUEST_TIMEOUT_MS).toISOString(),
70
+ });
71
+ await execContext?.publishDataEvent?.(buildInputRequestLifecycleDataEvent({
72
+ action: "created",
73
+ inputRequest: created,
74
+ }));
75
+ return created;
76
+ },
77
+ getSnapshot: (created) =>
78
+ getInputRequest({
79
+ authToken: context.authToken,
80
+ apiUrl,
81
+ conversationId,
82
+ inputRequestId: created.id,
83
+ }),
84
+ resolveSnapshot: (current) => resolveDurableInputRequestResult(context, current),
85
+ });
86
+
87
+ return {
88
+ ...result,
89
+ inputRequestId: createdRequest.id,
90
+ };
91
+ }
92
+
93
+ function resolveDurableInputRequestResult(
94
+ context: HostedFormInputToolContext,
95
+ snapshot: InputRequestOutput,
96
+ ): HumanInputResult | undefined {
97
+ if (snapshot.status === "submitted") {
98
+ const values = snapshot.latestResponse?.values ?? {};
99
+
100
+ if (containsExactArtifactPathValue(values)) {
101
+ context.slashCommandArtifactPathSeen = true;
102
+ }
103
+
104
+ return {
105
+ submitted: true,
106
+ values,
107
+ };
108
+ }
109
+
110
+ if (snapshot.status === "cancelled" || snapshot.status === "expired") {
111
+ return {
112
+ submitted: false,
113
+ values: {},
114
+ };
115
+ }
116
+
117
+ return undefined;
118
+ }
@@ -767,6 +767,26 @@ export {
767
767
  AgUiRequestSchema,
768
768
  createAgUiHandler,
769
769
  } from "./ag-ui-handler.js";
770
+ export {
771
+ createHostedFormInputTool,
772
+ type HostedFormInputToolContext,
773
+ } from "./hosted-form-input-tool.js";
774
+ export {
775
+ buildInputRequestLifecycleDataEvent,
776
+ createInputRequest,
777
+ createInputRequestRequestSchema,
778
+ createInputRequestResponseSchema,
779
+ type FormInputToolInput,
780
+ formInputToolInputSchema,
781
+ getInputRequest,
782
+ getInputRequestResponseSchema,
783
+ inputRequestLifecycleDataEventSchema,
784
+ type InputRequestOutput,
785
+ inputRequestOutputSchema,
786
+ inputRequestRestSchema,
787
+ inputResponseRestSchema,
788
+ inputResponseValuesSchema,
789
+ } from "./input-request-protocol.js";
770
790
  export {
771
791
  type DurableHumanInputFlowResult,
772
792
  executeDurableHumanInputFlow,
@@ -0,0 +1,210 @@
1
+ import { z } from "zod";
2
+ import type { ToolExecutionDataEvent } from "../tool/types.js";
3
+ import { HumanInputFieldSchema, HumanInputRequestSchema } from "./human-input.js";
4
+
5
+ export const formInputToolInputSchema = HumanInputRequestSchema.omit({ metadata: true });
6
+ export const inputResponseValuesSchema = z.record(
7
+ z.string(),
8
+ z.union([z.string(), z.boolean(), z.number(), z.null()]),
9
+ );
10
+
11
+ export const createInputRequestRequestSchema = z.object({
12
+ run_id: z.string().min(1),
13
+ tool_call_id: z.string().min(1),
14
+ kind: z.literal("form"),
15
+ requested_responder_type: z.literal("human"),
16
+ title: z.string(),
17
+ description: z.string().optional(),
18
+ fields: z.array(HumanInputFieldSchema).min(1),
19
+ expires_at: z.string().datetime({ offset: true }),
20
+ metadata: z.record(z.string(), z.unknown()).optional(),
21
+ });
22
+
23
+ export const inputResponseRestSchema = z
24
+ .object({
25
+ id: z.string().uuid(),
26
+ input_request_id: z.string().uuid(),
27
+ conversation_id: z.string().uuid(),
28
+ run_id: z.string().min(1),
29
+ actor_type: z.string(),
30
+ actor_id: z.string(),
31
+ values: inputResponseValuesSchema,
32
+ created_at: z.string(),
33
+ })
34
+ .passthrough()
35
+ .transform((value) => ({
36
+ id: value.id,
37
+ inputRequestId: value.input_request_id,
38
+ conversationId: value.conversation_id,
39
+ runId: value.run_id,
40
+ actorType: value.actor_type,
41
+ actorId: value.actor_id,
42
+ values: value.values,
43
+ createdAt: value.created_at,
44
+ }));
45
+
46
+ export const inputRequestRestSchema = z
47
+ .object({
48
+ id: z.string().uuid(),
49
+ conversation_id: z.string().uuid(),
50
+ run_id: z.string().min(1),
51
+ tool_call_id: z.string().min(1),
52
+ kind: z.literal("form"),
53
+ status: z.enum(["open", "submitted", "cancelled", "expired"]),
54
+ requested_responder_type: z.enum(["human", "agent", "system"]),
55
+ title: z.string(),
56
+ description: z.string().nullable(),
57
+ fields: z.array(HumanInputFieldSchema),
58
+ recommendations: z.record(z.string(), z.unknown()).nullable().optional(),
59
+ metadata: z.record(z.string(), z.unknown()).nullable().optional(),
60
+ created_at: z.string(),
61
+ expires_at: z.string().nullable(),
62
+ submitted_at: z.string().nullable().optional(),
63
+ cancelled_at: z.string().nullable().optional(),
64
+ expired_at: z.string().nullable().optional(),
65
+ latest_response: inputResponseRestSchema.nullable().optional(),
66
+ })
67
+ .passthrough()
68
+ .transform((value) => ({
69
+ id: value.id,
70
+ conversationId: value.conversation_id,
71
+ runId: value.run_id,
72
+ toolCallId: value.tool_call_id,
73
+ kind: value.kind,
74
+ status: value.status,
75
+ requestedResponderType: value.requested_responder_type,
76
+ title: value.title,
77
+ description: value.description,
78
+ fields: value.fields,
79
+ recommendations: value.recommendations ?? null,
80
+ metadata: value.metadata ?? null,
81
+ createdAt: value.created_at,
82
+ expiresAt: value.expires_at,
83
+ submittedAt: value.submitted_at ?? null,
84
+ cancelledAt: value.cancelled_at ?? null,
85
+ expiredAt: value.expired_at ?? null,
86
+ latestResponse: value.latest_response ?? null,
87
+ }));
88
+
89
+ export const createInputRequestResponseSchema = inputRequestRestSchema;
90
+ export const getInputRequestResponseSchema = inputRequestRestSchema;
91
+ export const inputRequestOutputSchema = z.object({
92
+ id: z.string().uuid(),
93
+ conversationId: z.string().uuid(),
94
+ runId: z.string().min(1),
95
+ toolCallId: z.string().min(1),
96
+ kind: z.literal("form"),
97
+ status: z.enum(["open", "submitted", "cancelled", "expired"]),
98
+ requestedResponderType: z.enum(["human", "agent", "system"]),
99
+ title: z.string(),
100
+ description: z.string().nullable(),
101
+ fields: z.array(HumanInputFieldSchema),
102
+ recommendations: z.record(z.string(), z.unknown()).nullable(),
103
+ metadata: z.record(z.string(), z.unknown()).nullable(),
104
+ createdAt: z.string(),
105
+ expiresAt: z.string().nullable(),
106
+ submittedAt: z.string().nullable(),
107
+ cancelledAt: z.string().nullable(),
108
+ expiredAt: z.string().nullable(),
109
+ latestResponse: inputResponseRestSchema.nullable(),
110
+ });
111
+
112
+ export const inputRequestLifecycleDataEventSchema = z.object({
113
+ type: z.literal("veryfront.input_request.lifecycle"),
114
+ data: z.object({
115
+ action: z.enum(["created", "updated"]),
116
+ inputRequest: inputRequestOutputSchema,
117
+ }),
118
+ name: z.literal("veryfront.input_request.lifecycle"),
119
+ value: z.object({
120
+ action: z.enum(["created", "updated"]),
121
+ inputRequest: inputRequestOutputSchema,
122
+ }),
123
+ });
124
+
125
+ export type FormInputToolInput = z.infer<typeof formInputToolInputSchema>;
126
+ export type InputRequestOutput = z.infer<typeof inputRequestOutputSchema>;
127
+
128
+ export async function createInputRequest(input: {
129
+ authToken: string;
130
+ apiUrl: string;
131
+ conversationId: string;
132
+ runId: string;
133
+ toolCallId: string;
134
+ form: FormInputToolInput;
135
+ expiresAt: string;
136
+ }): Promise<InputRequestOutput> {
137
+ const requestBody = createInputRequestRequestSchema.parse({
138
+ run_id: input.runId,
139
+ tool_call_id: input.toolCallId,
140
+ kind: "form",
141
+ requested_responder_type: "human",
142
+ title: input.form.title,
143
+ ...(input.form.description ? { description: input.form.description } : {}),
144
+ fields: input.form.fields,
145
+ expires_at: input.expiresAt,
146
+ ...(input.form.submitLabel ? { metadata: { submitLabel: input.form.submitLabel } } : {}),
147
+ });
148
+ const response = await fetch(
149
+ `${input.apiUrl}/conversations/${input.conversationId}/input-requests`,
150
+ {
151
+ method: "POST",
152
+ headers: {
153
+ Authorization: `Bearer ${input.authToken}`,
154
+ "Content-Type": "application/json",
155
+ },
156
+ body: JSON.stringify(requestBody),
157
+ signal: AbortSignal.timeout(15_000),
158
+ },
159
+ );
160
+
161
+ if (!response.ok) {
162
+ const detail = await response.text().catch(() => "");
163
+ throw new Error(detail || `Failed to create durable input request (HTTP ${response.status})`);
164
+ }
165
+
166
+ return createInputRequestResponseSchema.parse(await response.json());
167
+ }
168
+
169
+ export async function getInputRequest(input: {
170
+ authToken: string;
171
+ apiUrl: string;
172
+ conversationId: string;
173
+ inputRequestId: string;
174
+ }): Promise<InputRequestOutput> {
175
+ const response = await fetch(
176
+ `${input.apiUrl}/conversations/${input.conversationId}/input-requests/${input.inputRequestId}`,
177
+ {
178
+ method: "GET",
179
+ headers: {
180
+ Authorization: `Bearer ${input.authToken}`,
181
+ },
182
+ signal: AbortSignal.timeout(15_000),
183
+ },
184
+ );
185
+
186
+ if (!response.ok) {
187
+ const detail = await response.text().catch(() => "");
188
+ throw new Error(detail || `Failed to fetch durable input request (HTTP ${response.status})`);
189
+ }
190
+
191
+ return getInputRequestResponseSchema.parse(await response.json());
192
+ }
193
+
194
+ export function buildInputRequestLifecycleDataEvent(input: {
195
+ action: "created" | "updated";
196
+ inputRequest: InputRequestOutput;
197
+ }): ToolExecutionDataEvent {
198
+ return inputRequestLifecycleDataEventSchema.parse({
199
+ type: "veryfront.input_request.lifecycle",
200
+ data: {
201
+ action: input.action,
202
+ inputRequest: input.inputRequest,
203
+ },
204
+ name: "veryfront.input_request.lifecycle",
205
+ value: {
206
+ action: input.action,
207
+ inputRequest: input.inputRequest,
208
+ },
209
+ });
210
+ }
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.364";
3
+ export const VERSION = "0.1.366";