@deepagents/context 0.30.0 → 0.32.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.
Files changed (41) hide show
  1. package/dist/browser.js +41 -7
  2. package/dist/browser.js.map +2 -2
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +478 -73
  6. package/dist/index.js.map +4 -4
  7. package/dist/lib/engine.d.ts +0 -6
  8. package/dist/lib/engine.d.ts.map +1 -1
  9. package/dist/lib/fragments/message/environment-reminder.d.ts +26 -0
  10. package/dist/lib/fragments/message/environment-reminder.d.ts.map +1 -0
  11. package/dist/lib/fragments/message/user.d.ts +15 -1
  12. package/dist/lib/fragments/message/user.d.ts.map +1 -1
  13. package/dist/lib/fragments/socratic.d.ts +21 -0
  14. package/dist/lib/fragments/socratic.d.ts.map +1 -0
  15. package/dist/lib/sandbox/agent-os-sandbox.d.ts +84 -0
  16. package/dist/lib/sandbox/agent-os-sandbox.d.ts.map +1 -0
  17. package/dist/lib/sandbox/container-tool.d.ts +3 -1
  18. package/dist/lib/sandbox/container-tool.d.ts.map +1 -1
  19. package/dist/lib/sandbox/docker-sandbox.d.ts +8 -3
  20. package/dist/lib/sandbox/docker-sandbox.d.ts.map +1 -1
  21. package/dist/lib/sandbox/index.d.ts +2 -1
  22. package/dist/lib/sandbox/index.d.ts.map +1 -1
  23. package/dist/lib/tracing/batch-processor.d.ts +19 -0
  24. package/dist/lib/tracing/batch-processor.d.ts.map +1 -0
  25. package/dist/lib/tracing/exporter.d.ts +22 -0
  26. package/dist/lib/tracing/exporter.d.ts.map +1 -0
  27. package/dist/lib/tracing/ids.d.ts +4 -0
  28. package/dist/lib/tracing/ids.d.ts.map +1 -0
  29. package/dist/lib/tracing/index.d.ts +7 -0
  30. package/dist/lib/tracing/index.d.ts.map +1 -0
  31. package/dist/lib/tracing/index.js +661 -0
  32. package/dist/lib/tracing/index.js.map +7 -0
  33. package/dist/lib/tracing/openai-traces-integration.d.ts +20 -0
  34. package/dist/lib/tracing/openai-traces-integration.d.ts.map +1 -0
  35. package/dist/lib/tracing/processor.d.ts +26 -0
  36. package/dist/lib/tracing/processor.d.ts.map +1 -0
  37. package/dist/lib/tracing/serialization.d.ts +7 -0
  38. package/dist/lib/tracing/serialization.d.ts.map +1 -0
  39. package/dist/lib/tracing/types.d.ts +90 -0
  40. package/dist/lib/tracing/types.d.ts.map +1 -0
  41. package/package.json +18 -5
package/dist/index.js CHANGED
@@ -426,7 +426,7 @@ import {
426
426
  import { z } from "zod";
427
427
 
428
428
  // packages/context/src/lib/engine.ts
429
- import { isTextUIPart as isTextUIPart2, validateUIMessages } from "ai";
429
+ import { validateUIMessages } from "ai";
430
430
  import { mergeWith } from "lodash-es";
431
431
 
432
432
  // packages/context/src/lib/estimate.ts
@@ -753,14 +753,45 @@ function applyPartReminder(message2, value) {
753
753
  };
754
754
  }
755
755
  function resolveReminderText(item, ctx) {
756
- return typeof item.text === "function" ? item.text(ctx) : item.text;
756
+ return resolveReminder(item, ctx)?.text ?? "";
757
+ }
758
+ function normalizeReminderResolution(value) {
759
+ if (typeof value === "string") {
760
+ return value.trim().length === 0 ? null : { text: value };
761
+ }
762
+ if (value.text.trim().length === 0) {
763
+ return null;
764
+ }
765
+ return value;
766
+ }
767
+ function resolveReminder(item, ctx) {
768
+ const resolvedText = typeof item.text === "function" ? item.text(ctx) : item.text;
769
+ const resolved = normalizeReminderResolution(resolvedText);
770
+ if (!resolved) {
771
+ return null;
772
+ }
773
+ const metadata = item.metadata || resolved.metadata ? {
774
+ ...item.metadata ?? {},
775
+ ...resolved.metadata ?? {}
776
+ } : void 0;
777
+ return metadata ? { ...resolved, metadata } : resolved;
778
+ }
779
+ function mergeMessageMetadata(message2, addedMetadata) {
780
+ if (Object.keys(addedMetadata).length === 0) {
781
+ return;
782
+ }
783
+ const metadata = isRecord(message2.metadata) ? { ...message2.metadata } : {};
784
+ message2.metadata = { ...metadata, ...addedMetadata };
757
785
  }
