@effect/ai 0.32.1 → 0.33.1

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/src/Prompt.ts CHANGED
@@ -1333,6 +1333,7 @@ export interface PromptEncoded {
1333
1333
  export class PromptFromSelf extends Schema.declare(
1334
1334
  (u) => isPrompt(u),
1335
1335
  {
1336
+ typeConstructor: { _tag: "effect/ai/Prompt" },
1336
1337
  identifier: "PromptFromSelf",
1337
1338
  description: "a Prompt instance",
1338
1339
  arbitrary: (): Arbitrary.LazyArbitrary<Prompt> => (fc) =>
@@ -1510,38 +1511,6 @@ export const make = (input: RawInput): Prompt => {
1510
1511
  */
1511
1512
  export const fromMessages = (messages: ReadonlyArray<Message>): Prompt => makePrompt(messages)
1512
1513
 
1513
- const VALID_RESPONSE_PART_MAP = {
1514
- "response-metadata": false,
1515
- "text": true,
1516
- "text-start": false,
1517
- "text-delta": true,
1518
- "text-end": false,
1519
- "reasoning": true,
1520
- "reasoning-start": false,
1521
- "reasoning-delta": true,
1522
- "reasoning-end": false,
1523
- "file": false,
1524
- "source": false,
1525
- "tool-params-start": false,
1526
- "tool-params-delta": false,
1527
- "tool-params-end": false,
1528
- "tool-call": true,
1529
- "tool-result": true,
1530
- "finish": false,
1531
- "error": false
1532
- } as const satisfies Record<Response.AnyPart["type"], boolean>
1533
-
1534
- type ValidResponseParts = typeof VALID_RESPONSE_PART_MAP
1535
-
1536
- type ValidResponsePart = {
1537
- [Type in keyof ValidResponseParts]: ValidResponseParts[Type] extends true ? Extract<Response.AnyPart, { type: Type }>
1538
- : never
1539
- }[keyof typeof VALID_RESPONSE_PART_MAP]
1540
-
1541
- const isValidPart = (part: Response.AnyPart): part is ValidResponsePart => {
1542
- return VALID_RESPONSE_PART_MAP[part.type]
1543
- }
1544
-
1545
1514
  /**
1546
1515
  * Creates a Prompt from the response parts of a previous interaction with a
1547
1516
  * large language model.
@@ -1589,93 +1558,96 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
1589
1558
  const assistantParts: Array<AssistantMessagePart> = []
1590
1559
  const toolParts: Array<ToolMessagePart> = []
1591
1560
 
1592
- const textDeltas: Array<string> = []
1593
- function flushTextDeltas() {
1594
- if (textDeltas.length > 0) {
1595
- const text = textDeltas.join("")
1596
- if (text.length > 0) {
1597
- assistantParts.push(makePart("text", { text }))
1598
- }
1599
- textDeltas.length = 0
1600
- }
1601
- }
1561
+ const activeTextDeltas = new Map<string, { text: string }>()
1562
+ const activeReasoningDeltas = new Map<string, { text: string }>()
1602
1563
 
1603
- const reasoningDeltas: Array<string> = []
1604
- function flushReasoningDeltas() {
1605
- if (reasoningDeltas.length > 0) {
1606
- const text = reasoningDeltas.join("")
1607
- if (text.length > 0) {
1608
- assistantParts.push(makePart("reasoning", { text }))
1564
+ for (const part of parts) {
1565
+ switch (part.type) {
1566
+ // Text Parts
1567
+ case "text": {
1568
+ assistantParts.push(makePart("text", { text: part.text }))
1569
+ break
1609
1570
  }
1610
- reasoningDeltas.length = 0
1611
- }
1612
- }
1613
1571
 
1614
- function flushDeltas() {
1615
- flushTextDeltas()
1616
- flushReasoningDeltas()
1617
- }
1618
-
1619
- for (const part of parts) {
1620
- if (isValidPart(part)) {
1621
- switch (part.type) {
1622
- case "text": {
1623
- flushDeltas()
1624
- assistantParts.push(makePart("text", { text: part.text }))
1625
- break
1626
- }
1627
- case "text-delta": {
1628
- flushReasoningDeltas()
1629
- textDeltas.push(part.delta)
1630
- break
1631
- }
1632
- case "reasoning": {
1633
- flushDeltas()
1634
- assistantParts.push(makePart("reasoning", { text: part.text }))
1635
- break
1572
+ // Text Parts (streaming)
1573
+ case "text-start": {
1574
+ activeTextDeltas.set(part.id, { text: "" })
1575
+ break
1576
+ }
1577
+ case "text-delta": {
1578
+ if (activeTextDeltas.has(part.id)) {
1579
+ activeTextDeltas.get(part.id)!.text += part.delta
1636
1580
  }
1637
- case "reasoning-delta": {
1638
- flushTextDeltas()
1639
- reasoningDeltas.push(part.delta)
1640
- break
1581
+ break
1582
+ }
1583
+ case "text-end": {
1584
+ if (activeTextDeltas.has(part.id)) {
1585
+ assistantParts.push(makePart("text", activeTextDeltas.get(part.id)!))
1641
1586
  }
1642
- case "tool-call": {
1643
- flushDeltas()
1644
- assistantParts.push(makePart("tool-call", {
1645
- id: part.id,
1646
- name: part.providerName ?? part.name,
1647
- params: part.params,
1648
- providerExecuted: part.providerExecuted ?? false
1649
- }))
1650
- break
1587
+ break
1588
+ }
1589
+
1590
+ // Reasoning Parts
1591
+ case "reasoning": {
1592
+ assistantParts.push(makePart("reasoning", { text: part.text }))
1593
+ break
1594
+ }
1595
+
1596
+ // Reasoning Parts (streaming)
1597
+ case "reasoning-start": {
1598
+ activeReasoningDeltas.set(part.id, { text: "" })
1599
+ break
1600
+ }
1601
+ case "reasoning-delta": {
1602
+ if (activeReasoningDeltas.has(part.id)) {
1603
+ activeReasoningDeltas.get(part.id)!.text += part.delta
1651
1604
  }
1652
- case "tool-result": {
1653
- flushDeltas()
1654
- toolParts.push(makePart("tool-result", {
1655
- id: part.id,
1656
- name: part.providerName ?? part.name,
1657
- isFailure: part.isFailure,
1658
- result: part.encodedResult
1659
- }))
1660
- break
1605
+ break
1606
+ }
1607
+ case "reasoning-end": {
1608
+ if (activeReasoningDeltas.has(part.id)) {
1609
+ assistantParts.push(makePart("reasoning", activeReasoningDeltas.get(part.id)!))
1661
1610
  }
1611
+ break
1612
+ }
1613
+
1614
+ // Tool Call Parts
1615
+ case "tool-call": {
1616
+ assistantParts.push(makePart("tool-call", {
1617
+ id: part.id,
1618
+ name: part.providerName ?? part.name,
1619
+ params: part.params,
1620
+ providerExecuted: part.providerExecuted ?? false
1621
+ }))
1622
+ break
1623
+ }
1624
+
1625
+ // Tool Result Parts
1626
+ case "tool-result": {
1627
+ toolParts.push(makePart("tool-result", {
1628
+ id: part.id,
1629
+ name: part.providerName ?? part.name,
1630
+ isFailure: part.isFailure,
1631
+ result: part.encodedResult
1632
+ }))
1662
1633
  }
1663
1634
  }
1664
1635
  }
1665
1636
 
1666
- flushDeltas()
1667
-
1668
1637
  if (assistantParts.length === 0 && toolParts.length === 0) {
1669
1638
  return empty
1670
1639
  }
1671
1640
 
1672
1641
  const messages: Array<Message> = []
1642
+
1673
1643
  if (assistantParts.length > 0) {
1674
1644
  messages.push(makeMessage("assistant", { content: assistantParts }))
1675
1645
  }
1646
+
1676
1647
  if (toolParts.length > 0) {
1677
1648
  messages.push(makeMessage("tool", { content: toolParts }))
1678
1649
  }
1650
+
1679
1651
  return makePrompt(messages)
1680
1652
  }
1681
1653
 
@@ -1904,6 +1876,7 @@ export const setSystem: {
1904
1876
  * prompt,
1905
1877
  * "You are a helpful assistant. "
1906
1878
  * )
1879
+ * // result content: "You are a helpful assistant. You are an expert in programming."
1907
1880
  * ```
1908
1881
  *
1909
1882
  * @since 1.0.0
@@ -1934,6 +1907,7 @@ export const prependSystem: {
1934
1907
  * prompt,
1935
1908
  * "You are a helpful assistant. "
1936
1909
  * )
1910
+ * // result content: "You are a helpful assistant. You are an expert in programming."
1937
1911
  * ```
1938
1912
  *
1939
1913
  * @since 1.0.0
@@ -1964,6 +1938,7 @@ export const prependSystem: {
1964
1938
  * prompt,
1965
1939
  * "You are a helpful assistant. "
1966
1940
  * )
1941
+ * // result content: "You are a helpful assistant. You are an expert in programming."
1967
1942
  * ```
1968
1943
  *
1969
1944
  * @since 1.0.0
@@ -1971,18 +1946,19 @@ export const prependSystem: {
1971
1946
  */
1972
1947
  (self: Prompt, content: string): Prompt
1973
1948
  } = dual(2, (self: Prompt, content: string): Prompt => {
1974
- const messages: Array<Message> = []
1949
+ let system: SystemMessage | undefined = undefined
1975
1950
  for (const message of self.content) {
1976
1951
  if (message.role === "system") {
1977
- const system = makeMessage("system", {
1952
+ system = makeMessage("system", {
1978
1953
  content: content + message.content
1979
1954
  })
1980
- messages.push(system)
1981
- } else {
1982
- messages.push(message)
1955
+ break
1983
1956
  }
1984
1957
  }
1985
- return makePrompt(messages)
1958
+ if (Predicate.isUndefined(system)) {
1959
+ system = makeMessage("system", { content })
1960
+ }
1961
+ return makePrompt([system, ...self.content])
1986
1962
  })
1987
1963
 
1988
1964
  /**
@@ -1998,7 +1974,7 @@ export const prependSystem: {
1998
1974
  *
1999
1975
  * const systemPrompt = Prompt.make([{
2000
1976
  * role: "system",
2001
- * content: "You are a helpful assistant."
1977
+ * content: "You are an expert in programming."
2002
1978
  * }])
2003
1979
  *
2004
1980
  * const userPrompt = Prompt.make("Hello, world!")
@@ -2007,8 +1983,9 @@ export const prependSystem: {
2007
1983
  *
2008
1984
  * const replaced = Prompt.appendSystem(
2009
1985
  * prompt,
2010
- * " You are an expert in programming."
1986
+ * " You are a helpful assistant."
2011
1987
  * )
1988
+ * // result content: "You are an expert in programming. You are a helpful assistant."
2012
1989
  * ```
2013
1990
  *
2014
1991
  * @since 1.0.0
@@ -2028,7 +2005,7 @@ export const appendSystem: {
2028
2005
  *
2029
2006
  * const systemPrompt = Prompt.make([{
2030
2007
  * role: "system",
2031
- * content: "You are a helpful assistant."
2008
+ * content: "You are an expert in programming."
2032
2009
  * }])
2033
2010
  *
2034
2011
  * const userPrompt = Prompt.make("Hello, world!")
@@ -2037,8 +2014,9 @@ export const appendSystem: {
2037
2014
  *
2038
2015
  * const replaced = Prompt.appendSystem(
2039
2016
  * prompt,
2040
- * " You are an expert in programming."
2017
+ * " You are a helpful assistant."
2041
2018
  * )
2019
+ * // result content: "You are an expert in programming. You are a helpful assistant."
2042
2020
  * ```
2043
2021
  *
2044
2022
  * @since 1.0.0
@@ -2058,7 +2036,7 @@ export const appendSystem: {
2058
2036
  *
2059
2037
  * const systemPrompt = Prompt.make([{
2060
2038
  * role: "system",
2061
- * content: "You are a helpful assistant."
2039
+ * content: "You are an expert in programming."
2062
2040
  * }])
2063
2041
  *
2064
2042
  * const userPrompt = Prompt.make("Hello, world!")
@@ -2067,8 +2045,9 @@ export const appendSystem: {
2067
2045
  *
2068
2046
  * const replaced = Prompt.appendSystem(
2069
2047
  * prompt,
2070
- * " You are an expert in programming."
2048
+ * " You are a helpful assistant."
2071
2049
  * )
2050
+ * // result content: "You are an expert in programming. You are a helpful assistant."
2072
2051
  * ```
2073
2052
  *
2074
2053
  * @since 1.0.0
@@ -2076,16 +2055,17 @@ export const appendSystem: {
2076
2055
  */
2077
2056
  (self: Prompt, content: string): Prompt
2078
2057
  } = dual(2, (self: Prompt, content: string): Prompt => {
2079
- const messages: Array<Message> = []
2058
+ let system: SystemMessage | undefined = undefined
2080
2059
  for (const message of self.content) {
2081
2060
  if (message.role === "system") {
2082
- const system = makeMessage("system", {
2061
+ system = makeMessage("system", {
2083
2062
  content: message.content + content
2084
2063
  })
2085
- messages.push(system)
2086
- } else {
2087
- messages.push(message)
2064
+ break
2088
2065
  }
2089
2066
  }
2090
- return makePrompt(messages)
2067
+ if (Predicate.isUndefined(system)) {
2068
+ system = makeMessage("system", { content })
2069
+ }
2070
+ return makePrompt([system, ...self.content])
2091
2071
  })