@lampdotdev/lamp 0.36.2-nightly.28 → 0.36.2-nightly.29
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/cli/ai.mjs +10 -2
- package/cli/calls.mjs +3 -3
- package/cli/lamps/lamp-for-games.js +9 -3
- package/cli/lamps/lamp.js +9 -3
- package/cli/lamps/mac-starter/.lamp/meta.json +1 -1
- package/cli/lamps/mac-starter/Sources/LampSupport.swift +4 -3
- package/cli/lamps/web-starter/lamp.js +9 -3
- package/package.json +1 -1
package/cli/ai.mjs
CHANGED
|
@@ -212,6 +212,14 @@ export function models() {
|
|
|
212
212
|
return { models: listedHere, default: defaultId(which) };
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
/**
|
|
216
|
+
* How long a page's request may take: a real answer is never cut off however long the model takes, and the guard only
|
|
217
|
+
* ends a call that has stopped answering (`MAX_TURN_SECONDS` for a step of `act`, the same here). A page that wants a
|
|
218
|
+
* quicker answer asks for one (`seconds`), never a longer one.
|
|
219
|
+
*/
|
|
220
|
+
const GUARD_SECONDS = 600;
|
|
221
|
+
const secondsFor = (body) => (typeof body?.seconds === "number" && body.seconds > 0 ? Math.min(body.seconds, GUARD_SECONDS) : GUARD_SECONDS);
|
|
222
|
+
|
|
215
223
|
/** `/ai`: a text answer, or JSON when asked for it. */
|
|
216
224
|
export async function ask(body) {
|
|
217
225
|
const prompt = typeof body?.prompt === "string" ? body.prompt.trim() : "";
|
|
@@ -219,7 +227,7 @@ export async function ask(body) {
|
|
|
219
227
|
let system = typeof body.system === "string" ? body.system : "";
|
|
220
228
|
if (body.json) system += (system ? "\n\n" : "") + "Answer with JSON only, nothing around it.";
|
|
221
229
|
const which = engine();
|
|
222
|
-
try { return [200, { text: await complete({ system, prompt, images: body.images, which, model: modelFor(which, body.model) }) }]; }
|
|
230
|
+
try { return [200, { text: await complete({ system, prompt, images: body.images, which, model: modelFor(which, body.model), seconds: secondsFor(body) }) }]; }
|
|
223
231
|
catch (error) { return [502, { error: error.message }]; }
|
|
224
232
|
}
|
|
225
233
|
|
|
@@ -233,7 +241,7 @@ export async function decide(body) {
|
|
|
233
241
|
}
|
|
234
242
|
const { system, prompt, schema } = decidePrompt(body.state, questions);
|
|
235
243
|
let text;
|
|
236
|
-
try { text = await complete({ system, prompt, schema }); } catch (error) { return [502, { error: error.message }]; }
|
|
244
|
+
try { text = await complete({ system, prompt, schema, seconds: secondsFor(body) }); } catch (error) { return [502, { error: error.message }]; }
|
|
237
245
|
const read = readDecision(text, questions);
|
|
238
246
|
return read.answers ? [200, { answers: read.answers }] : [502, { error: read.problem }];
|
|
239
247
|
}
|
package/cli/calls.mjs
CHANGED
|
@@ -373,7 +373,7 @@ export const CALLS = {
|
|
|
373
373
|
*/
|
|
374
374
|
async openRouterText(given, { stopped } = {}) {
|
|
375
375
|
return openRouter(() => openRouterText({ key: text(given, "key"), prompt: text(given, "prompt"), images: given.images, system: given.system ?? "",
|
|
376
|
-
model: text(given, "model"), json: given.json === true, schema: given.schema ?? undefined, seconds: seconds(given.seconds,
|
|
376
|
+
model: text(given, "model"), json: given.json === true, schema: given.schema ?? undefined, seconds: seconds(given.seconds, 600, 600), signal: stopped }));
|
|
377
377
|
},
|
|
378
378
|
|
|
379
379
|
/** One chat completion from OpenRouter, its request as `body` (`actAsk`'s): `{message, cost}`, or `{trouble}`. */
|
|
@@ -384,7 +384,7 @@ export const CALLS = {
|
|
|
384
384
|
/** Decisions from OpenRouter's decision model (`AppAI.decide`): `key`, `model`, `state`, `questions`. `{answers, cost}` or `{trouble}`. */
|
|
385
385
|
async openRouterDecide(given, { stopped } = {}) {
|
|
386
386
|
return openRouter(() => openRouterDecide({ key: text(given, "key"), model: text(given, "model"), state: given.state, questions: given.questions ?? {},
|
|
387
|
-
seconds: seconds(given.seconds,
|
|
387
|
+
seconds: seconds(given.seconds, 600, 600), signal: stopped }));
|
|
388
388
|
},
|
|
389
389
|
|
|
390
390
|
/** A picture from OpenRouter (`AppAI.image`): `key`, `model`, `prompt`, `references`, `aspectRatio`. `{image, cost}` or `{trouble}`. */
|
|
@@ -403,7 +403,7 @@ export const CALLS = {
|
|
|
403
403
|
return { text: await complete({ which: text(given, "engine"), tool: typeof given.tool === "string" && given.tool ? given.tool : undefined,
|
|
404
404
|
env: given.env && typeof given.env === "object" ? given.env : {}, system: typeof given.system === "string" ? given.system : "",
|
|
405
405
|
prompt: text(given, "prompt"), schema: given.schema ?? undefined, model: typeof given.model === "string" ? given.model : "",
|
|
406
|
-
images: Array.isArray(given.images) ? given.images : [], seconds: seconds(given.seconds,
|
|
406
|
+
images: Array.isArray(given.images) ? given.images : [], seconds: seconds(given.seconds, 600, 600), signal: stopped }) };
|
|
407
407
|
} catch (error) {
|
|
408
408
|
if (error instanceof EngineTrouble) return { trouble: { kind: error.kind, message: error.message } };
|
|
409
409
|
throw error;
|
|
@@ -301,6 +301,10 @@
|
|
|
301
301
|
});
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// How long the page waits for an answer: as long as Lamp's guard on the call (10 minutes), or the page's own limit,
|
|
305
|
+
// with a little more for the answer to come back.
|
|
306
|
+
function AI_WAIT(seconds) { return (typeof seconds === 'number' && seconds > 0 ? Math.min(seconds, 600) : 600) * 1000 + 15000; }
|
|
307
|
+
|
|
304
308
|
function post(path, body, timeout, deadline) {
|
|
305
309
|
timeout = timeout || 240000;
|
|
306
310
|
var done;
|
|
@@ -485,7 +489,9 @@
|
|
|
485
489
|
return encode(o.images).then(function (images) {
|
|
486
490
|
var body = { prompt: text, system: rules.filter(function (r) { return r; }).join('\n\n'), json: !!o.json, images: images };
|
|
487
491
|
if (o.model) body.model = o.model;
|
|
488
|
-
|
|
492
|
+
// No limit of the page's own unless it asks for one: Lamp's guard ends only a call that stopped answering.
|
|
493
|
+
if (typeof o.seconds === 'number' && o.seconds > 0) body.seconds = o.seconds;
|
|
494
|
+
return post('/ai', body, AI_WAIT(body.seconds));
|
|
489
495
|
}).then(function (reply) {
|
|
490
496
|
if (typeof reply.text !== 'string') throw new Failure('The AI request failed.');
|
|
491
497
|
if (!o.json) return reply.text;
|
|
@@ -998,7 +1004,7 @@
|
|
|
998
1004
|
},
|
|
999
1005
|
/** Asks several questions about the same thing in one request. Answers come back under the same keys. */
|
|
1000
1006
|
decide: function (about, questions) {
|
|
1001
|
-
return post('/ai/decide', { state: decisionState(about), questions: questions }).then(function (reply) {
|
|
1007
|
+
return post('/ai/decide', { state: decisionState(about), questions: questions }, AI_WAIT()).then(function (reply) {
|
|
1002
1008
|
var answers = {};
|
|
1003
1009
|
for (var key in (reply.answers || {})) if (reply.answers.hasOwnProperty(key)) answers[key] = decision(reply.answers[key]);
|
|
1004
1010
|
return answers;
|
|
@@ -1036,7 +1042,7 @@
|
|
|
1036
1042
|
finish(i, answers);
|
|
1037
1043
|
return Promise.resolve();
|
|
1038
1044
|
}
|
|
1039
|
-
return post('/ai/decide', { state: decisionState(state), questions: questions }).then(function (reply) {
|
|
1045
|
+
return post('/ai/decide', { state: decisionState(state), questions: questions }, AI_WAIT()).then(function (reply) {
|
|
1040
1046
|
var answers = {};
|
|
1041
1047
|
for (var k in (reply.answers || {})) if (reply.answers.hasOwnProperty(k)) answers[k] = decision(reply.answers[k]);
|
|
1042
1048
|
if (key) saved[key] = { answers: reply.answers, until: now + o.remember * 1000 };
|
package/cli/lamps/lamp.js
CHANGED
|
@@ -301,6 +301,10 @@
|
|
|
301
301
|
});
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// How long the page waits for an answer: as long as Lamp's guard on the call (10 minutes), or the page's own limit,
|
|
305
|
+
// with a little more for the answer to come back.
|
|
306
|
+
function AI_WAIT(seconds) { return (typeof seconds === 'number' && seconds > 0 ? Math.min(seconds, 600) : 600) * 1000 + 15000; }
|
|
307
|
+
|
|
304
308
|
function post(path, body, timeout, deadline) {
|
|
305
309
|
timeout = timeout || 240000;
|
|
306
310
|
var done;
|
|
@@ -485,7 +489,9 @@
|
|
|
485
489
|
return encode(o.images).then(function (images) {
|
|
486
490
|
var body = { prompt: text, system: rules.filter(function (r) { return r; }).join('\n\n'), json: !!o.json, images: images };
|
|
487
491
|
if (o.model) body.model = o.model;
|
|
488
|
-
|
|
492
|
+
// No limit of the page's own unless it asks for one: Lamp's guard ends only a call that stopped answering.
|
|
493
|
+
if (typeof o.seconds === 'number' && o.seconds > 0) body.seconds = o.seconds;
|
|
494
|
+
return post('/ai', body, AI_WAIT(body.seconds));
|
|
489
495
|
}).then(function (reply) {
|
|
490
496
|
if (typeof reply.text !== 'string') throw new Failure('The AI request failed.');
|
|
491
497
|
if (!o.json) return reply.text;
|
|
@@ -998,7 +1004,7 @@
|
|
|
998
1004
|
},
|
|
999
1005
|
/** Asks several questions about the same thing in one request. Answers come back under the same keys. */
|
|
1000
1006
|
decide: function (about, questions) {
|
|
1001
|
-
return post('/ai/decide', { state: decisionState(about), questions: questions }).then(function (reply) {
|
|
1007
|
+
return post('/ai/decide', { state: decisionState(about), questions: questions }, AI_WAIT()).then(function (reply) {
|
|
1002
1008
|
var answers = {};
|
|
1003
1009
|
for (var key in (reply.answers || {})) if (reply.answers.hasOwnProperty(key)) answers[key] = decision(reply.answers[key]);
|
|
1004
1010
|
return answers;
|
|
@@ -1036,7 +1042,7 @@
|
|
|
1036
1042
|
finish(i, answers);
|
|
1037
1043
|
return Promise.resolve();
|
|
1038
1044
|
}
|
|
1039
|
-
return post('/ai/decide', { state: decisionState(state), questions: questions }).then(function (reply) {
|
|
1045
|
+
return post('/ai/decide', { state: decisionState(state), questions: questions }, AI_WAIT()).then(function (reply) {
|
|
1040
1046
|
var answers = {};
|
|
1041
1047
|
for (var k in (reply.answers || {})) if (reply.answers.hasOwnProperty(k)) answers[k] = decision(reply.answers[k]);
|
|
1042
1048
|
if (key) saved[key] = { answers: reply.answers, until: now + o.remember * 1000 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"Zqx App Name","instance":"
|
|
1
|
+
{"name":"Zqx App Name","instance":"1F28D505-8715-4018-8ADA-A146F6FEB632","exe":"ZqxAppName","platform":"mac"}
|
|
@@ -11299,7 +11299,7 @@
|
|
|
11299
11299
|
let reply = try await post("/ai/decide", [
|
|
11300
11300
|
"state": try decisionState(state),
|
|
11301
11301
|
"questions": questions.mapValues(\.json),
|
|
11302
|
-
])
|
|
11302
|
+
], timeout: 615)
|
|
11303
11303
|
let answers = reply["answers"] as? [String: [String: Any]] ?? [:]
|
|
11304
11304
|
return answers.mapValues(LampDecision.init)
|
|
11305
11305
|
}
|
|
@@ -11427,7 +11427,7 @@
|
|
|
11427
11427
|
group.addTask {
|
|
11428
11428
|
try Task.checkCancellation()
|
|
11429
11429
|
do {
|
|
11430
|
-
let reply = try await post("/ai/decide", body: request.body)
|
|
11430
|
+
let reply = try await post("/ai/decide", body: request.body, timeout: 615)
|
|
11431
11431
|
guard let answers = reply["answers"] as? [String: Any], !answers.isEmpty else {
|
|
11432
11432
|
return Outcome(index: request.index, error: "The decision model didn't answer.")
|
|
11433
11433
|
}
|
|
@@ -11600,7 +11600,8 @@
|
|
|
11600
11600
|
"images": images.compactMap(encode),
|
|
11601
11601
|
]
|
|
11602
11602
|
if let model { body["model"] = model }
|
|
11603
|
-
|
|
11603
|
+
// As long as Lamp's guard on the call: a real answer is never cut off, however long the model takes.
|
|
11604
|
+
let reply = try await post("/ai", body, timeout: 615)
|
|
11604
11605
|
guard let text = reply["text"] as? String else { throw Failure(message: "The AI request failed.") }
|
|
11605
11606
|
return text
|
|
11606
11607
|
}
|
|
@@ -301,6 +301,10 @@
|
|
|
301
301
|
});
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// How long the page waits for an answer: as long as Lamp's guard on the call (10 minutes), or the page's own limit,
|
|
305
|
+
// with a little more for the answer to come back.
|
|
306
|
+
function AI_WAIT(seconds) { return (typeof seconds === 'number' && seconds > 0 ? Math.min(seconds, 600) : 600) * 1000 + 15000; }
|
|
307
|
+
|
|
304
308
|
function post(path, body, timeout, deadline) {
|
|
305
309
|
timeout = timeout || 240000;
|
|
306
310
|
var done;
|
|
@@ -485,7 +489,9 @@
|
|
|
485
489
|
return encode(o.images).then(function (images) {
|
|
486
490
|
var body = { prompt: text, system: rules.filter(function (r) { return r; }).join('\n\n'), json: !!o.json, images: images };
|
|
487
491
|
if (o.model) body.model = o.model;
|
|
488
|
-
|
|
492
|
+
// No limit of the page's own unless it asks for one: Lamp's guard ends only a call that stopped answering.
|
|
493
|
+
if (typeof o.seconds === 'number' && o.seconds > 0) body.seconds = o.seconds;
|
|
494
|
+
return post('/ai', body, AI_WAIT(body.seconds));
|
|
489
495
|
}).then(function (reply) {
|
|
490
496
|
if (typeof reply.text !== 'string') throw new Failure('The AI request failed.');
|
|
491
497
|
if (!o.json) return reply.text;
|
|
@@ -998,7 +1004,7 @@
|
|
|
998
1004
|
},
|
|
999
1005
|
/** Asks several questions about the same thing in one request. Answers come back under the same keys. */
|
|
1000
1006
|
decide: function (about, questions) {
|
|
1001
|
-
return post('/ai/decide', { state: decisionState(about), questions: questions }).then(function (reply) {
|
|
1007
|
+
return post('/ai/decide', { state: decisionState(about), questions: questions }, AI_WAIT()).then(function (reply) {
|
|
1002
1008
|
var answers = {};
|
|
1003
1009
|
for (var key in (reply.answers || {})) if (reply.answers.hasOwnProperty(key)) answers[key] = decision(reply.answers[key]);
|
|
1004
1010
|
return answers;
|
|
@@ -1036,7 +1042,7 @@
|
|
|
1036
1042
|
finish(i, answers);
|
|
1037
1043
|
return Promise.resolve();
|
|
1038
1044
|
}
|
|
1039
|
-
return post('/ai/decide', { state: decisionState(state), questions: questions }).then(function (reply) {
|
|
1045
|
+
return post('/ai/decide', { state: decisionState(state), questions: questions }, AI_WAIT()).then(function (reply) {
|
|
1040
1046
|
var answers = {};
|
|
1041
1047
|
for (var k in (reply.answers || {})) if (reply.answers.hasOwnProperty(k)) answers[k] = decision(reply.answers[k]);
|
|
1042
1048
|
if (key) saved[key] = { answers: reply.answers, until: now + o.remember * 1000 };
|