758
786
  function applyReminderToMessage(message2, item, ctx) {
759
- const resolvedText = resolveReminderText(item, ctx);
760
- if (resolvedText.trim().length === 0) {
787
+ const resolved = resolveReminder(item, ctx);
788
+ if (!resolved) {
761
789
  return null;
762
790
  }
763
- return item.asPart ? applyPartReminder(message2, resolvedText) : applyInlineReminder(message2, resolvedText);
791
+ if (resolved.metadata) {
792
+ mergeMessageMetadata(message2, resolved.metadata);
793
+ }
794
+ return item.asPart ? applyPartReminder(message2, resolved.text) : applyInlineReminder(message2, resolved.text);
764
795
  }
765
796
  function mergeReminderMetadata(message2, addedReminders) {
766
797
  if (addedReminders.length === 0) return;
@@ -798,14 +829,14 @@ function user(content, ...reminders) {
798
829
  } : { ...content, role: "user", parts: [...content.parts] };
799
830
  if (reminders.length > 0) {
800
831
  const plainText = extractPlainText(message2);
801
- const addedReminders = [];
832
+ const added = [];
802
833
  for (const item of reminders) {
803
834
  const meta = applyReminderToMessage(message2, item, {
804
835
  content: plainText
805
836
  });
806
- if (meta) addedReminders.push(meta);
837
+ if (meta) added.push(meta);
807
838
  }
808
- mergeReminderMetadata(message2, addedReminders);
839
+ mergeReminderMetadata(message2, added);
809
840
  }
810
841
  return {
811
842
  id: message2.id,
@@ -1721,6 +1752,14 @@ var ContextEngine = class {
1721
1752
  #initialized = false;
1722
1753
  /** Initial metadata to merge on first initialization */
1723
1754
  #initialMetadata;
1755
+ get #activeBranch() {
1756
+ if (!this.#branch) {
1757
+ throw new Error(
1758
+ "Branch not initialized. Call #ensureInitialized() first."
1759
+ );
1760
+ }
1761
+ return this.#branch;
1762
+ }
1724
1763
  get #renderableFragments() {
1725
1764
  return this.#fragments.filter((f) => !isConditionalReminder(f));
1726
1765
  }
@@ -1757,7 +1796,13 @@ var ContextEngine = class {
1757
1796
  });
1758
1797
  this.#initialMetadata = void 0;
1759
1798
  }
1760
- this.#branch = await this.#store.getActiveBranch(this.#chatId);
1799
+ const branch = await this.#store.getActiveBranch(this.#chatId);
1800
+ if (!branch) {
1801
+ throw new Error(
1802
+ `Active branch not found for chat "${this.#chatId}" after upsertChat`
1803
+ );
1804
+ }
1805
+ this.#branch = branch;
1761
1806
  this.#initialized = true;
1762
1807
  }
1763
1808
  /**
@@ -1841,30 +1886,35 @@ var ContextEngine = class {
1841
1886
  };
1842
1887
  }
1843
1888
  /**
1844
- * Count user+assistant message pairs (turns) in the conversation.
1845
- * Includes persisted messages and pending messages.
1846
- * A turn is one user message paired with one assistant message.
1847
- * An unpaired trailing user message counts as the next turn.
1889
+ * Count user turns in the conversation and return the previous saved user message context.
1890
+ * Includes persisted messages and pending messages in the turn count.
1848
1891
  */
1849
- async getTurnCount() {
1892
+ async #getChainContext() {
1850
1893
  await this.#ensureInitialized();
1851
- let userCount = 0;
1894
+ let turn = 0;
1895
+ let lastMessageAt;
1896
+ let lastMessage;
1852
1897
  if (this.#branch?.headMessageId) {
1853
1898
  const chain = await this.#store.getMessageChain(
1854
1899
  this.#branch.headMessageId
1855
1900
  );
1856
1901
  for (const msg of chain) {
1857
- if (msg.name === "user") {
1858
- userCount++;
1902
+ if (msg.name !== "user") {
1903
+ continue;
1859
1904
  }
1905
+ turn++;
1906
+ lastMessageAt = msg.createdAt;
1907
+ lastMessage = msg.data;
1860
1908
  }
1861
1909
  }
1862
1910
  for (const fragment2 of this.#pendingMessages) {
1863
- if (fragment2.name === "user") {
1864
- userCount++;
1865
- }
1911
+ if (fragment2.name === "user") turn++;
1866
1912
  }
1867
- return userCount;
1913
+ return { turn, lastMessageAt, lastMessage };
1914
+ }
1915
+ async getTurnCount() {
1916
+ const { turn } = await this.#getChainContext();
1917
+ return turn;
1868
1918
  }
