@popcomputer/structured-chat 0.1.0 → 0.2.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/LICENSE +0 -1
- package/README.md +175 -108
- package/dist/adapters/openai-compatible-model.d.ts +4 -4
- package/dist/adapters/openai-compatible-model.js +33 -31
- package/dist/core/answer.d.ts +13 -13
- package/dist/core/answer.js +21 -12
- package/dist/core/chat.d.ts +12 -15
- package/dist/core/chat.js +36 -27
- package/dist/core/collect-stage.d.ts +28 -15
- package/dist/core/collect-stage.js +58 -37
- package/dist/core/command.d.ts +1 -1
- package/dist/core/command.js +1 -1
- package/dist/core/debug-protocol.d.ts +126 -0
- package/dist/core/debug-protocol.js +19 -0
- package/dist/core/debug.d.ts +103 -0
- package/dist/core/debug.js +276 -0
- package/dist/core/json-value.d.ts +1 -1
- package/dist/core/json-value.js +8 -1
- package/dist/core/model-guard.d.ts +2 -3
- package/dist/core/model-guard.js +4 -4
- package/dist/core/model.d.ts +15 -19
- package/dist/core/model.js +22 -10
- package/dist/core/protocol.d.ts +84 -79
- package/dist/core/protocol.js +18 -12
- package/dist/core/question.js +17 -15
- package/dist/core/repair.js +1 -1
- package/dist/core/session.d.ts +22 -28
- package/dist/core/session.js +16 -7
- package/dist/core/stage-name.d.ts +1 -1
- package/dist/core/stage-name.js +1 -1
- package/dist/core/stage.d.ts +4 -4
- package/dist/core/stage.js +11 -8
- package/dist/core/tool-set.js +6 -6
- package/dist/core/tool.d.ts +36 -39
- package/dist/core/tool.js +58 -31
- package/dist/core/view.d.ts +64 -39
- package/dist/core/view.js +12 -15
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/integrations/assistant-ui-debug.d.ts +25 -0
- package/dist/integrations/assistant-ui-debug.js +1162 -0
- package/dist/integrations/assistant-ui.d.ts +10 -3
- package/dist/integrations/assistant-ui.js +48 -18
- package/dist/testing/in-memory-session-store.js +1 -1
- package/dist/testing/scenario.js +6 -6
- package/examples/answer-modes.ts +60 -49
- package/examples/prompt-injection-policy.ts +20 -20
- package/examples/resource-search.ts +104 -0
- package/package.json +15 -3
- package/examples/agency-search.ts +0 -101
package/dist/core/protocol.d.ts
CHANGED
|
@@ -2,74 +2,74 @@ import { Effect, Schema } from "effect";
|
|
|
2
2
|
import { ChatSessionIdSchema, ChatSessionRevisionSchema } from "./session.js";
|
|
3
3
|
/** Bounded plain text emitted by a structured chat presenter. */
|
|
4
4
|
export declare const AssistantTextPartSchema: Schema.Struct<{
|
|
5
|
-
type: Schema.Literal<
|
|
6
|
-
text: Schema.
|
|
5
|
+
readonly type: Schema.Literal<"text">;
|
|
6
|
+
readonly text: Schema.Trimmed;
|
|
7
7
|
}>;
|
|
8
8
|
/** Provider-neutral named data emitted by a structured chat presenter. */
|
|
9
9
|
export declare const AssistantDataPartSchema: Schema.Struct<{
|
|
10
|
-
type: Schema.Literal<
|
|
11
|
-
name: Schema.
|
|
12
|
-
data:
|
|
10
|
+
readonly type: Schema.Literal<"data">;
|
|
11
|
+
readonly name: Schema.Trimmed;
|
|
12
|
+
readonly data: Schema.Unknown;
|
|
13
13
|
}>;
|
|
14
14
|
/** Message parts transported from a structured chat action to a browser. */
|
|
15
|
-
export declare const AssistantMessagePartSchema: Schema.Union<[Schema.Struct<{
|
|
16
|
-
type: Schema.Literal<
|
|
17
|
-
text: Schema.
|
|
15
|
+
export declare const AssistantMessagePartSchema: Schema.Union<readonly [Schema.Struct<{
|
|
16
|
+
readonly type: Schema.Literal<"text">;
|
|
17
|
+
readonly text: Schema.Trimmed;
|
|
18
18
|
}>, Schema.Struct<{
|
|
19
|
-
type: Schema.Literal<
|
|
20
|
-
name: Schema.
|
|
21
|
-
data:
|
|
19
|
+
readonly type: Schema.Literal<"data">;
|
|
20
|
+
readonly name: Schema.Trimmed;
|
|
21
|
+
readonly data: Schema.Unknown;
|
|
22
22
|
}>]>;
|
|
23
23
|
/** Message parts transported from a structured chat action to a browser. */
|
|
24
24
|
export type AssistantMessagePart = Schema.Schema.Type<typeof AssistantMessagePartSchema>;
|
|
25
25
|
/** Strict assistant message returned by one structured chat action. */
|
|
26
26
|
export declare const StructuredChatAssistantMessageSchema: Schema.Struct<{
|
|
27
|
-
role: Schema.Literal<
|
|
28
|
-
content: Schema.
|
|
29
|
-
type: Schema.Literal<
|
|
30
|
-
text: Schema.
|
|
27
|
+
readonly role: Schema.Literal<"assistant">;
|
|
28
|
+
readonly content: Schema.NonEmptyArray<Schema.Union<readonly [Schema.Struct<{
|
|
29
|
+
readonly type: Schema.Literal<"text">;
|
|
30
|
+
readonly text: Schema.Trimmed;
|
|
31
31
|
}>, Schema.Struct<{
|
|
32
|
-
type: Schema.Literal<
|
|
33
|
-
name: Schema.
|
|
34
|
-
data:
|
|
35
|
-
}>]
|
|
32
|
+
readonly type: Schema.Literal<"data">;
|
|
33
|
+
readonly name: Schema.Trimmed;
|
|
34
|
+
readonly data: Schema.Unknown;
|
|
35
|
+
}>]>>;
|
|
36
36
|
}>;
|
|
37
37
|
/** Strict assistant message returned by one structured chat action. */
|
|
38
38
|
export type StructuredChatAssistantMessage = Schema.Schema.Type<typeof StructuredChatAssistantMessageSchema>;
|
|
39
39
|
/** Opaque browser-held reference to one server-owned chat session. */
|
|
40
40
|
export declare const StructuredChatSessionReferenceSchema: Schema.Struct<{
|
|
41
|
-
id: Schema.
|
|
42
|
-
revision: Schema.
|
|
41
|
+
readonly id: Schema.Trimmed;
|
|
42
|
+
readonly revision: Schema.Trimmed;
|
|
43
43
|
}>;
|
|
44
44
|
/** Opaque browser-held reference to one server-owned chat session. */
|
|
45
45
|
export type StructuredChatSessionReference = Schema.Schema.Type<typeof StructuredChatSessionReferenceSchema>;
|
|
46
46
|
/** Browser request carrying no server-owned chat state. */
|
|
47
47
|
export declare const StructuredChatTurnRequestSchema: Schema.Struct<{
|
|
48
|
-
session: Schema.optional<Schema.Struct<{
|
|
49
|
-
id: Schema.
|
|
50
|
-
revision: Schema.
|
|
48
|
+
readonly session: Schema.optional<Schema.Struct<{
|
|
49
|
+
readonly id: Schema.Trimmed;
|
|
50
|
+
readonly revision: Schema.Trimmed;
|
|
51
51
|
}>>;
|
|
52
|
-
message: Schema.
|
|
52
|
+
readonly message: Schema.Trimmed;
|
|
53
53
|
}>;
|
|
54
54
|
/** Browser request carrying no server-owned chat state. */
|
|
55
55
|
export type StructuredChatTurnRequest = Schema.Schema.Type<typeof StructuredChatTurnRequestSchema>;
|
|
56
56
|
/** Versioned browser response for one persisted structured chat turn. */
|
|
57
57
|
export declare const StructuredChatTurnResponseSchema: Schema.Struct<{
|
|
58
|
-
schemaVersion: Schema.Literal<
|
|
59
|
-
session: Schema.optional<Schema.Struct<{
|
|
60
|
-
id: Schema.
|
|
61
|
-
revision: Schema.
|
|
58
|
+
readonly schemaVersion: Schema.Literal<1>;
|
|
59
|
+
readonly session: Schema.optional<Schema.Struct<{
|
|
60
|
+
readonly id: Schema.Trimmed;
|
|
61
|
+
readonly revision: Schema.Trimmed;
|
|
62
62
|
}>>;
|
|
63
|
-
message: Schema.Struct<{
|
|
64
|
-
role: Schema.Literal<
|
|
65
|
-
content: Schema.
|
|
66
|
-
type: Schema.Literal<
|
|
67
|
-
text: Schema.
|
|
63
|
+
readonly message: Schema.Struct<{
|
|
64
|
+
readonly role: Schema.Literal<"assistant">;
|
|
65
|
+
readonly content: Schema.NonEmptyArray<Schema.Union<readonly [Schema.Struct<{
|
|
66
|
+
readonly type: Schema.Literal<"text">;
|
|
67
|
+
readonly text: Schema.Trimmed;
|
|
68
68
|
}>, Schema.Struct<{
|
|
69
|
-
type: Schema.Literal<
|
|
70
|
-
name: Schema.
|
|
71
|
-
data:
|
|
72
|
-
}>]
|
|
69
|
+
readonly type: Schema.Literal<"data">;
|
|
70
|
+
readonly name: Schema.Trimmed;
|
|
71
|
+
readonly data: Schema.Unknown;
|
|
72
|
+
}>]>>;
|
|
73
73
|
}>;
|
|
74
74
|
}>;
|
|
75
75
|
/** Versioned browser response for one persisted structured chat turn. */
|
|
@@ -79,102 +79,107 @@ export declare const CollectQuestionView: {
|
|
|
79
79
|
name: "collect_question";
|
|
80
80
|
version: 1;
|
|
81
81
|
inputSchema: Schema.Struct<{
|
|
82
|
-
stage: Schema.
|
|
83
|
-
field: Schema.
|
|
84
|
-
text: Schema.
|
|
85
|
-
options: Schema
|
|
86
|
-
label: Schema.
|
|
87
|
-
}
|
|
82
|
+
readonly stage: Schema.Trimmed;
|
|
83
|
+
readonly field: Schema.Trimmed;
|
|
84
|
+
readonly text: Schema.Trimmed;
|
|
85
|
+
readonly options: Schema.$Array<Schema.Struct<{
|
|
86
|
+
readonly label: Schema.Trimmed;
|
|
87
|
+
}>>;
|
|
88
88
|
}>;
|
|
89
89
|
dataSchema: Schema.Struct<{
|
|
90
|
-
readonly schemaVersion: Schema.Literal<
|
|
90
|
+
readonly schemaVersion: Schema.Literal<1>;
|
|
91
91
|
} & {
|
|
92
|
-
stage: Schema.
|
|
93
|
-
field: Schema.
|
|
94
|
-
text: Schema.
|
|
95
|
-
options: Schema
|
|
96
|
-
label: Schema.
|
|
97
|
-
}
|
|
92
|
+
readonly stage: Schema.Trimmed;
|
|
93
|
+
readonly field: Schema.Trimmed;
|
|
94
|
+
readonly text: Schema.Trimmed;
|
|
95
|
+
readonly options: Schema.$Array<Schema.Struct<{
|
|
96
|
+
readonly label: Schema.Trimmed;
|
|
97
|
+
}>>;
|
|
98
98
|
}>;
|
|
99
99
|
partSchema: Schema.Struct<{
|
|
100
|
-
readonly type: Schema.Literal<
|
|
101
|
-
readonly name: Schema.Literal<
|
|
100
|
+
readonly type: Schema.Literal<"data">;
|
|
101
|
+
readonly name: Schema.Literal<"collect_question">;
|
|
102
102
|
readonly data: Schema.Struct<{
|
|
103
|
-
readonly schemaVersion: Schema.Literal<
|
|
103
|
+
readonly schemaVersion: Schema.Literal<1>;
|
|
104
104
|
} & {
|
|
105
|
-
stage: Schema.
|
|
106
|
-
field: Schema.
|
|
107
|
-
text: Schema.
|
|
108
|
-
options: Schema
|
|
109
|
-
label: Schema.
|
|
110
|
-
}
|
|
105
|
+
readonly stage: Schema.Trimmed;
|
|
106
|
+
readonly field: Schema.Trimmed;
|
|
107
|
+
readonly text: Schema.Trimmed;
|
|
108
|
+
readonly options: Schema.$Array<Schema.Struct<{
|
|
109
|
+
readonly label: Schema.Trimmed;
|
|
110
|
+
}>>;
|
|
111
111
|
}>;
|
|
112
112
|
}>;
|
|
113
113
|
make: (input: {
|
|
114
|
-
readonly text: string;
|
|
115
114
|
readonly stage: string;
|
|
116
115
|
readonly field: string;
|
|
116
|
+
readonly text: string;
|
|
117
117
|
readonly options: readonly {
|
|
118
118
|
readonly label: string;
|
|
119
119
|
}[];
|
|
120
120
|
}) => {
|
|
121
|
-
readonly name: "collect_question";
|
|
122
121
|
readonly type: "data";
|
|
122
|
+
readonly name: "collect_question";
|
|
123
123
|
readonly data: {
|
|
124
124
|
readonly schemaVersion: 1;
|
|
125
|
-
readonly text: string;
|
|
126
125
|
readonly stage: string;
|
|
127
126
|
readonly field: string;
|
|
127
|
+
readonly text: string;
|
|
128
128
|
readonly options: readonly {
|
|
129
129
|
readonly label: string;
|
|
130
130
|
}[];
|
|
131
131
|
};
|
|
132
132
|
};
|
|
133
|
-
parseData: (input:
|
|
134
|
-
readonly
|
|
133
|
+
parseData: (input: {
|
|
134
|
+
readonly stage: string;
|
|
135
|
+
readonly field: string;
|
|
136
|
+
readonly text: string;
|
|
137
|
+
readonly options: readonly {
|
|
138
|
+
readonly label: string;
|
|
139
|
+
}[];
|
|
140
|
+
}) => Effect.Effect<{
|
|
135
141
|
readonly type: "data";
|
|
142
|
+
readonly name: "collect_question";
|
|
136
143
|
readonly data: {
|
|
137
144
|
readonly schemaVersion: 1;
|
|
138
|
-
readonly text: string;
|
|
139
145
|
readonly stage: string;
|
|
140
146
|
readonly field: string;
|
|
147
|
+
readonly text: string;
|
|
141
148
|
readonly options: readonly {
|
|
142
149
|
readonly label: string;
|
|
143
150
|
}[];
|
|
144
151
|
};
|
|
145
|
-
},
|
|
152
|
+
}, Schema.SchemaError, never>;
|
|
146
153
|
decode: (input: import("./json-value.js").JsonValue) => Effect.Effect<{
|
|
147
|
-
readonly name: "collect_question";
|
|
148
154
|
readonly type: "data";
|
|
155
|
+
readonly name: "collect_question";
|
|
149
156
|
readonly data: {
|
|
150
157
|
readonly schemaVersion: 1;
|
|
151
|
-
readonly text: string;
|
|
152
158
|
readonly stage: string;
|
|
153
159
|
readonly field: string;
|
|
160
|
+
readonly text: string;
|
|
154
161
|
readonly options: readonly {
|
|
155
162
|
readonly label: string;
|
|
156
163
|
}[];
|
|
157
164
|
};
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
readonly name: "collect_question";
|
|
165
|
+
}, Schema.SchemaError, never>;
|
|
166
|
+
decodeResult: (input: import("./json-value.js").JsonValue) => import("effect/Result").Result<{
|
|
161
167
|
readonly type: "data";
|
|
168
|
+
readonly name: "collect_question";
|
|
162
169
|
readonly data: {
|
|
163
170
|
readonly schemaVersion: 1;
|
|
164
|
-
readonly text: string;
|
|
165
171
|
readonly stage: string;
|
|
166
172
|
readonly field: string;
|
|
173
|
+
readonly text: string;
|
|
167
174
|
readonly options: readonly {
|
|
168
175
|
readonly label: string;
|
|
169
176
|
}[];
|
|
170
177
|
};
|
|
171
|
-
},
|
|
178
|
+
}, Schema.SchemaError>;
|
|
172
179
|
};
|
|
173
|
-
declare const InvalidChatPresentation_base: Schema.
|
|
174
|
-
readonly
|
|
175
|
-
}
|
|
176
|
-
reason: Schema.Literal<["invalid_message"]>;
|
|
177
|
-
}>;
|
|
180
|
+
declare const InvalidChatPresentation_base: Schema.Class<InvalidChatPresentation, Schema.TaggedStruct<"InvalidChatPresentation", {
|
|
181
|
+
readonly reason: Schema.Literal<"invalid_message">;
|
|
182
|
+
}>, import("effect/Cause").YieldableError>;
|
|
178
183
|
/** Safe reason that application-owned message presentation was rejected. */
|
|
179
184
|
export declare class InvalidChatPresentation extends InvalidChatPresentation_base {
|
|
180
185
|
}
|
package/dist/core/protocol.js
CHANGED
|
@@ -4,20 +4,23 @@ import { defineView } from "./view.js";
|
|
|
4
4
|
/** Bounded plain text emitted by a structured chat presenter. */
|
|
5
5
|
export const AssistantTextPartSchema = Schema.Struct({
|
|
6
6
|
type: Schema.Literal("text"),
|
|
7
|
-
text: Schema.
|
|
7
|
+
text: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(20_000)),
|
|
8
8
|
});
|
|
9
9
|
/** Provider-neutral named data emitted by a structured chat presenter. */
|
|
10
10
|
export const AssistantDataPartSchema = Schema.Struct({
|
|
11
11
|
type: Schema.Literal("data"),
|
|
12
|
-
name: Schema.
|
|
12
|
+
name: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(100), Schema.isPattern(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/)),
|
|
13
13
|
data: Schema.Unknown,
|
|
14
14
|
});
|
|
15
15
|
/** Message parts transported from a structured chat action to a browser. */
|
|
16
|
-
export const AssistantMessagePartSchema = Schema.Union(
|
|
16
|
+
export const AssistantMessagePartSchema = Schema.Union([
|
|
17
|
+
AssistantTextPartSchema,
|
|
18
|
+
AssistantDataPartSchema,
|
|
19
|
+
]);
|
|
17
20
|
/** Strict assistant message returned by one structured chat action. */
|
|
18
21
|
export const StructuredChatAssistantMessageSchema = Schema.Struct({
|
|
19
22
|
role: Schema.Literal("assistant"),
|
|
20
|
-
content: Schema.NonEmptyArray(AssistantMessagePartSchema).
|
|
23
|
+
content: Schema.NonEmptyArray(AssistantMessagePartSchema).check(Schema.isMaxLength(20)),
|
|
21
24
|
});
|
|
22
25
|
/** Opaque browser-held reference to one server-owned chat session. */
|
|
23
26
|
export const StructuredChatSessionReferenceSchema = Schema.Struct({
|
|
@@ -27,7 +30,7 @@ export const StructuredChatSessionReferenceSchema = Schema.Struct({
|
|
|
27
30
|
/** Browser request carrying no server-owned chat state. */
|
|
28
31
|
export const StructuredChatTurnRequestSchema = Schema.Struct({
|
|
29
32
|
session: Schema.optional(StructuredChatSessionReferenceSchema),
|
|
30
|
-
message: Schema.
|
|
33
|
+
message: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(50_000)),
|
|
31
34
|
});
|
|
32
35
|
/** Versioned browser response for one persisted structured chat turn. */
|
|
33
36
|
export const StructuredChatTurnResponseSchema = Schema.Struct({
|
|
@@ -40,25 +43,28 @@ export const CollectQuestionView = defineView({
|
|
|
40
43
|
name: "collect_question",
|
|
41
44
|
version: 1,
|
|
42
45
|
schema: Schema.Struct({
|
|
43
|
-
stage: Schema.
|
|
44
|
-
field: Schema.
|
|
45
|
-
text: Schema.
|
|
46
|
+
stage: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(100)),
|
|
47
|
+
field: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(100)),
|
|
48
|
+
text: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(500)),
|
|
46
49
|
options: Schema.Array(Schema.Struct({
|
|
47
|
-
label: Schema.
|
|
48
|
-
})).
|
|
50
|
+
label: Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(100)),
|
|
51
|
+
})).check(Schema.isMaxLength(20)),
|
|
49
52
|
}),
|
|
50
53
|
});
|
|
51
54
|
/** Safe reason that application-owned message presentation was rejected. */
|
|
52
55
|
export class InvalidChatPresentation extends Schema.TaggedError()("InvalidChatPresentation", { reason: Schema.Literal("invalid_message") }) {
|
|
53
56
|
}
|
|
54
57
|
/** Construct and validate one plain assistant text part. */
|
|
55
|
-
const makeText = (text) => Schema.
|
|
58
|
+
const makeText = (text) => Schema.decodeSync(Schema.toType(AssistantTextPartSchema))({
|
|
59
|
+
type: "text",
|
|
60
|
+
text,
|
|
61
|
+
});
|
|
56
62
|
/** Constructors for deterministic assistant message parts. */
|
|
57
63
|
export const Text = {
|
|
58
64
|
make: makeText,
|
|
59
65
|
};
|
|
60
66
|
const invalidPresentation = () => new InvalidChatPresentation({ reason: "invalid_message" });
|
|
61
|
-
const parseResponse = (input) => Schema.
|
|
67
|
+
const parseResponse = (input) => Schema.decodeUnknownEffect(StructuredChatTurnResponseSchema)(input, {
|
|
62
68
|
onExcessProperty: "error",
|
|
63
69
|
}).pipe(Effect.mapError(invalidPresentation));
|
|
64
70
|
const buildPresentation = (evaluate) => Effect.try({
|
package/dist/core/question.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Schema
|
|
2
|
-
const QuestionTextSchema = Schema.
|
|
3
|
-
const QuestionGoalSchema = Schema.
|
|
4
|
-
const ChoiceLabelSchema = Schema.
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
const QuestionTextSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(500));
|
|
3
|
+
const QuestionGoalSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(1_000));
|
|
4
|
+
const ChoiceLabelSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(100));
|
|
5
|
+
const ChoiceCountSchema = Schema.Number.check(Schema.isInt(), Schema.isBetween({ minimum: 1, maximum: 20 }));
|
|
5
6
|
const fixed = (text) => ({
|
|
6
7
|
_tag: "FixedQuestion",
|
|
7
8
|
text: Schema.decodeSync(QuestionTextSchema)(text),
|
|
@@ -12,8 +13,8 @@ const adaptive = (goal, options) => ({
|
|
|
12
13
|
fallback: Schema.decodeSync(QuestionTextSchema)(options.fallback),
|
|
13
14
|
});
|
|
14
15
|
const adaptiveChoice = (prompt, options) => {
|
|
15
|
-
const minimumOptions = Schema.decodeSync(
|
|
16
|
-
const maximumOptions = Schema.decodeSync(
|
|
16
|
+
const minimumOptions = Schema.decodeSync(ChoiceCountSchema)(options.minimumOptions);
|
|
17
|
+
const maximumOptions = Schema.decodeSync(ChoiceCountSchema)(options.maximumOptions);
|
|
17
18
|
if (minimumOptions > maximumOptions) {
|
|
18
19
|
throw new Error("Adaptive choice minimumOptions cannot exceed maximumOptions");
|
|
19
20
|
}
|
|
@@ -36,21 +37,22 @@ const adaptiveChoice = (prompt, options) => {
|
|
|
36
37
|
};
|
|
37
38
|
};
|
|
38
39
|
const choice = (text, options) => {
|
|
39
|
-
const
|
|
40
|
-
|
|
40
|
+
const firstOption = {
|
|
41
|
+
...options[0],
|
|
42
|
+
label: Schema.decodeSync(ChoiceLabelSchema)(options[0].label),
|
|
43
|
+
};
|
|
44
|
+
const remainingOptions = options.slice(1).map((option) => ({
|
|
45
|
+
...option,
|
|
46
|
+
label: Schema.decodeSync(ChoiceLabelSchema)(option.label),
|
|
47
|
+
}));
|
|
48
|
+
const normalized = [firstOption, ...remainingOptions].map(({ label }) => label.toLocaleLowerCase("en"));
|
|
41
49
|
if (new Set(normalized).size !== normalized.length) {
|
|
42
50
|
throw new Error("Choice question labels must be unique");
|
|
43
51
|
}
|
|
44
|
-
const parsedOptions = options.map((option, index) => ({
|
|
45
|
-
...option,
|
|
46
|
-
label: labels[index] ?? option.label,
|
|
47
|
-
}));
|
|
48
|
-
// SAFETY: map preserves the non-empty tuple length and each option's value;
|
|
49
|
-
// every replacement label was parsed at the same array index.
|
|
50
52
|
return {
|
|
51
53
|
_tag: "ChoiceQuestion",
|
|
52
54
|
text: Schema.decodeSync(QuestionTextSchema)(text),
|
|
53
|
-
options:
|
|
55
|
+
options: [firstOption, ...remainingOptions],
|
|
54
56
|
};
|
|
55
57
|
};
|
|
56
58
|
/** Constructors for static, adaptive, and typed choice questions. */
|
package/dist/core/repair.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
import { structuredDefinition, } from "./definition.js";
|
|
3
|
-
const maximumCorrectionsSchema = Schema.Number.
|
|
3
|
+
const maximumCorrectionsSchema = Schema.Number.check(Schema.isInt(), Schema.isBetween({ minimum: 1, maximum: 20 }));
|
|
4
4
|
const standard = (options = {}) => structuredDefinition("repair")({
|
|
5
5
|
_tag: "StandardRepair",
|
|
6
6
|
maximumCorrections: Schema.decodeSync(maximumCorrectionsSchema)(options.maximumCorrections ?? 5),
|
package/dist/core/session.d.ts
CHANGED
|
@@ -1,53 +1,47 @@
|
|
|
1
1
|
import { Context, Effect, Schema } from "effect";
|
|
2
2
|
import { type UntrustedMessage } from "./model.js";
|
|
3
3
|
/** Stable application-owned identifier for one chat session. */
|
|
4
|
-
export declare const ChatSessionIdSchema: Schema.
|
|
4
|
+
export declare const ChatSessionIdSchema: Schema.Trimmed;
|
|
5
5
|
/** Optional application-owned partition for otherwise public session IDs. */
|
|
6
|
-
export declare const ChatSessionNamespaceSchema: Schema.
|
|
6
|
+
export declare const ChatSessionNamespaceSchema: Schema.Trimmed;
|
|
7
7
|
/** Opaque optimistic revision emitted by a session store adapter. */
|
|
8
|
-
export declare const ChatSessionRevisionSchema: Schema.
|
|
8
|
+
export declare const ChatSessionRevisionSchema: Schema.Trimmed;
|
|
9
9
|
/** Persisted session snapshot revalidated by the chat runtime after loading. */
|
|
10
10
|
export declare const ChatSessionSnapshotSchema: Schema.Struct<{
|
|
11
|
-
revision: Schema.
|
|
12
|
-
state:
|
|
13
|
-
messages: Schema
|
|
14
|
-
role: Schema.
|
|
15
|
-
content: Schema.
|
|
16
|
-
}
|
|
11
|
+
readonly revision: Schema.Trimmed;
|
|
12
|
+
readonly state: Schema.Unknown;
|
|
13
|
+
readonly messages: Schema.$Array<Schema.Struct<{
|
|
14
|
+
readonly role: Schema.Literals<readonly ["user", "assistant"]>;
|
|
15
|
+
readonly content: Schema.Trimmed;
|
|
16
|
+
}>>;
|
|
17
17
|
}>;
|
|
18
18
|
/** Parsed persisted chat session snapshot. */
|
|
19
19
|
export type ChatSessionSnapshot = Schema.Schema.Type<typeof ChatSessionSnapshotSchema>;
|
|
20
20
|
/** Successful optimistic session replacement returned by an adapter. */
|
|
21
21
|
export declare const ChatSessionReplacementSchema: Schema.Struct<{
|
|
22
|
-
revision: Schema.
|
|
22
|
+
readonly revision: Schema.Trimmed;
|
|
23
23
|
}>;
|
|
24
24
|
/** Successful optimistic session replacement returned by an adapter. */
|
|
25
25
|
export type ChatSessionReplacement = Schema.Schema.Type<typeof ChatSessionReplacementSchema>;
|
|
26
26
|
/** Safe reason that a session store dependency was unavailable. */
|
|
27
|
-
export declare const ChatSessionStoreUnavailableReasonSchema: Schema.
|
|
28
|
-
declare const ChatSessionStoreUnavailable_base: Schema.
|
|
29
|
-
readonly
|
|
30
|
-
}
|
|
31
|
-
reason: Schema.Literal<["load_failed", "write_failed"]>;
|
|
32
|
-
}>;
|
|
27
|
+
export declare const ChatSessionStoreUnavailableReasonSchema: Schema.Literals<readonly ["load_failed", "write_failed"]>;
|
|
28
|
+
declare const ChatSessionStoreUnavailable_base: Schema.Class<ChatSessionStoreUnavailable, Schema.TaggedStruct<"ChatSessionStoreUnavailable", {
|
|
29
|
+
readonly reason: Schema.Literals<readonly ["load_failed", "write_failed"]>;
|
|
30
|
+
}>, import("effect/Cause").YieldableError>;
|
|
33
31
|
/** A session store adapter could not load or replace state. */
|
|
34
32
|
export declare class ChatSessionStoreUnavailable extends ChatSessionStoreUnavailable_base {
|
|
35
33
|
}
|
|
36
|
-
declare const ChatSessionConflict_base: Schema.
|
|
37
|
-
readonly
|
|
38
|
-
}
|
|
39
|
-
reason: Schema.Literal<["concurrent_update"]>;
|
|
40
|
-
}>;
|
|
34
|
+
declare const ChatSessionConflict_base: Schema.Class<ChatSessionConflict, Schema.TaggedStruct<"ChatSessionConflict", {
|
|
35
|
+
readonly reason: Schema.Literal<"concurrent_update">;
|
|
36
|
+
}>, import("effect/Cause").YieldableError>;
|
|
41
37
|
/** A concurrent or stale transition attempted to replace newer state. */
|
|
42
38
|
export declare class ChatSessionConflict extends ChatSessionConflict_base {
|
|
43
39
|
}
|
|
44
40
|
/** Safe reason that session input or persisted data was rejected. */
|
|
45
|
-
export declare const InvalidChatSessionReasonSchema: Schema.
|
|
46
|
-
declare const InvalidChatSession_base: Schema.
|
|
47
|
-
readonly
|
|
48
|
-
}
|
|
49
|
-
reason: Schema.Literal<["invalid_input", "invalid_snapshot", "invalid_state", "invalid_replacement", "history_limit"]>;
|
|
50
|
-
}>;
|
|
41
|
+
export declare const InvalidChatSessionReasonSchema: Schema.Literals<readonly ["invalid_input", "invalid_snapshot", "invalid_state", "invalid_replacement", "history_limit"]>;
|
|
42
|
+
declare const InvalidChatSession_base: Schema.Class<InvalidChatSession, Schema.TaggedStruct<"InvalidChatSession", {
|
|
43
|
+
readonly reason: Schema.Literals<readonly ["invalid_input", "invalid_snapshot", "invalid_state", "invalid_replacement", "history_limit"]>;
|
|
44
|
+
}>, import("effect/Cause").YieldableError>;
|
|
51
45
|
/** Session input or persisted state failed runtime validation. */
|
|
52
46
|
export declare class InvalidChatSession extends InvalidChatSession_base {
|
|
53
47
|
}
|
|
@@ -71,7 +65,7 @@ export interface ChatSessionStoreService {
|
|
|
71
65
|
/** Atomically replace one complete session at its expected revision. */
|
|
72
66
|
readonly replace: (input: ReplaceChatSessionInput) => Effect.Effect<unknown, ChatSessionStoreUnavailable | ChatSessionConflict>;
|
|
73
67
|
}
|
|
74
|
-
declare const ChatSessionStore_base: Context.
|
|
68
|
+
declare const ChatSessionStore_base: Context.ServiceClass<ChatSessionStore, "@popcomputer/structured-chat/ChatSessionStore", ChatSessionStoreService>;
|
|
75
69
|
/** Effect service for the configured server-owned chat session store. */
|
|
76
70
|
export declare class ChatSessionStore extends ChatSessionStore_base {
|
|
77
71
|
}
|
package/dist/core/session.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { Context, Effect, Schema } from "effect";
|
|
2
2
|
import { UntrustedMessageSchema } from "./model.js";
|
|
3
3
|
/** Stable application-owned identifier for one chat session. */
|
|
4
|
-
export const ChatSessionIdSchema = Schema.
|
|
4
|
+
export const ChatSessionIdSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(200), Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/));
|
|
5
5
|
/** Optional application-owned partition for otherwise public session IDs. */
|
|
6
|
-
export const ChatSessionNamespaceSchema = Schema.
|
|
6
|
+
export const ChatSessionNamespaceSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(200), Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/));
|
|
7
7
|
/** Opaque optimistic revision emitted by a session store adapter. */
|
|
8
|
-
export const ChatSessionRevisionSchema = Schema.
|
|
8
|
+
export const ChatSessionRevisionSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(200), Schema.isPattern(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/));
|
|
9
9
|
/** Persisted session snapshot revalidated by the chat runtime after loading. */
|
|
10
10
|
export const ChatSessionSnapshotSchema = Schema.Struct({
|
|
11
11
|
revision: ChatSessionRevisionSchema,
|
|
12
12
|
state: Schema.Unknown,
|
|
13
|
-
messages: Schema.Array(UntrustedMessageSchema).
|
|
13
|
+
messages: Schema.Array(UntrustedMessageSchema).check(Schema.isMaxLength(200)),
|
|
14
14
|
});
|
|
15
15
|
/** Successful optimistic session replacement returned by an adapter. */
|
|
16
16
|
export const ChatSessionReplacementSchema = Schema.Struct({
|
|
17
17
|
revision: ChatSessionRevisionSchema,
|
|
18
18
|
});
|
|
19
19
|
/** Safe reason that a session store dependency was unavailable. */
|
|
20
|
-
export const ChatSessionStoreUnavailableReasonSchema = Schema.
|
|
20
|
+
export const ChatSessionStoreUnavailableReasonSchema = Schema.Literals([
|
|
21
|
+
"load_failed",
|
|
22
|
+
"write_failed",
|
|
23
|
+
]);
|
|
21
24
|
/** A session store adapter could not load or replace state. */
|
|
22
25
|
export class ChatSessionStoreUnavailable extends Schema.TaggedError()("ChatSessionStoreUnavailable", { reason: ChatSessionStoreUnavailableReasonSchema }) {
|
|
23
26
|
}
|
|
@@ -25,10 +28,16 @@ export class ChatSessionStoreUnavailable extends Schema.TaggedError()("ChatSessi
|
|
|
25
28
|
export class ChatSessionConflict extends Schema.TaggedError()("ChatSessionConflict", { reason: Schema.Literal("concurrent_update") }) {
|
|
26
29
|
}
|
|
27
30
|
/** Safe reason that session input or persisted data was rejected. */
|
|
28
|
-
export const InvalidChatSessionReasonSchema = Schema.
|
|
31
|
+
export const InvalidChatSessionReasonSchema = Schema.Literals([
|
|
32
|
+
"invalid_input",
|
|
33
|
+
"invalid_snapshot",
|
|
34
|
+
"invalid_state",
|
|
35
|
+
"invalid_replacement",
|
|
36
|
+
"history_limit",
|
|
37
|
+
]);
|
|
29
38
|
/** Session input or persisted state failed runtime validation. */
|
|
30
39
|
export class InvalidChatSession extends Schema.TaggedError()("InvalidChatSession", { reason: InvalidChatSessionReasonSchema }) {
|
|
31
40
|
}
|
|
32
41
|
/** Effect service for the configured server-owned chat session store. */
|
|
33
|
-
export class ChatSessionStore extends Context.
|
|
42
|
+
export class ChatSessionStore extends Context.Service()("@popcomputer/structured-chat/ChatSessionStore") {
|
|
34
43
|
}
|
package/dist/core/stage-name.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
/** Stable machine-facing name for one structured chat stage. */
|
|
3
|
-
export const StageNameSchema = Schema.
|
|
3
|
+
export const StageNameSchema = Schema.Trimmed.check(Schema.isNonEmpty(), Schema.isMaxLength(100), Schema.isPattern(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/));
|
package/dist/core/stage.d.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { Effect, Schema } from "effect";
|
|
|
2
2
|
import { StructuredChatModel, type ChatModelUnavailable, type UnsupportedModelToolSchema, type UntrustedMessage } from "./model.js";
|
|
3
3
|
import type { ModelGuardError, ModelGuardRequirements, ModelGuardTuple } from "./model-guard.js";
|
|
4
4
|
import { type ToolSet, type ToolSetCall, type ToolSetError, type ToolSetExecution, type ToolSetRequirements, type ToolTuple } from "./tool-set.js";
|
|
5
|
-
import type { CommandDefinitionContract, CommandExecutionContext, InvalidToolCall, InvalidToolProjection, StructuredCommand, ToolCall, ToolExecution, QueryToolDefinitionContract } from "./tool.js";
|
|
5
|
+
import type { CommandDefinitionContract, CommandExecutionContext, InvalidToolCall, InvalidToolProjection, StructuredCommand, ToolCall, ToolExecution, QueryToolDefinitionContract, ToolSchema } from "./tool.js";
|
|
6
6
|
import { type StructuredDefinition } from "./definition.js";
|
|
7
7
|
export { StageNameSchema } from "./stage-name.js";
|
|
8
8
|
/** State transition applied after one tool-stage execution. */
|
|
9
|
-
export declare const ToolStageAfterExecutionSchema: Schema.
|
|
9
|
+
export declare const ToolStageAfterExecutionSchema: Schema.Literals<readonly ["stay", "complete"]>;
|
|
10
10
|
/** State transition applied after one tool-stage execution. */
|
|
11
11
|
export type ToolStageAfterExecution = Schema.Schema.Type<typeof ToolStageAfterExecutionSchema>;
|
|
12
12
|
/** Definition input for one stage-scoped, repeatable tool step. */
|
|
@@ -21,8 +21,8 @@ export interface DefineToolStageInput<Name extends string, Tools extends ToolTup
|
|
|
21
21
|
export interface ToolStageRuntime {
|
|
22
22
|
readonly afterExecution: ToolStageAfterExecution;
|
|
23
23
|
readonly toolNames: ReadonlyArray<string>;
|
|
24
|
-
readonly planWith: (messages: ReadonlyArray<UntrustedMessage>, additionalTool: QueryToolDefinitionContract) => Effect.Effect<ToolCall<string,
|
|
25
|
-
readonly execute: (call: ToolCall<string,
|
|
24
|
+
readonly planWith: (messages: ReadonlyArray<UntrustedMessage>, additionalTool: QueryToolDefinitionContract) => Effect.Effect<ToolCall<string, ToolSchema>, unknown, unknown>;
|
|
25
|
+
readonly execute: (call: ToolCall<string, ToolSchema>) => Effect.Effect<unknown, unknown, unknown>;
|
|
26
26
|
readonly run: (messages: ReadonlyArray<UntrustedMessage>) => Effect.Effect<unknown, unknown, unknown>;
|
|
27
27
|
}
|
|
28
28
|
declare const toolStageRuntime: unique symbol;
|