@byokit/decide 0.1.1 → 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/README.md +5 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +32 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,6 +28,11 @@ if (intent.abstained) askThePerson(); else route(intent.answer);
|
|
|
28
28
|
- **Backends** are tried in order for the questions still unanswered. A backend that fails or takes longer than
|
|
29
29
|
`timeoutMs` (default 5 s) answers nothing. `privacy: 'stays-here'` skips every backend the state would leave the
|
|
30
30
|
device for (Jev), so private text never goes to one.
|
|
31
|
+
- **Any model**: `answerer({ name, leaves, ask })` makes a backend of any `(prompt, signal) => text`: on a phone, the
|
|
32
|
+
ChatGPT the person signed in to (`(p, signal) => accounts.respond(me, { instructions: 'Reply with JSON only.',
|
|
33
|
+
input: p, signal })`). It asks for each answer's probability as JSON; any other reply is an abstain.
|
|
34
|
+
- **Phones and browsers**: the main entry is plain TypeScript with `fetch` (the eval CLI is its own entry), so it
|
|
35
|
+
bundles for React Native and the web; `test/react-native.test.ts` runs it where there is no Node.
|
|
31
36
|
- **Keys**: `jev()` takes the key your host read from its own environment or config. The kit never reads an environment
|
|
32
37
|
variable, and the key goes only into the one request header. Never ship a key inside an app: keep it on the home
|
|
33
38
|
computer and let paired devices ask it.
|
package/dist/index.d.ts
CHANGED
|
@@ -57,3 +57,12 @@ export declare function decide(state: unknown, questions: Record<string, Questio
|
|
|
57
57
|
export declare function resolve(q: Question, raw: Raw | undefined): Omit<Answer, 'by' | 'ms'>;
|
|
58
58
|
/** The app's own function as a backend: return the answer when the case is obvious, undefined otherwise. Stays here. */
|
|
59
59
|
export declare function rules(fn: (state: any, name: string, q: Question) => string | boolean | number | undefined): Backend;
|
|
60
|
+
/** Any model as a backend: `ask` gets one prompt and returns the model's text (on a phone, the signed-in ChatGPT:
|
|
61
|
+
* `(p, signal) => accounts.respond(me, { instructions: '', input: p, signal })`). The model is asked for each option's
|
|
62
|
+
* probability as JSON; an answer that isn't that JSON is no answer, so the question abstains. `leaves`: whether the
|
|
63
|
+
* state goes off this device (true for any hosted model). */
|
|
64
|
+
export declare function answerer(o: {
|
|
65
|
+
name: string;
|
|
66
|
+
leaves: boolean;
|
|
67
|
+
ask: (prompt: string, signal: AbortSignal) => Promise<string>;
|
|
68
|
+
}): Backend;
|
package/dist/index.js
CHANGED
|
@@ -95,3 +95,35 @@ export function rules(fn) {
|
|
|
95
95
|
},
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
|
+
/** Any model as a backend: `ask` gets one prompt and returns the model's text (on a phone, the signed-in ChatGPT:
|
|
99
|
+
* `(p, signal) => accounts.respond(me, { instructions: '', input: p, signal })`). The model is asked for each option's
|
|
100
|
+
* probability as JSON; an answer that isn't that JSON is no answer, so the question abstains. `leaves`: whether the
|
|
101
|
+
* state goes off this device (true for any hosted model). */
|
|
102
|
+
export function answerer(o) {
|
|
103
|
+
return {
|
|
104
|
+
name: o.name,
|
|
105
|
+
leaves: o.leaves,
|
|
106
|
+
async ask(state, questions, signal) {
|
|
107
|
+
const described = Object.fromEntries(Object.entries(questions).map(([k, q]) => [k,
|
|
108
|
+
q.kind === 'choice' ? { pick_one_of: q.options, instructions: q.instructions }
|
|
109
|
+
: q.kind === 'yesno' ? { yes_or_no: q.question, yes: q.yes, no: q.no, answer_keys: ['true', 'false'] }
|
|
110
|
+
: { rate_on: Object.fromEntries(q.levels.map((l, i) => [String(i), l])), instructions: q.instructions }]));
|
|
111
|
+
const prompt = 'Answer each question about the state below. For each question give every answer key a probability ' +
|
|
112
|
+
'between 0 and 1, summing to 1. Reply with JSON only, shaped {"<question>": {"<answer key>": <probability>}}.\n\n' +
|
|
113
|
+
`State: ${JSON.stringify(state)}\n\nQuestions: ${JSON.stringify(described)}`;
|
|
114
|
+
const text = await o.ask(prompt, signal);
|
|
115
|
+
let parsed;
|
|
116
|
+
try {
|
|
117
|
+
parsed = JSON.parse(text.trim());
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
const out = Object.create(null);
|
|
123
|
+
for (const k of Object.keys(questions))
|
|
124
|
+
if (parsed?.[k] && typeof parsed[k] === 'object')
|
|
125
|
+
out[k] = { probabilities: parsed[k] };
|
|
126
|
+
return out;
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
package/package.json
CHANGED