1869
1919
  /**
1870
1920
  * Add fragments to the context.
@@ -1935,37 +1985,6 @@ var ContextEngine = class {
1935
1985
  }
1936
1986
  messages.push(fragment2.codec.encode());
1937
1987
  }
1938
- const conditionalReminders = this.#fragments.filter(isConditionalReminder);
1939
- if (conditionalReminders.length > 0) {
1940
- const turn = await this.getTurnCount();
1941
- let lastUserIndex = -1;
1942
- for (let i = messages.length - 1; i >= 0; i--) {
1943
- if (messages[i].role === "user") {
1944
- lastUserIndex = i;
1945
- break;
1946
- }
1947
- }
1948
- if (lastUserIndex >= 0) {
1949
- const original = messages[lastUserIndex];
1950
- const message2 = {
1951
- ...original,
1952
- parts: [...original.parts]
1953
- };
1954
- const plainText = message2.parts.filter(isTextUIPart2).map((p) => p.text).join(" ");
1955
- const addedReminders = [];
1956
- for (const fragment2 of conditionalReminders) {
1957
- const config = getConditionalReminder(fragment2);
1958
- if (!config.when(turn)) continue;
1959
- const meta = applyReminderToMessage(message2, config, {
1960
- content: plainText,
1961
- turn
1962
- });
1963
- if (meta) addedReminders.push(meta);
1964
- }
1965
- mergeReminderMetadata(message2, addedReminders);
1966
- messages[lastUserIndex] = message2;
1967
- }
1968
- }
1969
1988
  return {
1970
1989
  systemPrompt,
1971
1990
  messages: messages.length === 0 ? [] : await validateUIMessages({ messages })
@@ -2009,7 +2028,49 @@ var ContextEngine = class {
2009
2028
  }
2010
2029
  }
2011
2030
  }
2012
- let parentId = this.#branch.headMessageId;
2031
+ const conditionalReminders = this.#fragments.filter(isConditionalReminder);
2032
+ if (conditionalReminders.length > 0) {
2033
+ let lastUserIndex = -1;
2034
+ for (let i = this.#pendingMessages.length - 1; i >= 0; i--) {
2035
+ if (this.#pendingMessages[i].name === "user") {
2036
+ lastUserIndex = i;
2037
+ break;
2038
+ }
2039
+ }
2040
+ if (lastUserIndex >= 0) {
2041
+ const lastUserFragment = this.#pendingMessages[lastUserIndex];
2042
+ if (lastUserFragment.codec) {
2043
+ const { turn, lastMessageAt, lastMessage } = await this.#getChainContext();
2044
+ const firedReminders = conditionalReminders.map(getConditionalReminder).filter((config) => config.when(turn));
2045
+ if (firedReminders.length > 0) {
2046
+ const original = lastUserFragment.codec.encode();
2047
+ const plainText = extractPlainText(original);
2048
+ const reminders = firedReminders.flatMap((rem) => {
2049
+ const resolved = resolveReminder(rem, {
2050
+ content: plainText,
2051
+ turn,
2052
+ lastMessageAt,
2053
+ lastMessage
2054
+ });
2055
+ if (!resolved) {
2056
+ return [];
2057
+ }
2058
+ return [
2059
+ {
2060
+ text: resolved.text,
2061
+ asPart: rem.asPart,
2062
+ metadata: resolved.metadata
2063
+ }
2064
+ ];
2065
+ });
2066
+ const recreated = user(original, ...reminders);
2067
+ recreated.id = lastUserFragment.id;
2068
+ this.#pendingMessages[lastUserIndex] = recreated;
2069
+ }
2070
+ }
2071
+ }
2072
+ }
2073
+ let parentId = this.#activeBranch.headMessageId;
2013
2074
  const now = Date.now();
2014
2075
  for (const fragment2 of this.#pendingMessages) {
2015
2076
  if (!fragment2.codec) {
@@ -2037,10 +2098,10 @@ var ContextEngine = class {
2037
2098
  await this.#store.addMessage(messageData);
2038
2099
  parentId = messageData.id;
2039
2100
  }
2040
- await this.#store.updateBranchHead(this.#branch.id, parentId);
2041
- this.#branch.headMessageId = parentId;
2101
+ await this.#store.updateBranchHead(this.#activeBranch.id, parentId);
2102
+ this.#activeBranch.headMessageId = parentId;
2042
2103
  this.#pendingMessages = [];
2043
- return { headMessageId: this.#branch.headMessageId ?? void 0 };
2104
+ return { headMessageId: this.#activeBranch.headMessageId ?? void 0 };
2044
2105
  }
2045
2106
  /**
2046
2107
  * Resolve a lazy fragment by finding the appropriate ID.
@@ -3814,6 +3875,159 @@ function fromFragment(fragment2, options) {
3814
3875
  throw new Error(`Fragment "${fragment2.name}" is missing codec`);
3815
3876
  }
3816
3877
 
3878
+ // packages/context/src/lib/fragments/message/environment-reminder.ts
3879
+ var ENVIRONMENT_REMINDER_METADATA_KEY = "environment";
3880
+ function getSeason(month) {
3881
+ if (month >= 2 && month <= 4) return "Spring";
3882
+ if (month >= 5 && month <= 7) return "Summer";
3883
+ if (month >= 8 && month <= 10) return "Fall";
3884
+ return "Winter";
3885
+ }
3886
+ function isRecord2(value) {
3887
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3888
+ }
3889
+ function buildEnvironmentSnapshot(now, options) {
3890
+ const { language, timeZone } = options;
3891
+ const currentDateTime = now.toLocaleString("en-CA", {
3892
+ timeZone,
3893
+ year: "numeric",
3894
+ month: "2-digit",
3895
+ day: "2-digit",
3896
+ hour: "2-digit",
3897
+ minute: "2-digit",
3898
+ second: "2-digit",
3899
+ hour12: false
3900
+ });
3901
+ const dayOfWeek = now.toLocaleString("default", {
3902
+ weekday: "long",
3903
+ timeZone
3904
+ });
3905
+ const month = now.toLocaleString("default", {
3906
+ month: "long",
3907
+ timeZone
3908
+ });
3909
+ const year = parseInt(
3910
+ now.toLocaleString("en-CA", { year: "numeric", timeZone }),
3911
+ 10
3912
+ );
3913
+ const monthIndex = parseInt(now.toLocaleString("en-CA", { month: "numeric", timeZone }), 10) - 1;
3914
+ return {
3915
+ timeZone,
3916
+ language,
3917
+ currentDateTime,
3918
+ dateKey: now.toLocaleDateString("en-CA", { timeZone }),
3919
+ dayOfWeek,
3920
+ month,
3921
+ year,
3922
+ season: getSeason(monthIndex),
3923
+ timestamp: now.getTime()
3924
+ };
3925
+ }
3926
+ function buildEnvironmentBlock(snapshot) {
3927
+ return `TimeZone is always in ${snapshot.timeZone}.
3928
+
3929
+ Current Date & Time: "${snapshot.currentDateTime}"
3930
+ Day of Week: ${snapshot.dayOfWeek}
3931
+ Month: ${snapshot.month}
3932
+ Year: ${snapshot.year}
3933
+ Timestamp: ${snapshot.timestamp}
3934
+ Language: ${snapshot.language}
3935
+ Season: ${snapshot.season}`;
3936
+ }
3937
+ function formatChange(previous, current) {
3938
+ const changes = [];
3939
+ if (previous.timeZone !== current.timeZone) {
3940
+ changes.push(`time zone: ${previous.timeZone} -> ${current.timeZone}`);
3941
+ }
3942
+ if (previous.language !== current.language) {
3943
+ changes.push(`language: ${previous.language} -> ${current.language}`);
3944
+ }
3945
+ if (previous.dateKey !== current.dateKey) {
3946
+ changes.push(`date: ${previous.dateKey} -> ${current.dateKey}`);
3947
+ }
3948
+ if (previous.dayOfWeek !== current.dayOfWeek) {
3949
+ changes.push(`day of week: ${previous.dayOfWeek} -> ${current.dayOfWeek}`);
3950
+ }
3951
+ if (previous.month !== current.month) {
3952
+ changes.push(`month: ${previous.month} -> ${current.month}`);
3953
+ }
3954
+ if (previous.year !== current.year) {
3955
+ changes.push(`year: ${previous.year} -> ${current.year}`);
3956
+ }
3957
+ if (previous.season !== current.season) {
3958
+ changes.push(`season: ${previous.season} -> ${current.season}`);
3959
+ }
3960
+ return changes;
3961
+ }
3962
+ function buildChangeSummary(previous, current) {
3963
+ if (!previous) {
3964
+ return "";
3965
+ }
3966
+ const changes = formatChange(previous, current);
3967
+ if (changes.length === 0) {
3968
+ return "";
3969
+ }
3970
+ return `Changes since last environment snapshot:
3971
+ - ${changes.join("\n- ")}
3972
+
3973
+ `;
3974
+ }
3975
+ function parseEnvironmentSnapshot(value) {
3976
+ if (!isRecord2(value)) {
3977
+ return null;
3978
+ }
3979
+ if (typeof value.timeZone !== "string" || typeof value.language !== "string" || typeof value.currentDateTime !== "string" || typeof value.dateKey !== "string" || typeof value.dayOfWeek !== "string" || typeof value.month !== "string" || typeof value.year !== "number" || typeof value.season !== "string" || typeof value.timestamp !== "number") {
3980
+ return null;
3981
+ }
3982
+ return {
3983
+ timeZone: value.timeZone,
3984
+ language: value.language,
3985
+ currentDateTime: value.currentDateTime,
3986
+ dateKey: value.dateKey,
3987
+ dayOfWeek: value.dayOfWeek,
3988
+ month: value.month,
3989
+ year: value.year,
3990
+ season: value.season,
3991
+ timestamp: value.timestamp
3992
+ };
3993
+ }
3994
+ function getEnvironmentSnapshot(message2) {
3995
+ const metadata = isRecord2(message2?.metadata) ? message2.metadata : null;
3996
+ if (!metadata) {
3997
+ return null;
3998
+ }
3999
+ const stored = metadata[ENVIRONMENT_REMINDER_METADATA_KEY];
4000
+ if (!isRecord2(stored) || stored.version !== 1) {
4001
+ return null;
4002
+ }
4003
+ return parseEnvironmentSnapshot(stored.snapshot);
4004
+ }
4005
+ function environmentReminder(options) {
4006
+ const getNow = options?.getNow ?? (() => /* @__PURE__ */ new Date());
4007
+ const language = options?.language ?? "English (US)";
4008
+ const timeZone = options?.timeZone ?? "UTC";
4009
+ return reminder(
4010
+ (ctx) => {
4011
+ const snapshot = buildEnvironmentSnapshot(getNow(), {
4012
+ language,
4013
+ timeZone
4014
+ });
4015
+ const previousSnapshot = getEnvironmentSnapshot(ctx.lastMessage);
4016
+ const summary = buildChangeSummary(previousSnapshot, snapshot);
4017
+ return {
4018
+ text: `${summary}${buildEnvironmentBlock(snapshot)}`,
4019
+ metadata: {
4020
+ [ENVIRONMENT_REMINDER_METADATA_KEY]: {
4021
+ version: 1,
4022
+ snapshot
4023
+ }
4024
+ }
4025
+ };
4026
+ },
4027
+ { when: everyNTurns(1) }
4028
+ );
4029
+ }
4030
+
3817
4031
  // packages/context/src/lib/fragments/reasoning.ts
