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.
- package/esm/deno.js +1 -1
- package/esm/src/agent/hosted-form-input-tool.d.ts +93 -0
- package/esm/src/agent/hosted-form-input-tool.d.ts.map +1 -0
- package/esm/src/agent/hosted-form-input-tool.js +81 -0
- package/esm/src/agent/index.d.ts +2 -0
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +2 -0
- package/esm/src/agent/input-request-protocol.d.ts +1656 -0
- package/esm/src/agent/input-request-protocol.d.ts.map +1 -0
- package/esm/src/agent/input-request-protocol.js +168 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/agent/hosted-form-input-tool.ts +118 -0
- package/src/src/agent/index.ts +20 -0
- package/src/src/agent/input-request-protocol.ts +210 -0
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -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.
|
|
1
|
+
export declare const VERSION = "0.1.366";
|
|
2
2
|
//# sourceMappingURL=version-constant.d.ts.map
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
|
@@ -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
|
+
}
|
package/src/src/agent/index.ts
CHANGED
|
@@ -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
|
+
}
|