@namzu/sdk 52.0.0 → 52.1.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 +19 -0
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +57 -17
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/contracts/a2a.d.ts +2 -2
- package/dist/provider/capabilities.d.ts +9 -0
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +15 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/errors.d.ts.map +1 -1
- package/dist/provider/errors.js +13 -0
- package/dist/provider/errors.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +10 -0
- package/dist/provider/fallback.js.map +1 -1
- package/dist/provider/idle-timeout.d.ts.map +1 -1
- package/dist/provider/idle-timeout.js +5 -0
- package/dist/provider/idle-timeout.js.map +1 -1
- package/dist/provider/image-input-refusal.d.ts +9 -0
- package/dist/provider/image-input-refusal.d.ts.map +1 -0
- package/dist/provider/image-input-refusal.js +54 -0
- package/dist/provider/image-input-refusal.js.map +1 -0
- package/dist/provider/index.d.ts +2 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +2 -1
- package/dist/provider/index.js.map +1 -1
- package/dist/provider/retry.d.ts +7 -2
- package/dist/provider/retry.d.ts.map +1 -1
- package/dist/provider/retry.js +38 -4
- package/dist/provider/retry.js.map +1 -1
- package/dist/public-runtime.d.ts +1 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +1 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/runtime/query/deferred-sandbox.d.ts +54 -0
- package/dist/runtime/query/deferred-sandbox.d.ts.map +1 -0
- package/dist/runtime/query/deferred-sandbox.js +75 -0
- package/dist/runtime/query/deferred-sandbox.js.map +1 -0
- package/dist/runtime/query/executor.d.ts +10 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +24 -3
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +93 -25
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +26 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +164 -21
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts +10 -7
- package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction-breaker.js +10 -7
- package/dist/runtime/query/iteration/phases/compaction-breaker.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +42 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +119 -21
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts +21 -1
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -1
- package/dist/runtime/query/iteration/provider-rejected-image.js +53 -7
- package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -1
- package/dist/runtime/query/iteration/request-repair.d.ts +108 -0
- package/dist/runtime/query/iteration/request-repair.d.ts.map +1 -0
- package/dist/runtime/query/iteration/request-repair.js +593 -0
- package/dist/runtime/query/iteration/request-repair.js.map +1 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts +6 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +2 -2
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/request-rich-content.d.ts +5 -1
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +67 -25
- package/dist/runtime/query/request-rich-content.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +12 -5
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/types/provider/errors.d.ts.map +1 -1
- package/dist/types/provider/errors.js +30 -5
- package/dist/types/provider/errors.js.map +1 -1
- package/dist/types/provider/interface.d.ts +12 -0
- package/dist/types/provider/interface.d.ts.map +1 -1
- package/dist/types/provider/stream.d.ts +1 -1
- package/dist/types/session/config.d.ts +14 -0
- package/dist/types/session/config.d.ts.map +1 -1
- package/dist/types/session/events.d.ts +20 -5
- package/dist/types/session/events.d.ts.map +1 -1
- package/dist/types/session/events.js.map +1 -1
- package/package.json +1 -1
- package/src/compaction/verifier.ts +57 -20
- package/src/provider/capabilities.ts +17 -0
- package/src/provider/errors.ts +13 -0
- package/src/provider/fallback.ts +10 -0
- package/src/provider/idle-timeout.ts +5 -0
- package/src/provider/image-input-refusal.ts +54 -0
- package/src/provider/index.ts +2 -0
- package/src/provider/retry.ts +42 -4
- package/src/public-runtime.ts +3 -0
- package/src/runtime/query/deferred-sandbox.ts +110 -0
- package/src/runtime/query/executor.ts +25 -3
- package/src/runtime/query/index.ts +124 -49
- package/src/runtime/query/iteration/index.ts +188 -23
- package/src/runtime/query/iteration/phases/compaction-breaker.ts +10 -8
- package/src/runtime/query/iteration/phases/compaction.ts +151 -35
- package/src/runtime/query/iteration/provider-rejected-image.ts +71 -5
- package/src/runtime/query/iteration/request-repair.ts +743 -0
- package/src/runtime/query/iteration/stream-turn.ts +11 -1
- package/src/runtime/query/request-rich-content.ts +77 -27
- package/src/tools/builtins/computer-use.ts +13 -4
- package/src/types/provider/errors.ts +33 -5
- package/src/types/provider/interface.ts +13 -0
- package/src/types/provider/stream.ts +1 -1
- package/src/types/session/config.ts +14 -0
- package/src/types/session/events.ts +25 -5
|
@@ -6,7 +6,7 @@ import { CHARS_PER_TOKEN } from '../../../constants/limits.js';
|
|
|
6
6
|
import { DEFAULT_STRUCTURED_OUTPUT_RETRIES, STRUCTURED_OUTPUT_REPROMPT, } from '../../../constants/tools/index.js';
|
|
7
7
|
import { withStreamedMessageIdentity } from '../../../manager/session/streamed-message-identity.js';
|
|
8
8
|
import { renderSkillsSection } from '../../../persona/assembler.js';
|
|
9
|
-
import { resolveProviderCapabilities } from '../../../provider/capabilities.js';
|
|
9
|
+
import { modelReadsImages, resolveProviderCapabilities } from '../../../provider/capabilities.js';
|
|
10
10
|
import { collectChatCompletion } from '../../../provider/collect-chat-completion.js';
|
|
11
11
|
import { renderToolSchema } from '../../../registry/tool/schema.js';
|
|
12
12
|
import { formatCompletionNotification } from '../../../scheduler/completion-inbox.js';
|
|
@@ -21,6 +21,7 @@ import { stableDigest } from '../../../utils/hash.js';
|
|
|
21
21
|
import { generateMessageId } from '../../../utils/id.js';
|
|
22
22
|
import { parseStructuredResultJson } from '../../../utils/structured-result-json.js';
|
|
23
23
|
import { createCallbackInference } from '../callback-inference.js';
|
|
24
|
+
import { SandboxAcquisitionStopped } from '../deferred-sandbox.js';
|
|
24
25
|
import { deliverDurableInbound } from '../durable-inbound.js';
|
|
25
26
|
import { projectObservationContext } from '../observation-context.js';
|
|
26
27
|
import { applyLifecycleHookResults } from '../plugin-hooks.js';
|
|
@@ -32,12 +33,13 @@ import { drainArrivedTaskCompletions, holdForOutstandingWork, settleOutstandingW
|
|
|
32
33
|
import { runAdvisoryPhase } from './phases/advisory.js';
|
|
33
34
|
import { runIterationCheckpoint } from './phases/checkpoint.js';
|
|
34
35
|
import { compactionBreaker } from './phases/compaction-breaker.js';
|
|
35
|
-
import { activeContextWindow, measureContext, relieveOverflow, runCompactionCheck, } from './phases/compaction.js';
|
|
36
|
+
import { AUTOMATIC_COMPACTION_FAILED, OVERFLOW_RELIEF_LIMIT, activeContextWindow, clearCompactionErrorNote, compactionErrorNote, measureContext, relieveOverflow, runCompactionCheck, stopOnRefill, } from './phases/compaction.js';
|
|
36
37
|
import { runHandoffPause } from './phases/handoff.js';
|
|
37
38
|
import { runPlanGate } from './phases/plan.js';
|
|
38
39
|
import { runToolReview } from './phases/tool-review.js';
|
|
39
40
|
import { refreshWorkingMemory, splitWorkingMemoryForRequest } from './phases/working-memory.js';
|
|
40
|
-
import { streamWithProviderRejectedImageRecovery } from './provider-rejected-image.js';
|
|
41
|
+
import { streamWithProviderRejectedImageRecovery, } from './provider-rejected-image.js';
|
|
42
|
+
import { RequestRepair } from './request-repair.js';
|
|
41
43
|
import { appendWorkContext, beforeStep, prepareStep, selectContextModel, stepContextMessage, } from './step-shaping.js';
|
|
42
44
|
import { streamProviderTurn } from './stream-turn.js';
|
|
43
45
|
/** A host reviewer is not the model transport, even when its cause is an HTTP failure. */
|
|
@@ -69,6 +71,10 @@ const MIN_OUTPUT_CAP_TOKENS = 3000;
|
|
|
69
71
|
// Use the same standard for warning closure and empty-completion recovery.
|
|
70
72
|
const CLOSING_RESPONSE_GUIDANCE = 'Give a concise response using only what the available evidence supports. Attribute unverified statements to their source instead of presenting them as observed facts. If evidence is missing or conflicting, state what cannot be established. Do not claim unfinished work is complete. Do not request any more tool calls.';
|
|
71
73
|
export { awaitedJobGraceMs, settleGraceMs } from './outstanding-work.js';
|
|
74
|
+
/** One provider's model, as {@link IterationOrchestrator} remembers it. */
|
|
75
|
+
function textOnlyKey(providerId, model) {
|
|
76
|
+
return `${providerId}\u0000${model}`;
|
|
77
|
+
}
|
|
72
78
|
export class IterationOrchestrator {
|
|
73
79
|
ctx;
|
|
74
80
|
advisoryTurn;
|
|
@@ -103,6 +109,68 @@ export class IterationOrchestrator {
|
|
|
103
109
|
}
|
|
104
110
|
/** Rich tool blocks already reported; durable history is scanned every turn. */
|
|
105
111
|
warnedRichToolResults = new Set();
|
|
112
|
+
/** What this run has learned about requests its provider rejects as invalid, and how to repair them. */
|
|
113
|
+
requestRepair = new RequestRepair({
|
|
114
|
+
debug: (message) => this.ctx.log.debug(message),
|
|
115
|
+
onMediaRemoved: (removal) => this.noteMediaRemoved(removal),
|
|
116
|
+
servedBy: () => this.ctx.servingMember?.(),
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* Provider and model pairs that refused a request for holding an image; they
|
|
120
|
+
* get none for the rest of the run. Keyed by both: one model id can be served
|
|
121
|
+
* by two members of a fallback chain, and only the one that refused is known.
|
|
122
|
+
*/
|
|
123
|
+
textOnlyModels = new Set();
|
|
124
|
+
/**
|
|
125
|
+
* The member a request for `model` goes to first. A fallback chain keeps
|
|
126
|
+
* serving from the member it last moved to, so that member, not the head,
|
|
127
|
+
* is the one whose reading of images counts.
|
|
128
|
+
*/
|
|
129
|
+
servingModel(model) {
|
|
130
|
+
const serving = this.ctx.servingMember?.();
|
|
131
|
+
return {
|
|
132
|
+
providerId: serving?.providerId ?? this.ctx.provider.id,
|
|
133
|
+
model: serving?.model ?? model,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Whether a request for `model` may carry images: the driver's catalogue and this run's own evidence agree. */
|
|
137
|
+
modelReadsImages(model) {
|
|
138
|
+
const serving = this.servingModel(model);
|
|
139
|
+
return (!this.textOnlyModels.has(textOnlyKey(serving.providerId, serving.model)) &&
|
|
140
|
+
modelReadsImages(this.ctx.provider, model));
|
|
141
|
+
}
|
|
142
|
+
/** What a request for `model` does when its model turns out to read text only. */
|
|
143
|
+
textOnlyRecovery(model) {
|
|
144
|
+
return {
|
|
145
|
+
servedBy: () => this.servingModel(model),
|
|
146
|
+
onAccepted: (refused) => this.noteTextOnlyModel(refused),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A provider refused a request for holding an image its model cannot read, and
|
|
151
|
+
* the retry without images was accepted. Stop sending images to it, and say so
|
|
152
|
+
* once, so the host can remember the model beyond this run.
|
|
153
|
+
*/
|
|
154
|
+
async noteTextOnlyModel(refused) {
|
|
155
|
+
const key = textOnlyKey(refused.providerId, refused.model ?? '');
|
|
156
|
+
if (this.textOnlyModels.has(key))
|
|
157
|
+
return;
|
|
158
|
+
this.textOnlyModels.add(key);
|
|
159
|
+
const { providerId, model } = refused;
|
|
160
|
+
this.ctx.log.warn('Capability mismatch: the model cannot read images', {
|
|
161
|
+
[GENAI.SYSTEM]: providerId,
|
|
162
|
+
[GENAI.REQUEST_MODEL]: model ?? '',
|
|
163
|
+
});
|
|
164
|
+
await this.ctx.emitEvent?.({
|
|
165
|
+
type: 'capability_warning',
|
|
166
|
+
turnId: this.ctx.recorder.turnId,
|
|
167
|
+
capability: 'vision',
|
|
168
|
+
contentSource: 'history',
|
|
169
|
+
providerId,
|
|
170
|
+
...(model !== undefined ? { model } : {}),
|
|
171
|
+
message: `Model '${model ?? 'unknown'}' on provider '${providerId}' refused a request that held an image, so images are left out of its requests. They stay in the conversation and are sent again to a model that reads them.`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
106
174
|
/**
|
|
107
175
|
* The previous iteration held a `stopWhen` decision open for a worker.
|
|
108
176
|
*
|
|
@@ -330,16 +398,19 @@ export class IterationOrchestrator {
|
|
|
330
398
|
// paused it. Taken after the intent above is known, so the
|
|
331
399
|
// checkpoint names the message the turn is answering.
|
|
332
400
|
await this.ctx.checkpointMgr.markLoopStart?.(recorder);
|
|
333
|
-
//
|
|
401
|
+
// Context-overflow relief is a two-rung ladder per *stuck point*, not per
|
|
402
|
+
// turn, as in the reference terminal (at most two reactive compactions per
|
|
403
|
+
// overflow): the first relief, then one deeper pass if the retry still
|
|
404
|
+
// overflows.
|
|
334
405
|
//
|
|
335
|
-
// The
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
let
|
|
406
|
+
// The limit exists so that an overflow that survives both rungs — an
|
|
407
|
+
// irreducible prompt — stops instead of looping. It was never meant to
|
|
408
|
+
// disarm the mechanism for the rest of the turn, which is what a
|
|
409
|
+
// turn-scoped flag did: one relief at iteration 3 left iteration 40 to die
|
|
410
|
+
// on an overflow with obvious moves left. The count is cleared by a turn
|
|
411
|
+
// that actually succeeded, which is the evidence that the turn is no
|
|
412
|
+
// longer stuck.
|
|
413
|
+
let overflowReliefs = 0;
|
|
343
414
|
// The output cap a provider told us fits beside this prompt. One request's
|
|
344
415
|
// worth: it is cleared by a call that went through.
|
|
345
416
|
let outputCapOverride;
|
|
@@ -662,7 +733,7 @@ export class IterationOrchestrator {
|
|
|
662
733
|
if (step.context)
|
|
663
734
|
requestHistory.push(stepContextMessage(step.context));
|
|
664
735
|
const messages = projectRequestRichContent(this.projectObservations(requestHistory), this.ctx.turnConfig.maxRequestRichContentBytes ??
|
|
665
|
-
DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES);
|
|
736
|
+
DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES, { imagesReadable: this.modelReadsImages(stepModel) });
|
|
666
737
|
appendWorkContext(shaping, messages, iterationNum, step);
|
|
667
738
|
if (closingDirective)
|
|
668
739
|
messages.push(closingDirective);
|
|
@@ -814,6 +885,8 @@ export class IterationOrchestrator {
|
|
|
814
885
|
signal: this.ctx.abortController.signal,
|
|
815
886
|
}, this.ctx.emitEvent, this.ctx.drainPending, recorder.turnId, iterationNum, forceFinalize, this.ctx.log, iterSpan, stepMessageId, {
|
|
816
887
|
onAccepted: (identity) => this.acceptProviderRejectedImage(identity),
|
|
888
|
+
textOnly: this.textOnlyRecovery(stepModel),
|
|
889
|
+
repair: this.requestRepair,
|
|
817
890
|
}, Boolean(this.ctx.reviewAnswer || this.ctx.structuredOutput?.review || this.ctx.advisoryCtx), recorder.sessionId);
|
|
818
891
|
stepResponse = response;
|
|
819
892
|
const reviewRequest = {
|
|
@@ -859,7 +932,8 @@ export class IterationOrchestrator {
|
|
|
859
932
|
});
|
|
860
933
|
// The turn went through, so the turn is not sitting on an
|
|
861
934
|
// irreducible prompt any more. Re-arm relief for the next one.
|
|
862
|
-
|
|
935
|
+
overflowReliefs = 0;
|
|
936
|
+
clearCompactionErrorNote(this.ctx);
|
|
863
937
|
outputCapOverride = undefined;
|
|
864
938
|
if (response.finishReason !== 'length')
|
|
865
939
|
this.outputContinuations = 0;
|
|
@@ -1591,6 +1665,12 @@ export class IterationOrchestrator {
|
|
|
1591
1665
|
}
|
|
1592
1666
|
catch (err) {
|
|
1593
1667
|
const cancelled = this.ctx.abortController.signal.aborted;
|
|
1668
|
+
// A deferred sandbox that was cancelled or ran out of time. The
|
|
1669
|
+
// turn settles it as `cancelled` / `timeout` in `query()`, which is
|
|
1670
|
+
// not a failure of this iteration: it is recorded the way a turn
|
|
1671
|
+
// stopped by its own abort or timeout is (a cancelled step, no
|
|
1672
|
+
// error span), so the ledger and the stop reason agree.
|
|
1673
|
+
const sandboxStopped = err instanceof SandboxAcquisitionStopped;
|
|
1594
1674
|
// This iteration gets a step too, and it is the one the
|
|
1595
1675
|
// argument three hundred lines above was actually about.
|
|
1596
1676
|
//
|
|
@@ -1651,7 +1731,7 @@ export class IterationOrchestrator {
|
|
|
1651
1731
|
startedAt: stepStartedAt,
|
|
1652
1732
|
usageBefore,
|
|
1653
1733
|
costBefore,
|
|
1654
|
-
unfinished: cancelled
|
|
1734
|
+
unfinished: cancelled || sandboxStopped
|
|
1655
1735
|
? { finishReason: 'cancelled' }
|
|
1656
1736
|
: {
|
|
1657
1737
|
finishReason: 'error',
|
|
@@ -1706,21 +1786,59 @@ export class IterationOrchestrator {
|
|
|
1706
1786
|
continue;
|
|
1707
1787
|
}
|
|
1708
1788
|
}
|
|
1709
|
-
if (!
|
|
1710
|
-
!(err instanceof AnswerReviewFailure) &&
|
|
1789
|
+
if (!(err instanceof AnswerReviewFailure) &&
|
|
1711
1790
|
classifyProviderError(err, this.ctx.provider.id).code === 'context_length_exceeded') {
|
|
1712
|
-
|
|
1713
|
-
|
|
1791
|
+
// The rapid-refill check comes first, before the first reactive relief
|
|
1792
|
+
// of an overflow, as in the reference terminal. A relief that follows
|
|
1793
|
+
// the previous compaction within the refill window counts toward the
|
|
1794
|
+
// limit, so a tool that re-fills the window every time it is called
|
|
1795
|
+
// stops the turn instead of being cleared and called again without end.
|
|
1796
|
+
// The deeper rung of the same overflow is not counted again.
|
|
1797
|
+
if (overflowReliefs === 0 && (await stopOnRefill(this.ctx))) {
|
|
1798
|
+
if (iterationActivity) {
|
|
1799
|
+
this.ctx.activityStore.fail(iterationActivity.id, toErrorMessage(err));
|
|
1800
|
+
}
|
|
1801
|
+
if (this.stopForCompactionBreaker())
|
|
1802
|
+
break;
|
|
1803
|
+
}
|
|
1804
|
+
// A rung that sheds too little to change the verdict is not worth a
|
|
1805
|
+
// provider call; climb to the next one at once.
|
|
1806
|
+
let shed = false;
|
|
1807
|
+
while (!shed && overflowReliefs < OVERFLOW_RELIEF_LIMIT) {
|
|
1808
|
+
overflowReliefs++;
|
|
1809
|
+
shed = await relieveOverflow(this.ctx, { deeper: overflowReliefs > 1 });
|
|
1810
|
+
}
|
|
1714
1811
|
if (shed) {
|
|
1812
|
+
// Clearing results is a compaction too: only summaries and reducers
|
|
1813
|
+
// recorded themselves, so a clear-only relief was invisible to the
|
|
1814
|
+
// breaker.
|
|
1815
|
+
compactionBreaker(this.ctx)?.recordCompaction(iterationNum);
|
|
1715
1816
|
this.ctx.log.info('Retrying the turn after relieving a context overflow', {
|
|
1716
1817
|
[NAMZU.TURN_ID]: recorder.turnId,
|
|
1717
1818
|
[NAMZU.ITERATION]: iterationNum,
|
|
1819
|
+
'namzu.runtime.relief_rung': overflowReliefs,
|
|
1718
1820
|
});
|
|
1719
1821
|
if (iterationActivity) {
|
|
1720
1822
|
this.ctx.activityStore.complete(iterationActivity.id);
|
|
1721
1823
|
}
|
|
1722
1824
|
continue;
|
|
1723
1825
|
}
|
|
1826
|
+
// Out of rungs. The conversation is kept; say why compaction could not
|
|
1827
|
+
// make room when it errored, as the reference does.
|
|
1828
|
+
const cause = compactionErrorNote(this.ctx);
|
|
1829
|
+
if (cause !== undefined && err instanceof Error) {
|
|
1830
|
+
try {
|
|
1831
|
+
err.message = `${err.message}${AUTOMATIC_COMPACTION_FAILED}${cause}`;
|
|
1832
|
+
}
|
|
1833
|
+
catch {
|
|
1834
|
+
// A frozen error keeps its own message; the cause stays in the log.
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
if (sandboxStopped) {
|
|
1839
|
+
if (iterationActivity)
|
|
1840
|
+
this.ctx.activityStore.complete(iterationActivity.id);
|
|
1841
|
+
throw err;
|
|
1724
1842
|
}
|
|
1725
1843
|
if (iterationActivity) {
|
|
1726
1844
|
this.ctx.activityStore.fail(iterationActivity.id, toErrorMessage(err));
|
|
@@ -2257,6 +2375,31 @@ export class IterationOrchestrator {
|
|
|
2257
2375
|
.listTasks()
|
|
2258
2376
|
.some((t) => t.state !== 'completed' && t.state !== 'failed' && t.state !== 'canceled');
|
|
2259
2377
|
}
|
|
2378
|
+
/** Media the provider could not process was left out of a request that then went through. */
|
|
2379
|
+
async noteMediaRemoved(removal) {
|
|
2380
|
+
this.ctx.log.warn('Media the provider rejected was left out of the request', {
|
|
2381
|
+
[GENAI.SYSTEM]: this.ctx.provider.id,
|
|
2382
|
+
'namzu.request.media_removed': removal.count,
|
|
2383
|
+
});
|
|
2384
|
+
const noun = removal.count === 1 ? 'a file' : `${removal.count} files`;
|
|
2385
|
+
const it = removal.count === 1 ? 'it' : 'they';
|
|
2386
|
+
await this.ctx.emitEvent?.({
|
|
2387
|
+
type: 'capability_warning',
|
|
2388
|
+
turnId: this.ctx.recorder.turnId,
|
|
2389
|
+
capability: removal.kind === 'document' ? 'documents' : 'vision',
|
|
2390
|
+
// The person's own latest attachment is named as such; a count limit is
|
|
2391
|
+
// not a fault in any file.
|
|
2392
|
+
contentSource: removal.current
|
|
2393
|
+
? 'media-removed-current'
|
|
2394
|
+
: removal.limit
|
|
2395
|
+
? 'media-limit'
|
|
2396
|
+
: 'media-removed',
|
|
2397
|
+
providerId: this.ctx.provider.id,
|
|
2398
|
+
message: removal.limit
|
|
2399
|
+
? `The conversation holds more files than the provider accepts at once, so ${noun} (the oldest) ${removal.count === 1 ? 'was' : 'were'} left out of the request. The conversation still holds ${it}.`
|
|
2400
|
+
: `The provider could not process ${noun}${removal.current ? ' attached to your latest message' : ' in this conversation'}, so ${it} ${removal.count === 1 ? 'was' : 'were'} left out of the request. The conversation still holds ${it}.`,
|
|
2401
|
+
});
|
|
2402
|
+
}
|
|
2260
2403
|
async acceptProviderRejectedImage(identity) {
|
|
2261
2404
|
const repaired = markProviderRejectedImage(this.ctx.recorder.messages, identity);
|
|
2262
2405
|
if (repaired.count === 0) {
|
|
@@ -2301,7 +2444,7 @@ export class IterationOrchestrator {
|
|
|
2301
2444
|
...workingMemory.history,
|
|
2302
2445
|
...(workingMemory.context ? [workingMemory.context] : []),
|
|
2303
2446
|
];
|
|
2304
|
-
const finalMessages = projectRequestRichContent(this.projectObservations(finalHistory), this.ctx.turnConfig.maxRequestRichContentBytes ?? DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES);
|
|
2447
|
+
const finalMessages = projectRequestRichContent(this.projectObservations(finalHistory), this.ctx.turnConfig.maxRequestRichContentBytes ?? DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES, { imagesReadable: this.modelReadsImages(model) });
|
|
2305
2448
|
appendWorkContext(this.stepShaping(), finalMessages, this.steps.length + 1, { model });
|
|
2306
2449
|
// The closing directive is the last thing the model reads: after
|
|
2307
2450
|
// the working memory and any work context above.
|
|
@@ -2340,7 +2483,7 @@ export class IterationOrchestrator {
|
|
|
2340
2483
|
// stream to completion.
|
|
2341
2484
|
signal: this.ctx.abortController.signal,
|
|
2342
2485
|
};
|
|
2343
|
-
const response = await collectChatCompletion(streamWithProviderRejectedImageRecovery(this.ctx.provider, finalParams, (identity) => this.acceptProviderRejectedImage(identity)));
|
|
2486
|
+
const response = await collectChatCompletion(streamWithProviderRejectedImageRecovery(this.ctx.provider, finalParams, (identity) => this.acceptProviderRejectedImage(identity), undefined, this.textOnlyRecovery(model), this.requestRepair));
|
|
2344
2487
|
const servingMember = this.ctx.servingMember?.() ?? requestedMember;
|
|
2345
2488
|
const servedBy = {
|
|
2346
2489
|
providerId: servingMember.providerId,
|