@deepagents/context 0.35.0 → 0.36.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/dist/index.js CHANGED
@@ -83,22 +83,6 @@ function assistantText(content, options) {
83
83
  parts: [{ type: "text", text: content }]
84
84
  });
85
85
  }
86
- var LAZY_ID = Symbol.for("@deepagents/context:lazy-id");
87
- function isLazyFragment(fragment2) {
88
- return LAZY_ID in fragment2;
89
- }
90
- function lastAssistantMessage(content) {
91
- return {
92
- name: "assistant",
93
- type: "message",
94
- persist: true,
95
- data: "content",
96
- [LAZY_ID]: {
97
- type: "last-assistant",
98
- content
99
- }
100
- };
101
- }
102
86
 
103
87
  // packages/context/src/lib/guardrail.ts
104
88
  function pass(part) {
@@ -149,6 +133,7 @@ var Agent = class _Agent {
149
133
  return generateText({
150
134
  abortSignal: config?.abortSignal,
151
135
  providerOptions: this.#options.providerOptions,
136
+ experimental_telemetry: this.#options.experimental_telemetry,
152
137
  model: this.#options.model,
153
138
  system: systemPrompt,
154
139
  messages: await convertToModelMessages(messages, {
@@ -157,7 +142,10 @@ var Agent = class _Agent {
157
142
  stopWhen: stepCountIs(200),
158
143
  tools: this.#options.tools,
159
144
  experimental_context: contextVariables,
160
- experimental_repairToolCall: createRepairToolCall(this.#options.model),
145
+ experimental_repairToolCall: createRepairToolCall(
146
+ this.#options.model,
147
+ config?.abortSignal
148
+ ),
161
149
  toolChoice: this.#options.toolChoice,
162
150
  onStepFinish: (step) => {
163
151
  const toolCall = step.toolCalls.at(-1);
@@ -218,12 +206,16 @@ var Agent = class _Agent {
218
206
  return streamText({
219
207
  abortSignal: config?.abortSignal,
220
208
  providerOptions: this.#options.providerOptions,
209
+ experimental_telemetry: this.#options.experimental_telemetry,
221
210
  model,
222
211
  system: systemPrompt,
223
212
  messages: await convertToModelMessages(messages, {
224
213
  ignoreIncompleteToolCalls: true
225
214
  }),
226
- experimental_repairToolCall: createRepairToolCall(model),
215
+ experimental_repairToolCall: createRepairToolCall(
216
+ model,
217
+ config?.abortSignal
218
+ ),
227
219
  stopWhen: stepCountIs(200),
228
220
  experimental_transform: config?.transform ?? smoothStream(),
229
221
  tools: this.#options.tools,
@@ -243,8 +235,8 @@ var Agent = class _Agent {
243
235
  * Wrap a StreamTextResult with guardrail protection on toUIMessageStream().
244
236
  *
245
237
  * When a guardrail fails:
246
- * 1. Accumulated text + feedback is appended as the assistant's self-correction
247
- * 2. The feedback is written to the output stream (user sees the correction)
238
+ * 1. The feedback is written to the output stream (user sees the correction)
239
+ * 2. A finish-step is emitted, triggering onStepFinish to persist the self-correction
248
240
  * 3. A new stream is started and the model continues from the correction
249
241
  */
250
242
  #wrapWithGuardrails(result, contextVariables, config) {
@@ -255,8 +247,18 @@ var Agent = class _Agent {
255
247
  }
256
248
  const originalToUIMessageStream = result.toUIMessageStream.bind(result);
257
249
  result.toUIMessageStream = (options) => {
250
+ const assistantMsgId = options?.generateMessageId?.();
251
+ let stepSaved = null;
258
252
  return createUIMessageStream({
259
- generateId: generateId2,
253
+ generateId: assistantMsgId ? () => assistantMsgId : generateId2,
254
+ onStepFinish: async ({ responseMessage }) => {
255
+ if (!stepSaved) return;
256
+ const normalizedMessage = assistantMsgId ? { ...responseMessage, id: assistantMsgId } : responseMessage;
257
+ context.set(assistant(normalizedMessage));
258
+ await context.save({ branch: false });
259
+ stepSaved.resolve();
260
+ stepSaved = null;
261
+ },
260
262
  execute: async ({ writer }) => {
261
263
  let currentResult = result;
262
264
  let attempt = 0;
@@ -271,7 +273,6 @@ var Agent = class _Agent {
271
273
  return;
272
274
  }
273
275
  attempt++;
274
- let accumulatedText = "";
275
276
  let guardrailFailed = false;
276
277
  let failureFeedback = "";
277
278
  const uiStream = currentResult === result ? originalToUIMessageStream(options) : currentResult.toUIMessageStream(options);
@@ -301,9 +302,6 @@ var Agent = class _Agent {
301
302
  writer.write({ type: "finish" });
302
303
  return;
303
304
  }
304
- if (checkResult.part.type === "text-delta") {
305
- accumulatedText += checkResult.part.delta;
306
- }
307
305
  writer.write(part);
308
306
  }
309
307
  if (!guardrailFailed) {
@@ -320,9 +318,9 @@ var Agent = class _Agent {
320
318
  return;
321
319
  }
322
320
  writeText(writer, failureFeedback);
323
- const selfCorrectionText = accumulatedText + " " + failureFeedback;
324
- context.set(lastAssistantMessage(selfCorrectionText));
325
- await context.save({ branch: false });
321
+ stepSaved = Promise.withResolvers();
322
+ writer.write({ type: "finish-step" });
323
+ await stepSaved.promise;
326
324
  currentResult = await this.#createRawStream(
327
325
  contextVariables,
328
326
  config
@@ -362,13 +360,17 @@ function structuredOutput(options) {
362
360
  const result = await generateText({
363
361
  abortSignal: config?.abortSignal,
364
362
  providerOptions: options.providerOptions,
363
+ experimental_telemetry: options.experimental_telemetry,
365
364
  model: options.model,
366
365
  system: systemPrompt,
367
366
  messages: await convertToModelMessages(messages, {
368
367
  ignoreIncompleteToolCalls: true
369
368
  }),
370
369
  stopWhen: stepCountIs(200),
371
- experimental_repairToolCall: createRepairToolCall(options.model),
370
+ experimental_repairToolCall: createRepairToolCall(
371
+ options.model,
372
+ config?.abortSignal
373
+ ),
372
374
  experimental_context: contextVariables,
373
375
  output: Output.object({ schema: options.schema }),
374
376
  tools: options.tools
@@ -388,9 +390,13 @@ function structuredOutput(options) {
388
390
  return streamText({
389
391
  abortSignal: config?.abortSignal,
390
392
  providerOptions: options.providerOptions,
393
+ experimental_telemetry: options.experimental_telemetry,
391
394
  model: options.model,
392
395
  system: systemPrompt,
393
- experimental_repairToolCall: createRepairToolCall(options.model),
396
+ experimental_repairToolCall: createRepairToolCall(
397
+ options.model,
398
+ config?.abortSignal
399
+ ),
394
400
  messages: await convertToModelMessages(messages, {
395
401
  ignoreIncompleteToolCalls: true
396
402
  }),
@@ -1999,7 +2005,7 @@ var ContextEngine = class {
1999
2005
  let messageCount = 0;
2000
2006
  let lastMessageAt;
2001
2007
  let lastMessage;
2002
- let lastAssistantMessage2;
2008
+ let lastAssistantMessage;
2003
2009
  if (this.#branch?.headMessageId) {
2004
2010
  const chain = await this.#store.getMessageChain(
2005
2011
  this.#branch.headMessageId
@@ -2007,7 +2013,7 @@ var ContextEngine = class {
2007
2013
  for (const msg of chain) {
2008
2014
  messageCount++;
2009
2015
  if (msg.name === "assistant") {
2010
- lastAssistantMessage2 = msg.data;
2016
+ lastAssistantMessage = msg.data;
2011
2017
  }
2012
2018
  if (msg.name !== "user") {
2013
2019
  continue;
@@ -2026,7 +2032,7 @@ var ContextEngine = class {
2026
2032
  messageCount,
2027
2033
  lastMessageAt,
2028
2034
  lastMessage,
2029
- lastAssistantMessage: lastAssistantMessage2
2035
+ lastAssistantMessage
2030
2036
  };
2031
2037
  }
2032
2038
  async getTurnCount() {
@@ -2088,17 +2094,9 @@ var ContextEngine = class {
2088
2094
  messages.push(msg.data);
2089
2095
  }
2090
2096
  }
2091
- for (let i = 0; i < this.#pendingMessages.length; i++) {
2092
- const fragment2 = this.#pendingMessages[i];
2093
- if (isLazyFragment(fragment2)) {
2094
- this.#pendingMessages[i] = await this.#resolveLazyFragment(fragment2);
2095
- }
2096
- }
2097
2097
  for (const fragment2 of this.#pendingMessages) {
2098
2098
  if (!fragment2.codec) {
2099
- throw new Error(
2100
- `Fragment "${fragment2.name}" is missing codec. Lazy fragments must be resolved before encode.`
2101
- );
2099
+ throw new Error(`Fragment "${fragment2.name}" is missing codec.`);
2102
2100
  }
2103
2101
  messages.push(fragment2.codec.encode());
2104
2102
  }
@@ -2127,12 +2125,6 @@ var ContextEngine = class {
2127
2125
  return { headMessageId: this.#branch?.headMessageId ?? void 0 };
2128
2126
  }
2129
2127
  const shouldBranch = options?.branch ?? true;
2130
- for (let i = 0; i < this.#pendingMessages.length; i++) {
2131
- const fragment2 = this.#pendingMessages[i];
2132
- if (isLazyFragment(fragment2)) {
2133
- this.#pendingMessages[i] = await this.#resolveLazyFragment(fragment2);
2134
- }
2135
- }
2136
2128
  if (shouldBranch) {
2137
2129
  for (const fragment2 of this.#pendingMessages) {
2138
2130
  if (fragment2.id) {
@@ -2162,7 +2154,7 @@ var ContextEngine = class {
2162
2154
  messageCount,
2163
2155
  lastMessageAt,
2164
2156
  lastMessage,
2165
- lastAssistantMessage: lastAssistantMessage2
2157
+ lastAssistantMessage
2166
2158
  } = await this.#getChainContext();
2167
2159
  const original = lastUserFragment.codec.encode();
2168
2160
  const plainText = extractPlainText(original);
@@ -2179,7 +2171,7 @@ var ContextEngine = class {
2179
2171
  branch: this.#branchName,
2180
2172
  elapsed,
2181
2173
  messageCount,
2182
- lastAssistantMessage: lastAssistantMessage2
2174
+ lastAssistantMessage
2183
2175
  };
2184
2176
  const configs = conditionalReminders.map(getConditionalReminder);
2185
2177
  const whenResults = await Promise.all(
@@ -2211,9 +2203,7 @@ var ContextEngine = class {
2211
2203
  const now = Date.now();
2212
2204
  for (const fragment2 of this.#pendingMessages) {
2213
2205
  if (!fragment2.codec) {
2214
- throw new Error(
2215
- `Fragment "${fragment2.name}" is missing codec. Lazy fragments must be resolved before encode.`
2216
- );
2206
+ throw new Error(`Fragment "${fragment2.name}" is missing codec.`);
2217
2207
  }
2218
2208
  const msgId = fragment2.id ?? crypto.randomUUID();
2219
2209
  let msgParentId = parentId;
@@ -2240,39 +2230,6 @@ var ContextEngine = class {
2240
2230
  this.#pendingMessages = [];
2241
2231
  return { headMessageId: this.#activeBranch.headMessageId ?? void 0 };
2242
2232
  }
2243
- /**
2244
- * Resolve a lazy fragment by finding the appropriate ID.
2245
- */
2246
- async #resolveLazyFragment(fragment2) {
2247
- const lazy = fragment2[LAZY_ID];
2248
- if (lazy.type === "last-assistant") {
2249
- const lastId = await this.#getLastAssistantId();
2250
- return assistantText(lazy.content, { id: lastId ?? crypto.randomUUID() });
2251
- }
2252
- throw new Error(`Unknown lazy fragment type: ${lazy.type}`);
2253
- }
2254
- /**
2255
- * Find the most recent assistant message ID (pending or persisted).
2256
- */
2257
- async #getLastAssistantId() {
2258
- for (let i = this.#pendingMessages.length - 1; i >= 0; i--) {
2259
- const msg = this.#pendingMessages[i];
2260
- if (msg.name === "assistant" && !isLazyFragment(msg)) {
2261
- return msg.id;
2262
- }
2263
- }
2264
- if (this.#branch?.headMessageId) {
2265
- const chain = await this.#store.getMessageChain(
2266
- this.#branch.headMessageId
2267
- );
2268
- for (let i = chain.length - 1; i >= 0; i--) {
2269
- if (chain[i].name === "assistant") {
2270
- return chain[i].id;
2271
- }
2272
- }
2273
- }
2274
- return void 0;
2275
- }
2276
2233
  /**
2277
2234
  * Estimate token count and cost for the full context.
2278
2235
  *
@@ -7965,7 +7922,6 @@ export {
7965
7922
  DockerfileBuildError,
7966
7923
  DockerfileStrategy,
7967
7924
  InMemoryContextStore,
7968
- LAZY_ID,
7969
7925
  MarkdownRenderer,
7970
7926
  ModelsRegistry,
7971
7927
  MountPathError,
@@ -8033,10 +7989,8 @@ export {
8033
7989
  isDockerfileOptions,
8034
7990
  isFragment,
8035
7991
  isFragmentObject,
8036
- isLazyFragment,
8037
7992
  isMessageFragment,
8038
7993
  isRecord,
8039
- lastAssistantMessage,
8040
7994
  loadSkillMetadata,
8041
7995
  localeReminder,
8042
7996
  mergeMessageMetadata,