sygnal 6.1.1 → 6.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/CHANGELOG.md +39 -0
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs.map +1 -1
- package/dist/diagnostics.cjs.js +10 -3
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +10 -3
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/adapters.md +2 -1
- package/dist/guide/agent.md +112 -6
- package/dist/guide/ai-chat.md +60 -16
- package/dist/guide/ai-decisions.md +1 -1
- package/dist/guide/behaviors.md +1 -1
- package/dist/guide/error-boundaries.md +2 -1
- package/dist/guide/forms.md +1 -1
- package/dist/guide/http.md +4 -4
- package/dist/guide/mcp-apps.md +4 -2
- package/dist/guide/persistence.md +1 -1
- package/dist/guide/recipes/ai-form-fill.md +1 -1
- package/dist/guide/recipes/ai-summarize.md +1 -1
- package/dist/guide/recipes/ai-support-inbox.md +1 -1
- package/dist/guide/resources.md +11 -10
- package/dist/guide/ui/combobox.md +1 -1
- package/dist/guide/undo.md +1 -1
- package/dist/guide/web-components.md +1 -0
- package/dist/guide/webmcp.md +1 -2
- package/dist/index.cjs.js +155 -31
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +42 -6
- package/dist/index.esm.js +155 -31
- package/dist/index.esm.js.map +1 -1
- package/dist/sygnal.min.js +1 -1
- package/dist/sygnal.min.js.map +1 -1
- package/dist/vike/config/package.json +1 -1
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/ai.d.ts +41 -5
- package/src/extra/ai/agent/index.ts +111 -26
- package/src/extra/ai/chat/behavior.ts +14 -6
- package/src/extra/ai/webmcp.ts +5 -3
- package/src/extra/diagnostics/codes.ts +10 -3
- package/src/index.d.ts +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -744,6 +744,9 @@ const DEV_CODE_SEVERITY = {
|
|
|
744
744
|
SYG240: 'error',
|
|
745
745
|
SYG241: 'error',
|
|
746
746
|
SYG243: 'warn',
|
|
747
|
+
SYG246: 'error',
|
|
748
|
+
SYG247: 'warn',
|
|
749
|
+
SYG248: 'warn',
|
|
747
750
|
// PLAN-6 A-2 (WebMCP, reported with the severity passed)
|
|
748
751
|
SYG242: 'warn',
|
|
749
752
|
SYG244: 'warn',
|
|
@@ -12688,7 +12691,8 @@ async function parseInput(schema, args, options = {}) {
|
|
|
12688
12691
|
* `t.tools()` / `t.callTool()` / `t.agentContext()` (A-4) all use it.
|
|
12689
12692
|
*
|
|
12690
12693
|
* Comp.agent = { name, description?, read?, label?, untrusted?,
|
|
12691
|
-
* actions: { ACTION: { description, input?, consequential?, when?, idempotent? } }
|
|
12694
|
+
* actions: { ACTION: { description, input?, consequential?, when?, idempotent?, until?, timeout? } },
|
|
12695
|
+
* queries: { find: { description, input?, when?, run: (state, input) => result } } }
|
|
12692
12696
|
*
|
|
12693
12697
|
* It reaches the app only through the runtime API (`root`, `get`, `dispatch`, `flushed`,
|
|
12694
12698
|
* `addHooks`) and one hook layer, so the core pays 0 bytes:
|
|
@@ -12707,12 +12711,24 @@ async function parseInput(schema, args, options = {}) {
|
|
|
12707
12711
|
* outcome measured by `wrapHandler` on that action only: success when a STATE handler changed
|
|
12708
12712
|
* the state structurally, a sink got a value or an EFFECT ran; `abort(reason)` refuses with the
|
|
12709
12713
|
* reason; otherwise "changed nothing" (`idempotent: true`: `{ ok: true, unchanged: true }`, D256);
|
|
12714
|
+
* - `until`: an action whose result arrives later (a `resources` entry, a driver reply) answers
|
|
12715
|
+
* once it is in state: `until: 'search'` (the resource is neither loading nor refreshing) or
|
|
12716
|
+
* `until: (state) => boolean`, checked after the action's flush and after every flush that
|
|
12717
|
+
* changed something; `{ ok: true, pending: true, note, state }` after `timeout` (default 10 s) or
|
|
12718
|
+
* `cancel()` (the chat behavior's STOP / new turn); `removed: true` when the instance went away.
|
|
12719
|
+
* Calls run one at a time, so a waiting call delays the next one;
|
|
12720
|
+
* - queries: read-only tools (`readOnlyHint`) that take an input, for data too large for `read`
|
|
12721
|
+
* or answers computed from the state: `run(state, input)` is a pure, synchronous function of the
|
|
12722
|
+
* instance's state; a call validates the input as for actions, checks `when`, and returns
|
|
12723
|
+
* `{ ok: true, result }` without dispatching anything (no confirm, no flush);
|
|
12710
12724
|
* - `when` and `read`: cached by state identity per instance (reducers are immutable);
|
|
12711
12725
|
* - HMR: given the `run()` result, it re-binds to `app.__runtime` after the root's dispose.
|
|
12712
12726
|
* Diagnostics (dev, once each): SYG240 an input with no JSON Schema form (the tool is left out;
|
|
12713
|
-
* `list({ all: true })` shows it with `error`), SYG241 `read` / `when` / `label` threw,
|
|
12714
|
-
* lossy input schema,
|
|
12715
|
-
*
|
|
12727
|
+
* `list({ all: true })` shows it with `error`), SYG241 `read` / `when` / `until` / `label` / a query threw,
|
|
12728
|
+
* SYG243 a lossy input schema, SYG246 a query whose `run` is not a function or returned a promise,
|
|
12729
|
+
* SYG247 a query with the tool name of an action (not offered), SYG248 `until` names no resource of
|
|
12730
|
+
* the component (the call answers at once), SYG440 two declarations with one
|
|
12731
|
+
* name, SYG441 Collection items with no or duplicate keys.
|
|
12716
12732
|
*/
|
|
12717
12733
|
const snake = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/\W+/g, '_').toLowerCase();
|
|
12718
12734
|
const keyOf$1 = (iv) => iv.state?.id;
|
|
@@ -12725,9 +12741,9 @@ const dev$2 = (code, decl, what, component, message) => {
|
|
|
12725
12741
|
if (s.has(code + what))
|
|
12726
12742
|
return;
|
|
12727
12743
|
s.add(code + what);
|
|
12728
|
-
// severities are passed (DEV_CODE_SEVERITY, kept out of the main bundle's table): 240 / 241 error, 243 / 440 / 441 warn
|
|
12744
|
+
// severities are passed (DEV_CODE_SEVERITY, kept out of the main bundle's table): 240 / 241 / 246 error, 243 / 247 / 248 / 440 / 441 warn
|
|
12729
12745
|
try {
|
|
12730
|
-
report(code, { component, message, severity: code < 'SYG242' ? 'error' : 'warn' });
|
|
12746
|
+
report(code, { component, message, severity: code < 'SYG242' || code == 'SYG246' ? 'error' : 'warn' });
|
|
12731
12747
|
}
|
|
12732
12748
|
catch (e) {
|
|
12733
12749
|
queueMicrotask(() => { throw e; });
|
|
@@ -12826,6 +12842,17 @@ function agentTools(target, options = {}) {
|
|
|
12826
12842
|
const owners = new Map();
|
|
12827
12843
|
const listeners = new Set();
|
|
12828
12844
|
let last, scheduled = false;
|
|
12845
|
+
// `until`: calls waiting for their action's result to land in state, checked after each flush that changed something
|
|
12846
|
+
const waiters = new Set(), cancels = new Set();
|
|
12847
|
+
let waking = false;
|
|
12848
|
+
const wake = () => {
|
|
12849
|
+
if (!waiters.size || waking)
|
|
12850
|
+
return;
|
|
12851
|
+
waking = true;
|
|
12852
|
+
queueMicrotask(() => api.flushed().then(() => { waking = false; for (const w of [...waiters])
|
|
12853
|
+
w(); }));
|
|
12854
|
+
};
|
|
12855
|
+
const changed = () => { dirty(); wake(); };
|
|
12829
12856
|
const dirty = () => {
|
|
12830
12857
|
ver++;
|
|
12831
12858
|
if (!listeners.size || scheduled || stopped)
|
|
@@ -12836,10 +12863,10 @@ function agentTools(target, options = {}) {
|
|
|
12836
12863
|
};
|
|
12837
12864
|
const hooks = {
|
|
12838
12865
|
onCreate: dirty,
|
|
12839
|
-
onPatch:
|
|
12840
|
-
onReducer:
|
|
12866
|
+
onPatch: changed,
|
|
12867
|
+
onReducer: changed,
|
|
12841
12868
|
onDispose: (iv) => {
|
|
12842
|
-
|
|
12869
|
+
changed();
|
|
12843
12870
|
// HMR: run()'s hmr() disposes this app, starts its successor and swaps __runtime
|
|
12844
12871
|
if (iv.isRoot && isApp)
|
|
12845
12872
|
queueMicrotask(rebind);
|
|
@@ -13009,24 +13036,39 @@ function agentTools(target, options = {}) {
|
|
|
13009
13036
|
const d = e.decl;
|
|
13010
13037
|
if (d.read)
|
|
13011
13038
|
recs.set(e.name + '_read', { e, tool: { name: e.name + '_read', description: `Read ${e.name}` + (d.description ? `: ${d.description}` : ''), inputSchema: { type: 'object', properties: {} }, annotations: { readOnlyHint: true, ...(d.untrusted && { untrustedContentHint: true }) } } });
|
|
13012
|
-
|
|
13013
|
-
|
|
13039
|
+
// the actions, then the queries (read-only, `run(state, input)`): one tool each
|
|
13040
|
+
const defs = [];
|
|
13041
|
+
for (const k in d.actions)
|
|
13042
|
+
defs.push([k, d.actions[k], false]);
|
|
13043
|
+
for (const k in d.queries)
|
|
13044
|
+
defs.push([k, d.queries[k], true]);
|
|
13045
|
+
for (const [action, a, isQuery] of defs) {
|
|
13046
|
+
const name = e.name + '_' + snake(action), comp = e.ivs[0].name, where = `agent.${isQuery ? 'queries' : 'actions'}.${action}`;
|
|
13047
|
+
if (isQuery && recs.has(name)) {
|
|
13048
|
+
dev$2('SYG247', d, action, comp, `${where} has the tool name ${name} of an action; the query is not offered (rename it)`);
|
|
13049
|
+
continue;
|
|
13050
|
+
}
|
|
13051
|
+
if (isQuery && typeof a?.run != 'function') {
|
|
13052
|
+
dev$2('SYG246', d, action, comp, `${where}.run is not a function; the query is not offered`);
|
|
13053
|
+
continue;
|
|
13054
|
+
}
|
|
13014
13055
|
const c = a.input ? toJsonSchema(a.input) : undefined;
|
|
13015
13056
|
if (c?.schema)
|
|
13016
13057
|
enumsOf(c.schema, e.enums);
|
|
13017
|
-
const tool = { name, description: a.description, inputSchema: c?.schema || { type: 'object', properties: {} },
|
|
13018
|
-
|
|
13058
|
+
const tool = { name, description: a.description, inputSchema: c?.schema || { type: 'object', properties: {} },
|
|
13059
|
+
annotations: isQuery ? { readOnlyHint: true, ...(d.untrusted && { untrustedContentHint: true }) } : a.consequential ? { consequentialHint: true } : {} };
|
|
13060
|
+
const rec = isQuery ? { e, query: action, a, tool } : { e, action, a, tool };
|
|
13019
13061
|
recs.set(name, rec);
|
|
13020
13062
|
if (e.item)
|
|
13021
|
-
seen.set(name, { e: { ...e, ivs: [] }
|
|
13063
|
+
seen.set(name, { ...rec, e: { ...e, ivs: [] } });
|
|
13022
13064
|
if (c?.error) {
|
|
13023
13065
|
tool.error = `SYG240 ${c.error}`;
|
|
13024
13066
|
rec.off = 1;
|
|
13025
|
-
dev$2('SYG240', d, action, comp,
|
|
13067
|
+
dev$2('SYG240', d, action, comp, `${where}.input: ${c.error}; the tool is not offered`);
|
|
13026
13068
|
continue;
|
|
13027
13069
|
}
|
|
13028
13070
|
if (c?.lossy)
|
|
13029
|
-
dev$2('SYG243', d, action, comp,
|
|
13071
|
+
dev$2('SYG243', d, action, comp, `${where}.input: the model doesn't see ${c.lossy}`);
|
|
13030
13072
|
const live = e.ivs.filter(iv => whenOk(iv, action, a.when));
|
|
13031
13073
|
if (!live.length) {
|
|
13032
13074
|
rec.off = 1;
|
|
@@ -13124,8 +13166,8 @@ function agentTools(target, options = {}) {
|
|
|
13124
13166
|
}
|
|
13125
13167
|
if (r.tool.error)
|
|
13126
13168
|
return { ok: false, error: r.tool.error };
|
|
13127
|
-
const { e, a, action } = r;
|
|
13128
|
-
if (!action)
|
|
13169
|
+
const { e, a, action, query } = r;
|
|
13170
|
+
if (!action && !query)
|
|
13129
13171
|
return { ok: true, state: context()[e.name] };
|
|
13130
13172
|
const key = r.key || 'id', view = e.view;
|
|
13131
13173
|
let raw = args ?? {}, k;
|
|
@@ -13150,22 +13192,25 @@ function agentTools(target, options = {}) {
|
|
|
13150
13192
|
let iv = resolve();
|
|
13151
13193
|
if (!iv)
|
|
13152
13194
|
return e.item ? missing(e, view, k) : { ok: false, error: `${e.name} is not on the page` };
|
|
13153
|
-
if (
|
|
13195
|
+
if (query)
|
|
13196
|
+
return ask(name, iv, query, a, data);
|
|
13197
|
+
const type = action;
|
|
13198
|
+
if (!whenOk(iv, type, a.when))
|
|
13154
13199
|
return { ok: false, error: `${name} is not available now`, state: resultState(iv) };
|
|
13155
13200
|
if (a.consequential) {
|
|
13156
13201
|
const c = 'confirm' in o ? o.confirm : options.confirm;
|
|
13157
|
-
const info = { tool: name, component: iv.name, action, description: a.description, input: data, ...(e.item && { key: k, label: labelOf(iv) }) };
|
|
13202
|
+
const info = { tool: name, component: iv.name, action: type, description: a.description, input: data, ...(e.item && { key: k, label: labelOf(iv) }) };
|
|
13158
13203
|
if (!(typeof c == 'function' ? await c(info) : c === true))
|
|
13159
13204
|
return { ok: false, error: 'the user declined' };
|
|
13160
13205
|
// the app may have changed while the user decided: resolve and check again
|
|
13161
13206
|
iv = resolve();
|
|
13162
13207
|
if (!iv)
|
|
13163
13208
|
return e.item ? { ...missing(e, view, k), error: `the ${e.name} with id ${JSON.stringify(k)} is gone` } : { ok: false, error: `${e.name} is not on the page any more` };
|
|
13164
|
-
if (!whenOk(iv,
|
|
13209
|
+
if (!whenOk(iv, type, a.when))
|
|
13165
13210
|
return { ok: false, error: `${name} is not available any more`, state: resultState(iv) };
|
|
13166
13211
|
}
|
|
13167
|
-
const rec = pending = { id: iv.id, type
|
|
13168
|
-
api.dispatch(iv.id,
|
|
13212
|
+
const rec = pending = { id: iv.id, type, data, ran: false, out: [] };
|
|
13213
|
+
api.dispatch(iv.id, type, data, 'agent');
|
|
13169
13214
|
await api.flushed();
|
|
13170
13215
|
if (pending === rec)
|
|
13171
13216
|
pending = null;
|
|
@@ -13182,12 +13227,76 @@ function agentTools(target, options = {}) {
|
|
|
13182
13227
|
const gone = iv.disposed;
|
|
13183
13228
|
const state = gone ? resultState(api.get(iv.parentId)) : resultState(iv);
|
|
13184
13229
|
if (out.some(x => x.kind == 'changed' || x.kind == 'sent' || x.kind == 'effect'))
|
|
13185
|
-
return gone ? { ok: true, removed: true, state } : { ok: true, state };
|
|
13230
|
+
return gone ? { ok: true, removed: true, state } : a.until ? settle(name, iv, type, a) : { ok: true, state };
|
|
13186
13231
|
if (refused)
|
|
13187
13232
|
return { ok: false, error: `${action} was refused: ${refused.reason}`, state };
|
|
13188
13233
|
return a.idempotent ? { ok: true, unchanged: true, state } : { ok: false, error: `${action} changed nothing (already so, or the input matched nothing)`, state };
|
|
13189
13234
|
}
|
|
13235
|
+
/** `until` as a predicate: a resource name is done when that resource is neither loading nor refreshing */
|
|
13236
|
+
const doneTest = (iv, action, u) => {
|
|
13237
|
+
if (typeof u == 'function')
|
|
13238
|
+
return u;
|
|
13239
|
+
if (typeof u != 'string')
|
|
13240
|
+
return;
|
|
13241
|
+
const res = iv.def.view.resources;
|
|
13242
|
+
if (!res || !(u in res)) {
|
|
13243
|
+
dev$2('SYG248', declOf(iv), 'until' + action, iv.name, `agent.actions.${action}.until names '${u}', which is not one of ${iv.name}'s resources${res ? ` (${Object.keys(res).join(', ')})` : ''}; the call answers at once`);
|
|
13244
|
+
return;
|
|
13245
|
+
}
|
|
13246
|
+
return (s) => { const r = s?.[u]; return !r || (r.status != 'loading' && !r.refreshing); };
|
|
13247
|
+
};
|
|
13248
|
+
/**
|
|
13249
|
+
* `until`: answer once the action's result is in state (after this flush or a later one), or
|
|
13250
|
+
* with `pending` on `timeout` / `cancel()`; `removed` when the instance went away meanwhile
|
|
13251
|
+
*/
|
|
13252
|
+
function settle(name, iv, action, a) {
|
|
13253
|
+
const test = doneTest(iv, action, a.until);
|
|
13254
|
+
const holds = () => {
|
|
13255
|
+
if (!test)
|
|
13256
|
+
return true;
|
|
13257
|
+
try {
|
|
13258
|
+
return !!test(iv.state);
|
|
13259
|
+
}
|
|
13260
|
+
catch (err) {
|
|
13261
|
+
dev$2('SYG241', declOf(iv), 'until' + action, iv.name, `agent.actions.${action}.until threw: ${err?.message ?? err}`);
|
|
13262
|
+
return true;
|
|
13263
|
+
}
|
|
13264
|
+
};
|
|
13265
|
+
const result = (extra) => ({ ok: true, ...extra, state: iv.disposed ? resultState(api.get(iv.parentId)) : resultState(iv) });
|
|
13266
|
+
if (holds())
|
|
13267
|
+
return result();
|
|
13268
|
+
return new Promise(resolve => {
|
|
13269
|
+
const finish = (extra) => { waiters.delete(check); cancels.delete(cancel); clearTimeout(timer); resolve(result(extra)); };
|
|
13270
|
+
const cancel = () => finish({ pending: true, note: `${name} is still in progress: its result will be in the app state later` });
|
|
13271
|
+
const check = () => stopped ? cancel() : iv.disposed ? finish({ removed: true }) : holds() && finish();
|
|
13272
|
+
const timer = setTimeout(cancel, a.timeout ?? 10000);
|
|
13273
|
+
waiters.add(check);
|
|
13274
|
+
cancels.add(cancel);
|
|
13275
|
+
});
|
|
13276
|
+
}
|
|
13277
|
+
/** a query call: `run(state, input)` on the instance's state now; nothing is dispatched */
|
|
13278
|
+
function ask(name, iv, query, q, data) {
|
|
13279
|
+
if (!whenOk(iv, query, q.when))
|
|
13280
|
+
return { ok: false, error: `${name} is not available now` };
|
|
13281
|
+
let result;
|
|
13282
|
+
try {
|
|
13283
|
+
result = q.run(iv.state, data);
|
|
13284
|
+
}
|
|
13285
|
+
catch (err) {
|
|
13286
|
+
const m = err?.message ?? err;
|
|
13287
|
+
dev$2('SYG241', declOf(iv), 'query' + query, iv.name, `agent.queries.${query}.run threw: ${m}`);
|
|
13288
|
+
return { ok: false, error: `${name} failed: ${m}` };
|
|
13289
|
+
}
|
|
13290
|
+
if (result && typeof result.then == 'function') {
|
|
13291
|
+
dev$2('SYG246', declOf(iv), 'promise' + query, iv.name, `agent.queries.${query}.run returned a promise: a query is a pure, synchronous function of the state`);
|
|
13292
|
+
return { ok: false, error: `${name} is not available: it returned a promise` };
|
|
13293
|
+
}
|
|
13294
|
+
return { ok: true, result };
|
|
13295
|
+
}
|
|
13190
13296
|
return {
|
|
13297
|
+
/** answer every call waiting on `until` now, as `pending` (a chat turn stopped or replaced) */
|
|
13298
|
+
cancel() { for (const c of [...cancels])
|
|
13299
|
+
c(); },
|
|
13191
13300
|
/** the offered tools; `{ all: true }` adds declared tools that can't be offered (`error`, SYG240) */
|
|
13192
13301
|
list,
|
|
13193
13302
|
/** run a tool as an agent: resolves with the result after the action's flush */
|
|
@@ -13199,7 +13308,8 @@ function agentTools(target, options = {}) {
|
|
|
13199
13308
|
dirty();
|
|
13200
13309
|
return () => { listeners.delete(fn); };
|
|
13201
13310
|
},
|
|
13202
|
-
stop() { stopped = true; off?.(); listeners.clear();
|
|
13311
|
+
stop() { stopped = true; off?.(); listeners.clear(); for (const c of [...cancels])
|
|
13312
|
+
c(); },
|
|
13203
13313
|
/** internal (A-2, WebMCP; chat; the command bar): the offered tools grouped by declaration, with `untrusted` as declared and an item declaration's live labels (id → `agent.label`) */
|
|
13204
13314
|
groups() {
|
|
13205
13315
|
const rs = [...build().values()];
|
|
@@ -17722,15 +17832,15 @@ function experimentalExposeWebMcp(app, options = {}) {
|
|
|
17722
17832
|
o[k] = params(s[k], tool, path);
|
|
17723
17833
|
return o;
|
|
17724
17834
|
};
|
|
17725
|
-
/** a result within 1,500 characters of JSON: `state` and long fields are cut first */
|
|
17835
|
+
/** a result within 1,500 characters of JSON: `state`, a query's `result` and long fields are cut first */
|
|
17726
17836
|
const fit = (r, tool) => {
|
|
17727
17837
|
if (!r || typeof r != 'object')
|
|
17728
17838
|
r = { ok: false, error: 'no result' };
|
|
17729
17839
|
let s = JSON.stringify(r);
|
|
17730
17840
|
if (s.length <= OUT)
|
|
17731
17841
|
return r;
|
|
17732
|
-
dev('SYG242', tool + 'out', `a result of ${tool} is ${s.length} characters of JSON, over the budget of ${OUT}; its state is cut (make the agent.read projection smaller)`);
|
|
17733
|
-
const { state, issues, keys, ...rest } = r;
|
|
17842
|
+
dev('SYG242', tool + 'out', `a result of ${tool} is ${s.length} characters of JSON, over the budget of ${OUT}; its ${'result' in r ? 'result' : 'state'} is cut (make ${'result' in r ? "the query's result" : 'the agent.read projection'} smaller)`);
|
|
17843
|
+
const { state, result, issues, keys, ...rest } = r;
|
|
17734
17844
|
const o = { ...rest, truncated: true };
|
|
17735
17845
|
if (typeof o.error == 'string')
|
|
17736
17846
|
o.error = cut(o.error, 400);
|
|
@@ -17739,10 +17849,13 @@ function experimentalExposeWebMcp(app, options = {}) {
|
|
|
17739
17849
|
for (let room = OUT; room > 20; room = room / 2 | 0) {
|
|
17740
17850
|
if (state !== undefined)
|
|
17741
17851
|
o.state = cut(JSON.stringify(state), room);
|
|
17852
|
+
if (result !== undefined)
|
|
17853
|
+
o.result = cut(JSON.stringify(result), room);
|
|
17742
17854
|
if (JSON.stringify(o).length <= OUT)
|
|
17743
17855
|
return o;
|
|
17744
17856
|
}
|
|
17745
17857
|
delete o.state;
|
|
17858
|
+
delete o.result;
|
|
17746
17859
|
delete o.issues;
|
|
17747
17860
|
return o;
|
|
17748
17861
|
};
|
|
@@ -18039,7 +18152,8 @@ function checkLinked(sources, name, without) {
|
|
|
18039
18152
|
*
|
|
18040
18153
|
* Actions ('assistant.X'): SEND (the form's submit: the prompt; or a string as data), STOP (aborts
|
|
18041
18154
|
* the stream, keeps the partial text and reasoning; calls that already ran keep their results,
|
|
18042
|
-
* G-626
|
|
18155
|
+
* G-626; a call waiting on an action's `until` answers as pending: the tool set's cancel(), as on
|
|
18156
|
+
* FAILED and a new turn), REGENERATE (replays the last user turn), APPROVE, DENY,
|
|
18043
18157
|
* DONE (the turn is over: `{ message, text, finishReason, usage, steps }`; a host entry
|
|
18044
18158
|
* 'assistant.DONE' runs after it, like 'form.DONE'). Internal: PROMPT (typing), DELTA / REPLY /
|
|
18045
18159
|
* FAILED (the chat driver's reply actions), ASK (a consequential call waits), RESULTS (the tool
|
|
@@ -18099,8 +18213,14 @@ const askInfo = (p) => {
|
|
|
18099
18213
|
const name = p.type.slice(5);
|
|
18100
18214
|
return { tool: name, component: 'server', action: name, description: p.approval?.requestReason ?? `Run the ${name} tool`, input: p.input, approvalId: p.approval?.id };
|
|
18101
18215
|
};
|
|
18102
|
-
/**
|
|
18103
|
-
|
|
18216
|
+
/**
|
|
18217
|
+
* a tool part with an A-1 result (`{ output }` or `{ error }`); the other side's field goes (a late
|
|
18218
|
+
* result replaces the "not run" error of a stopped turn, G-626)
|
|
18219
|
+
*/
|
|
18220
|
+
const withResult = (p, r) => {
|
|
18221
|
+
const { output: _o, errorText: _e, ...rest } = p;
|
|
18222
|
+
return 'error' in r ? { ...rest, state: 'output-error', errorText: r.error } : { ...rest, state: 'output-available', output: r.output };
|
|
18223
|
+
};
|
|
18104
18224
|
/**
|
|
18105
18225
|
* The last message with its open tool parts closed (a turn stopped, failed or capped): a call
|
|
18106
18226
|
* that already ran gets its result (`ran`, G-626), the others `why`; a server approval still
|
|
@@ -18215,10 +18335,12 @@ function appState(t, groups, labels) {
|
|
|
18215
18335
|
function request(e, o, k, messages, fresh) {
|
|
18216
18336
|
const t = e && toolsOf$1(e);
|
|
18217
18337
|
if (e) {
|
|
18338
|
+
// a new turn: a call still waiting on `until` answers now, as pending
|
|
18218
18339
|
if (fresh) {
|
|
18219
18340
|
e.turn++;
|
|
18220
18341
|
e.steps = 0;
|
|
18221
18342
|
e.answer?.(false);
|
|
18343
|
+
e.tools?.cancel();
|
|
18222
18344
|
}
|
|
18223
18345
|
e.steps++;
|
|
18224
18346
|
}
|
|
@@ -18354,6 +18476,7 @@ const chat = (options = {}) => {
|
|
|
18354
18476
|
EFFECT: (s, _d, _n, p, o, k) => { const e = busy$1(s) && E(p, k, o); if (e) {
|
|
18355
18477
|
e.turn++;
|
|
18356
18478
|
e.answer?.(false);
|
|
18479
|
+
e.tools?.cancel();
|
|
18357
18480
|
} },
|
|
18358
18481
|
},
|
|
18359
18482
|
FAILED: {
|
|
@@ -18361,6 +18484,7 @@ const chat = (options = {}) => {
|
|
|
18361
18484
|
EFFECT: (_s, _d, _n, p, o, k) => { const e = E(p, k, o); if (e) {
|
|
18362
18485
|
e.turn++;
|
|
18363
18486
|
e.answer?.(false);
|
|
18487
|
+
e.tools?.cancel();
|
|
18364
18488
|
} },
|
|
18365
18489
|
},
|
|
18366
18490
|
// (REPLY already set ready: a host entry gets the finished state)
|