3818
4032
  function reasoningFramework() {
3819
4033
  return [
@@ -3938,6 +4152,68 @@ function selfCritique(checks = DEFAULT_SELF_CRITIQUE_CHECKS) {
3938
4152
  });
3939
4153
  }
3940
4154
 
4155
+ // packages/context/src/lib/fragments/socratic.ts
4156
+ function socraticPrompting() {
4157
+ return [
4158
+ role(
4159
+ "You are a deep, methodical thinker. Before producing any output, you reason through the problem by asking and answering foundational questions. You never treat a request as a simple task to complete \u2014 you first build understanding through inquiry, then apply that understanding to produce high-quality output."
4160
+ ),
4161
+ fragment(
4162
+ "socratic_prompting",
4163
+ hint(
4164
+ "When given a task, do not jump straight to producing output. Instead, decompose the task into foundational questions that, once answered, will make the output significantly better. Answer those questions first, then synthesize your answers into the final output."
4165
+ ),
4166
+ principle({
4167
+ title: "Question-first decomposition",
4168
+ description: 'Every task hides assumptions about what "good" looks like. Surface those assumptions by asking what makes the output effective before attempting to produce it.',
4169
+ policies: [
4170
+ 'Ask "What makes X effective/compelling/useful?" before producing X.',
4171
+ "Identify the criteria, frameworks, or principles that govern quality for this type of output.",
4172
+ "Do not skip this step even when the task seems straightforward \u2014 obvious tasks often have non-obvious quality dimensions."
4173
+ ]
4174
+ }),
4175
+ principle({
4176
+ title: "Multi-dimensional inquiry",
4177
+ description: "Explore the problem from multiple angles \u2014 emotional, logical, practical, audience-specific \u2014 through targeted questions.",
4178
+ policies: [
4179
+ "Ask about the audience: Who is this for? What do they care about?",
4180
+ "Ask about constraints: What must this include or avoid?",
4181
+ "Ask about effectiveness: What separates great output from mediocre output in this domain?",
4182
+ "Ask about structure: How should this be organized for maximum impact?"
4183
+ ]
4184
+ }),
4185
+ principle({
4186
+ title: "Framework discovery before application",
4187
+ description: "Build or recall a relevant framework by reasoning through questions, then explicitly apply that framework to the specific task.",
4188
+ policies: [
4189
+ "First derive the framework: What principles govern this type of work?",
4190
+ 'Then apply it: "Now, using these principles, produce the specific output."',
4191
+ "The framework should emerge from your reasoning, not from a template."
4192
+ ]
4193
+ }),
4194
+ workflow({
4195
+ task: "Socratic reasoning process",
4196
+ steps: [
4197
+ "Identify the core task and desired output type.",
4198
+ "Formulate 2-5 foundational questions about what makes this output effective.",
4199
+ "Answer each question, drawing on relevant knowledge and frameworks.",
4200
+ "Synthesize answers into a coherent set of principles or criteria.",
4201
+ "Apply the discovered framework to produce the specific output.",
4202
+ "Verify the output satisfies the criteria you identified."
4203
+ ]
4204
+ }),
4205
+ example({
4206
+ question: "How should I prompt for a value proposition for my AI analytics tool?",
4207
+ answer: "What makes a value proposition compelling to B2B buyers? What emotional and logical triggers should it hit? Now apply that framework to an AI analytics tool that helps teams make faster data-driven decisions."
4208
+ }),
4209
+ example({
4210
+ question: "How should I prompt for a 30-day LinkedIn content calendar for B2B SaaS?",
4211
+ answer: "What types of LinkedIn content generate the most engagement in B2B SaaS? What posting frequency avoids audience fatigue? How should topics build on each other? Now design a 30-day calendar using these principles."
4212
+ })
4213
+ )
4214
+ ];
4215
+ }
4216
+
3941
4217
  // packages/context/src/lib/guardrails/error-recovery.guardrail.ts
3942
4218
  import chalk2 from "chalk";
3943
4219
  var errorRecoveryGuardrail = {
@@ -4046,6 +4322,107 @@ function render(tag, ...fragments) {
4046
4322
  return renderer.render([wrapped]);
4047
4323
  }
4048
4324
 
4325
+ // packages/context/src/lib/sandbox/agent-os-sandbox.ts
4326
+ import "bash-tool";
4327
+ var textDecoder = new TextDecoder();
4328
+ var AgentOsSandboxError = class extends Error {
4329
+ constructor(message2) {
4330
+ super(message2);
4331
+ this.name = "AgentOsSandboxError";
4332
+ }
4333
+ };
4334
+ var AgentOsNotAvailableError = class extends AgentOsSandboxError {
4335
+ constructor(cause) {
4336
+ super(
4337
+ "@rivet-dev/agent-os-core is not installed. Install it with: npm install @rivet-dev/agent-os-core @rivet-dev/agent-os-common"
4338
+ );
4339
+ this.name = "AgentOsNotAvailableError";
4340
+ this.cause = cause;
4341
+ }
4342
+ };
4343
+ var AgentOsCreationError = class extends AgentOsSandboxError {
4344
+ constructor(message2, cause) {
4345
+ super(`Failed to create Agent OS instance: ${message2}`);
4346
+ this.name = "AgentOsCreationError";
4347
+ this.cause = cause;
4348
+ }
4349
+ };
4350
+ async function importAgentOs() {
4351
+ try {
4352
+ return await import("@rivet-dev/agent-os-core");
4353
+ } catch (error) {
4354
+ throw new AgentOsNotAvailableError(
4355
+ error instanceof Error ? error : void 0
4356
+ );
4357
+ }
4358
+ }
4359
+ async function createAgentOsSandbox(options = {}) {
4360
+ const { AgentOs } = await importAgentOs();
4361
+ let os;
4362
+ try {
4363
+ os = await AgentOs.create(options);
4364
+ } catch (error) {
4365
+ const err = error instanceof Error ? error : new Error(String(error));
4366
+ throw new AgentOsCreationError(err.message, err);
4367
+ }
4368
+ return {
4369
+ async executeCommand(command) {
4370
+ try {
4371
+ const result = await os.exec(command);
4372
+ return {
4373
+ stdout: result.stdout,
4374
+ stderr: result.stderr,
4375
+ exitCode: result.exitCode
4376
+ };
4377
+ } catch (error) {
4378
+ const err = error;
4379
+ return {
4380
+ stdout: err.stdout || "",
4381
+ stderr: err.stderr || err.message || "",
4382
+ exitCode: err.exitCode ?? 1
4383
+ };
4384
+ }
4385
+ },
4386
+ async readFile(path3) {
4387
+ try {
4388
+ const bytes = await os.readFile(path3);
4389
+ return textDecoder.decode(bytes);
4390
+ } catch (error) {
4391
+ throw new Error(
4392
+ `Failed to read file "${path3}": ${error instanceof Error ? error.message : String(error)}`
4393
+ );
4394
+ }
4395
+ },
4396
+ async writeFiles(files) {
4397
+ const results = await os.writeFiles(
4398
+ files.map((f) => ({
4399
+ path: f.path,
4400
+ content: typeof f.content === "string" ? f.content : new Uint8Array(f.content)
4401
+ }))
4402
+ );
4403
+ const failures = results.filter((r) => !r.success);
4404
+ if (failures.length > 0) {
4405
+ const details = failures.map((f) => `${f.path}: ${f.error}`).join(", ");
4406
+ throw new Error(`Failed to write files: ${details}`);
4407
+ }
4408
+ },
4409
+ async dispose() {
4410
+ try {
4411
+ await os.dispose();
4412
+ } catch {
4413
+ }
4414
+ }
4415
+ };
4416
+ }
4417
+ async function useAgentOsSandbox(options, fn) {
4418
+ const sandbox = await createAgentOsSandbox(options);
4419
+ try {
4420
+ return await fn(sandbox);
4421
+ } finally {
4422
+ await sandbox.dispose();
4423
+ }
4424
+ }
4425
+
4049
4426
  // packages/context/src/lib/sandbox/binary-bridges.ts
4050
4427
  import { existsSync } from "fs";
4051
4428
  import { defineCommand } from "just-bash";
@@ -4142,6 +4519,11 @@ function resolveRealCwd(ctx) {
4142
4519
  return realCwd;
4143
4520
  }
4144
4521
 
4522
+ // packages/context/src/lib/sandbox/container-tool.ts
4523
+ import {
4524
+ createBashTool
4525
+ } from "bash-tool";
4526
+
4145
4527
  // packages/context/src/lib/sandbox/docker-sandbox.ts
4146
4528
  import "bash-tool";
4147
4529
  import spawn2 from "nano-spawn";
@@ -4234,10 +4616,10 @@ var ComposeStartError = class extends DockerSandboxError {
4234
4616
  }
4235
4617
  };
4236
4618
  function isDebianBased(image) {
4619
+ const lower = image.toLowerCase();
4620
+ if (lower.includes("alpine")) return false;
4237
4621
  const debianPatterns = ["debian", "ubuntu", "node", "python"];
4238
- return debianPatterns.some(
4239
- (pattern) => image.toLowerCase().includes(pattern)
4240
- );
4622
+ return debianPatterns.some((pattern) => lower.includes(pattern));
4241
4623
  }
4242
4624
  function isDockerfileOptions(opts) {
4243
4625
  return "dockerfile" in opts;
@@ -4249,9 +4631,18 @@ var DockerSandboxStrategy = class {
4249
4631
  context;
4250
4632
  mounts;
4251
4633
  resources;
4252
- constructor(mounts = [], resources = {}) {
4634
+ env;
4635
+ constructor(mounts = [], resources = {}, env = {}) {
4636
+ for (const key of Object.keys(env)) {
4637
+ if (key.length === 0 || key.includes("=")) {
4638
+ throw new DockerSandboxError(
4639
+ `Invalid environment variable key: "${key}"`
4640
+ );
4641
+ }
4642
+ }
4253
4643
  this.mounts = mounts;
4254
4644
  this.resources = resources;
4645
+ this.env = env;
4255
4646
  }
4256
4647
  /**
4257
4648
  * Template method - defines the algorithm skeleton for creating a sandbox.
@@ -4308,6 +4699,9 @@ var DockerSandboxStrategy = class {
4308
4699
  "/workspace"
4309
4700
  // Set working directory
4310
4701
  ];
4702
+ for (const [key, value] of Object.entries(this.env)) {
4703
+ args.push("-e", `${key}=${value}`);
4704
+ }
4311
4705
  for (const mount of this.mounts) {
4312
4706
  const mode = mount.readOnly !== false ? "ro" : "rw";
4313
4707
  args.push("-v", `${mount.hostPath}:${mount.containerPath}:${mode}`);
@@ -4411,8 +4805,8 @@ var RuntimeStrategy = class extends DockerSandboxStrategy {
4411
4805
  image;
4412
4806
  packages;
4413
4807
  binaries;
4414
- constructor(image = "alpine:latest", packages = [], binaries = [], mounts, resources) {
4415
- super(mounts, resources);
4808
+ constructor(image = "alpine:latest", packages = [], binaries = [], mounts, resources, env) {
4809
+ super(mounts, resources, env);
4416
4810
  this.image = image;
4417
4811
  this.packages = packages;
4418
4812
  this.binaries = binaries;
@@ -4581,8 +4975,8 @@ var DockerfileStrategy = class extends DockerSandboxStrategy {
4581
4975
  imageTag;
4582
4976
  dockerfile;
4583
4977
  dockerContext;
4584
- constructor(dockerfile, dockerContext = ".", mounts, resources) {
4585
- super(mounts, resources);
4978
+ constructor(dockerfile, dockerContext = ".", mounts, resources, env) {
4979
+ super(mounts, resources, env);
4586
4980
  this.dockerfile = dockerfile;
4587
4981
  this.dockerContext = dockerContext;
4588
4982
  this.imageTag = this.computeImageTag();
@@ -4755,7 +5149,8 @@ async function createDockerSandbox(options = {}) {
4755
5149
  options.dockerfile,
4756
5150
  options.context,
4757
5151
  options.mounts,
4758
- options.resources
5152
+ options.resources,
5153
+ options.env
4759
5154
  );
4760
5155
  } else {
4761
5156
  strategy = new RuntimeStrategy(
@@ -4763,7 +5158,8 @@ async function createDockerSandbox(options = {}) {
4763
5158
  options.packages,
4764
5159
  options.binaries,
4765
5160
  options.mounts,
4766
- options.resources
5161
+ options.resources,
5162
+ options.env
4767
5163
  );
4768
5164
  }
4769
5165
  return strategy.create();
@@ -4778,9 +5174,6 @@ async function useSandbox(options, fn) {
4778
5174
  }
4779
5175
 
4780
5176
  // packages/context/src/lib/sandbox/container-tool.ts
4781
- import {
4782
- createBashTool
4783
- } from "bash-tool";
4784
5177
  async function createContainerTool(options = {}) {
4785
5178
  let sandboxOptions;
4786
5179
  let bashOptions;
@@ -4789,12 +5182,12 @@ async function createContainerTool(options = {}) {
4789
5182
  sandboxOptions = { compose, service, resources };
4790
5183
  bashOptions = rest;
4791
5184
  } else if (isDockerfileOptions(options)) {
4792
- const { dockerfile, context, mounts, resources, ...rest } = options;
4793
- sandboxOptions = { dockerfile, context, mounts, resources };
5185
+ const { dockerfile, context, mounts, resources, env, ...rest } = options;
5186
+ sandboxOptions = { dockerfile, context, mounts, resources, env };
4794
5187
  bashOptions = rest;
4795
5188
  } else {
4796
- const { image, packages, binaries, mounts, resources, ...rest } = options;
4797
- sandboxOptions = { image, packages, binaries, mounts, resources };
5189
+ const { image, packages, binaries, mounts, resources, env, ...rest } = options;
5190
+ sandboxOptions = { image, packages, binaries, mounts, resources, env };
4798
5191
  bashOptions = rest;
4799
5192
  }
4800
5193
  const sandbox = await createDockerSandbox(sandboxOptions);
@@ -7335,6 +7728,9 @@ function visualizeGraph(data) {
7335
7728
  return lines.join("\n");
7336
7729
  }
7337
7730
  export {
7731
+ AgentOsCreationError,
7732
+ AgentOsNotAvailableError,
7733
+ AgentOsSandboxError,
7338
7734
  BM25SkillClassifier,
7339
7735
  BinaryInstallError,
7340
7736
  ComposeStartError,
@@ -7350,6 +7746,7 @@ export {
7350
7746
  DockerSandboxStrategy,
7351
7747
  DockerfileBuildError,
7352
7748
  DockerfileStrategy,
7749
+ ENVIRONMENT_REMINDER_METADATA_KEY,
7353
7750
  InMemoryContextStore,
7354
7751
  LAZY_ID,
7355
7752
  MarkdownRenderer,
@@ -7381,23 +7778,27 @@ export {
7381
7778
  clarification,
7382
7779
  correction,
7383
7780
  createAdaptivePollingState,
7781
+ createAgentOsSandbox,
7384
7782
  createBinaryBridges,
7385
7783
  createContainerTool,
7386
7784
  createDockerSandbox,
7387
7785
  defaultTokenizer,
7388
7786
  discoverSkillsInDirectory,
7389
7787
  encodeSerializedValue,
7788
+ environmentReminder,
7390
7789
  errorRecoveryGuardrail,
7391
7790
  estimate,
7392
7791
  everyNTurns,
7393
7792
  example,
7394
7793
  explain,
7794
+ extractPlainText,
7395
7795
  fail,
7396
7796
  firstN,
7397
7797
  fragment,
7398
7798
  fromFragment,
7399
7799
  generateChatTitle,
7400
7800
  getConditionalReminder,
7801
+ getEnvironmentSnapshot,
7401
7802
  getFragmentData,
7402
7803
  getModelsRegistry,
7403
7804
  getReminderRanges,
@@ -7414,6 +7815,7 @@ export {
7414
7815
  isMessageFragment,
7415
7816
  lastAssistantMessage,
7416
7817
  loadSkillMetadata,
7818
+ mergeMessageMetadata,
7417
7819
  mergeReminderMetadata,
7418
7820
  message,
7419
7821
  nextAdaptivePollingDelay,
@@ -7434,12 +7836,14 @@ export {
7434
7836
  reminder,
7435
7837
  render,
7436
7838
  resetAdaptivePolling,
7839
+ resolveReminder,
7437
7840
  resolveReminderText,
7438
7841
  role,
7439
7842
  runGuardrailChain,
7440
7843
  selfCritique,
7441
7844
  skills,
7442
7845
  skillsReminder,
7846
+ socraticPrompting,
7443
7847
  soul,
7444
7848
  staticChatTitle,
7445
7849
  stop,
@@ -7450,6 +7854,7 @@ export {
7450
7854
  term,
7451
7855
  toFragment,
7452
7856
  toMessageFragment,
7857
+ useAgentOsSandbox,
7453
7858
  useSandbox,
7454
7859
  user,
7455
7860
  visualizeGraph,