feat: add memory citation to agent message (#14821)
Client side to come
This commit is contained in:
parent
0f9484dc8a
commit
a265d6043e
43 changed files with 1420 additions and 40 deletions
|
|
@ -1455,6 +1455,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -2181,6 +2229,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8600,6 +8600,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MergeStrategy": {
|
||||
"enum": [
|
||||
"replace",
|
||||
|
|
@ -11841,6 +11889,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5388,6 +5388,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MergeStrategy": {
|
||||
"enum": [
|
||||
"replace",
|
||||
|
|
@ -9601,6 +9649,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -289,6 +289,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -444,6 +492,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -289,6 +289,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -444,6 +492,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -403,6 +403,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -558,6 +606,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -488,6 +488,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -1038,6 +1086,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -426,6 +426,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -796,6 +844,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -426,6 +426,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -796,6 +844,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -426,6 +426,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -796,6 +844,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -488,6 +488,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -1038,6 +1086,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -426,6 +426,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -796,6 +844,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -488,6 +488,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -1038,6 +1086,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -426,6 +426,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -796,6 +844,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -426,6 +426,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -796,6 +844,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -403,6 +403,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -558,6 +606,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -403,6 +403,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -558,6 +606,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -403,6 +403,54 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"MemoryCitation": {
|
||||
"properties": {
|
||||
"entries": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/MemoryCitationEntry"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"threadIds": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entries",
|
||||
"threadIds"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MemoryCitationEntry": {
|
||||
"properties": {
|
||||
"lineEnd": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"lineStart": {
|
||||
"format": "uint32",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lineEnd",
|
||||
"lineStart",
|
||||
"note",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"MessagePhase": {
|
||||
"description": "Classifies an assistant message as interim commentary or final answer text.\n\nProviders do not emit this consistently, so callers must treat `None` as \"phase unknown\" and keep compatibility behavior for legacy models.",
|
||||
"oneOf": [
|
||||
|
|
@ -558,6 +606,17 @@
|
|||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memoryCitation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/MemoryCitation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"phase": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { MemoryCitationEntry } from "./MemoryCitationEntry";
|
||||
|
||||
export type MemoryCitation = { entries: Array<MemoryCitationEntry>, threadIds: Array<string>, };
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type MemoryCitationEntry = { path: string, lineStart: number, lineEnd: number, note: string, };
|
||||
|
|
@ -15,11 +15,12 @@ import type { FileUpdateChange } from "./FileUpdateChange";
|
|||
import type { McpToolCallError } from "./McpToolCallError";
|
||||
import type { McpToolCallResult } from "./McpToolCallResult";
|
||||
import type { McpToolCallStatus } from "./McpToolCallStatus";
|
||||
import type { MemoryCitation } from "./MemoryCitation";
|
||||
import type { PatchApplyStatus } from "./PatchApplyStatus";
|
||||
import type { UserInput } from "./UserInput";
|
||||
import type { WebSearchAction } from "./WebSearchAction";
|
||||
|
||||
export type ThreadItem = { "type": "userMessage", id: string, content: Array<UserInput>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
|
||||
export type ThreadItem = { "type": "userMessage", id: string, content: Array<UserInput>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
|
||||
/**
|
||||
* The command to be executed.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -174,6 +174,8 @@ export type { McpToolCallError } from "./McpToolCallError";
|
|||
export type { McpToolCallProgressNotification } from "./McpToolCallProgressNotification";
|
||||
export type { McpToolCallResult } from "./McpToolCallResult";
|
||||
export type { McpToolCallStatus } from "./McpToolCallStatus";
|
||||
export type { MemoryCitation } from "./MemoryCitation";
|
||||
export type { MemoryCitationEntry } from "./MemoryCitationEntry";
|
||||
export type { MergeStrategy } from "./MergeStrategy";
|
||||
export type { Model } from "./Model";
|
||||
export type { ModelAvailabilityNux } from "./ModelAvailabilityNux";
|
||||
|
|
|
|||
|
|
@ -118,9 +118,11 @@ impl ThreadHistoryBuilder {
|
|||
pub fn handle_event(&mut self, event: &EventMsg) {
|
||||
match event {
|
||||
EventMsg::UserMessage(payload) => self.handle_user_message(payload),
|
||||
EventMsg::AgentMessage(payload) => {
|
||||
self.handle_agent_message(payload.message.clone(), payload.phase.clone())
|
||||
}
|
||||
EventMsg::AgentMessage(payload) => self.handle_agent_message(
|
||||
payload.message.clone(),
|
||||
payload.phase.clone(),
|
||||
payload.memory_citation.clone().map(Into::into),
|
||||
),
|
||||
EventMsg::AgentReasoning(payload) => self.handle_agent_reasoning(payload),
|
||||
EventMsg::AgentReasoningRawContent(payload) => {
|
||||
self.handle_agent_reasoning_raw_content(payload)
|
||||
|
|
@ -208,15 +210,23 @@ impl ThreadHistoryBuilder {
|
|||
self.current_turn = Some(turn);
|
||||
}
|
||||
|
||||
fn handle_agent_message(&mut self, text: String, phase: Option<MessagePhase>) {
|
||||
fn handle_agent_message(
|
||||
&mut self,
|
||||
text: String,
|
||||
phase: Option<MessagePhase>,
|
||||
memory_citation: Option<crate::protocol::v2::MemoryCitation>,
|
||||
) {
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = self.next_item_id();
|
||||
self.ensure_turn()
|
||||
.items
|
||||
.push(ThreadItem::AgentMessage { id, text, phase });
|
||||
self.ensure_turn().items.push(ThreadItem::AgentMessage {
|
||||
id,
|
||||
text,
|
||||
phase,
|
||||
memory_citation,
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_agent_reasoning(&mut self, payload: &AgentReasoningEvent) {
|
||||
|
|
@ -1178,6 +1188,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Hi there".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::AgentReasoning(AgentReasoningEvent {
|
||||
text: "thinking".into(),
|
||||
|
|
@ -1194,6 +1205,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Reply two".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
@ -1229,6 +1241,7 @@ mod tests {
|
|||
id: "item-2".into(),
|
||||
text: "Hi there".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
|
|
@ -1260,6 +1273,7 @@ mod tests {
|
|||
id: "item-5".into(),
|
||||
text: "Reply two".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1318,6 +1332,7 @@ mod tests {
|
|||
let events = vec![EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Final reply".into(),
|
||||
phase: Some(CoreMessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
})];
|
||||
|
||||
let items = events
|
||||
|
|
@ -1332,6 +1347,7 @@ mod tests {
|
|||
id: "item-1".into(),
|
||||
text: "Final reply".into(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1354,6 +1370,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "interlude".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::AgentReasoning(AgentReasoningEvent {
|
||||
text: "second summary".into(),
|
||||
|
|
@ -1399,6 +1416,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Working...".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::TurnAborted(TurnAbortedEvent {
|
||||
turn_id: Some("turn-1".into()),
|
||||
|
|
@ -1413,6 +1431,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Second attempt complete.".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
@ -1442,6 +1461,7 @@ mod tests {
|
|||
id: "item-2".into(),
|
||||
text: "Working...".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -1464,6 +1484,7 @@ mod tests {
|
|||
id: "item-4".into(),
|
||||
text: "Second attempt complete.".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1480,6 +1501,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A1".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
message: "Second".into(),
|
||||
|
|
@ -1490,6 +1512,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A2".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::ThreadRolledBack(ThreadRolledBackEvent { num_turns: 1 }),
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
|
|
@ -1501,6 +1524,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A3".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
@ -1529,6 +1553,7 @@ mod tests {
|
|||
id: "item-2".into(),
|
||||
text: "A1".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
|
@ -1546,6 +1571,7 @@ mod tests {
|
|||
id: "item-4".into(),
|
||||
text: "A3".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
|
@ -1563,6 +1589,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A1".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::UserMessage(UserMessageEvent {
|
||||
message: "Two".into(),
|
||||
|
|
@ -1573,6 +1600,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "A2".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::ThreadRolledBack(ThreadRolledBackEvent { num_turns: 99 }),
|
||||
];
|
||||
|
|
@ -2209,6 +2237,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "still in b".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::TurnComplete(TurnCompleteEvent {
|
||||
turn_id: "turn-b".into(),
|
||||
|
|
@ -2263,6 +2292,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "still in b".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
@ -2497,6 +2527,7 @@ mod tests {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "done".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
EventMsg::Error(ErrorEvent {
|
||||
message: "rollback failed".into(),
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ use codex_protocol::items::TurnItem as CoreTurnItem;
|
|||
use codex_protocol::mcp::Resource as McpResource;
|
||||
use codex_protocol::mcp::ResourceTemplate as McpResourceTemplate;
|
||||
use codex_protocol::mcp::Tool as McpTool;
|
||||
use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation;
|
||||
use codex_protocol::memory_citation::MemoryCitationEntry as CoreMemoryCitationEntry;
|
||||
use codex_protocol::models::FileSystemPermissions as CoreFileSystemPermissions;
|
||||
use codex_protocol::models::MacOsAutomationPermission as CoreMacOsAutomationPermission;
|
||||
use codex_protocol::models::MacOsContactsPermission as CoreMacOsContactsPermission;
|
||||
|
|
@ -3568,6 +3570,44 @@ pub struct Turn {
|
|||
pub error: Option<TurnError>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MemoryCitation {
|
||||
pub entries: Vec<MemoryCitationEntry>,
|
||||
pub thread_ids: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<CoreMemoryCitation> for MemoryCitation {
|
||||
fn from(value: CoreMemoryCitation) -> Self {
|
||||
Self {
|
||||
entries: value.entries.into_iter().map(Into::into).collect(),
|
||||
thread_ids: value.rollout_ids,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct MemoryCitationEntry {
|
||||
pub path: String,
|
||||
pub line_start: u32,
|
||||
pub line_end: u32,
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
impl From<CoreMemoryCitationEntry> for MemoryCitationEntry {
|
||||
fn from(value: CoreMemoryCitationEntry) -> Self {
|
||||
Self {
|
||||
path: value.path,
|
||||
line_start: value.line_start,
|
||||
line_end: value.line_end,
|
||||
note: value.note,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, Error)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
|
|
@ -4068,6 +4108,8 @@ pub enum ThreadItem {
|
|||
text: String,
|
||||
#[serde(default)]
|
||||
phase: Option<MessagePhase>,
|
||||
#[serde(default)]
|
||||
memory_citation: Option<MemoryCitation>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
|
|
@ -4317,6 +4359,7 @@ impl From<CoreTurnItem> for ThreadItem {
|
|||
id: agent.id,
|
||||
text,
|
||||
phase: agent.phase,
|
||||
memory_citation: agent.memory_citation.map(Into::into),
|
||||
}
|
||||
}
|
||||
CoreTurnItem::Plan(plan) => ThreadItem::Plan {
|
||||
|
|
@ -7393,6 +7436,7 @@ mod tests {
|
|||
},
|
||||
],
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -7401,6 +7445,7 @@ mod tests {
|
|||
id: "agent-1".to_string(),
|
||||
text: "Hello world".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -7410,6 +7455,15 @@ mod tests {
|
|||
text: "final".to_string(),
|
||||
}],
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: Some(CoreMemoryCitation {
|
||||
entries: vec![CoreMemoryCitationEntry {
|
||||
path: "MEMORY.md".to_string(),
|
||||
line_start: 1,
|
||||
line_end: 2,
|
||||
note: "summary".to_string(),
|
||||
}],
|
||||
rollout_ids: vec!["rollout-1".to_string()],
|
||||
}),
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -7418,6 +7472,15 @@ mod tests {
|
|||
id: "agent-2".to_string(),
|
||||
text: "final".to_string(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: Some(MemoryCitation {
|
||||
entries: vec![MemoryCitationEntry {
|
||||
path: "MEMORY.md".to_string(),
|
||||
line_start: 1,
|
||||
line_end: 2,
|
||||
note: "summary".to_string(),
|
||||
}],
|
||||
thread_ids: vec!["rollout-1".to_string()],
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -450,6 +450,7 @@ async fn thread_resume_and_read_interrupt_incomplete_rollout_turn_when_thread_is
|
|||
"payload": serde_json::to_value(EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Still running".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}))?,
|
||||
})
|
||||
.to_string(),
|
||||
|
|
|
|||
|
|
@ -6856,6 +6856,7 @@ async fn emit_agent_message_in_plan_mode(
|
|||
id: agent_message_id.clone(),
|
||||
content: Vec::new(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
})
|
||||
});
|
||||
sess.emit_turn_item_started(turn_context, &start_item).await;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,12 @@ fn parse_agent_message(
|
|||
}
|
||||
}
|
||||
let id = id.cloned().unwrap_or_else(|| Uuid::new_v4().to_string());
|
||||
AgentMessageItem { id, content, phase }
|
||||
AgentMessageItem {
|
||||
id,
|
||||
content,
|
||||
phase,
|
||||
memory_citation: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_turn_item(item: &ResponseItem) -> Option<TurnItem> {
|
||||
|
|
|
|||
|
|
@ -1,36 +1,89 @@
|
|||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::memory_citation::MemoryCitation;
|
||||
use codex_protocol::memory_citation::MemoryCitationEntry;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn parse_memory_citation(citations: Vec<String>) -> Option<MemoryCitation> {
|
||||
let mut entries = Vec::new();
|
||||
let mut rollout_ids = Vec::new();
|
||||
let mut seen_rollout_ids = HashSet::new();
|
||||
|
||||
pub fn get_thread_id_from_citations(citations: Vec<String>) -> Vec<ThreadId> {
|
||||
let mut result = Vec::new();
|
||||
for citation in citations {
|
||||
let mut ids_block = None;
|
||||
for (open, close) in [
|
||||
("<thread_ids>", "</thread_ids>"),
|
||||
("<rollout_ids>", "</rollout_ids>"),
|
||||
] {
|
||||
if let Some((_, rest)) = citation.split_once(open)
|
||||
&& let Some((ids, _)) = rest.split_once(close)
|
||||
{
|
||||
ids_block = Some(ids);
|
||||
break;
|
||||
}
|
||||
if let Some(entries_block) =
|
||||
extract_block(&citation, "<citation_entries>", "</citation_entries>")
|
||||
{
|
||||
entries.extend(
|
||||
entries_block
|
||||
.lines()
|
||||
.filter_map(parse_memory_citation_entry),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(ids_block) = ids_block {
|
||||
if let Some(ids_block) = extract_ids_block(&citation) {
|
||||
for id in ids_block
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty())
|
||||
{
|
||||
if let Ok(thread_id) = ThreadId::try_from(id) {
|
||||
result.push(thread_id);
|
||||
if seen_rollout_ids.insert(id.to_string()) {
|
||||
rollout_ids.push(id.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if entries.is_empty() && rollout_ids.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(MemoryCitation {
|
||||
entries,
|
||||
rollout_ids,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_thread_id_from_citations(citations: Vec<String>) -> Vec<ThreadId> {
|
||||
let mut result = Vec::new();
|
||||
if let Some(memory_citation) = parse_memory_citation(citations) {
|
||||
for rollout_id in memory_citation.rollout_ids {
|
||||
if let Ok(thread_id) = ThreadId::try_from(rollout_id.as_str()) {
|
||||
result.push(thread_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_memory_citation_entry(line: &str) -> Option<MemoryCitationEntry> {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (location, note) = line.rsplit_once("|note=[")?;
|
||||
let note = note.strip_suffix(']')?.trim().to_string();
|
||||
let (path, line_range) = location.rsplit_once(':')?;
|
||||
let (line_start, line_end) = line_range.split_once('-')?;
|
||||
|
||||
Some(MemoryCitationEntry {
|
||||
path: path.trim().to_string(),
|
||||
line_start: line_start.trim().parse().ok()?,
|
||||
line_end: line_end.trim().parse().ok()?,
|
||||
note,
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_block<'a>(text: &'a str, open: &str, close: &str) -> Option<&'a str> {
|
||||
let (_, rest) = text.split_once(open)?;
|
||||
let (body, _) = rest.split_once(close)?;
|
||||
Some(body)
|
||||
}
|
||||
|
||||
fn extract_ids_block(text: &str) -> Option<&str> {
|
||||
extract_block(text, "<rollout_ids>", "</rollout_ids>")
|
||||
.or_else(|| extract_block(text, "<thread_ids>", "</thread_ids>"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "citations_tests.rs"]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use super::get_thread_id_from_citations;
|
||||
use super::parse_memory_citation;
|
||||
use codex_protocol::ThreadId;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
|
|
@ -24,3 +25,40 @@ fn get_thread_id_from_citations_supports_legacy_rollout_ids() {
|
|||
|
||||
assert_eq!(get_thread_id_from_citations(citations), vec![thread_id]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_memory_citation_extracts_entries_and_rollout_ids() {
|
||||
let first = ThreadId::new();
|
||||
let second = ThreadId::new();
|
||||
let citations = vec![format!(
|
||||
"<citation_entries>\nMEMORY.md:1-2|note=[summary]\nrollout_summaries/foo.md:10-12|note=[details]\n</citation_entries>\n<rollout_ids>\n{first}\n{second}\n{first}\n</rollout_ids>"
|
||||
)];
|
||||
|
||||
let parsed = parse_memory_citation(citations).expect("memory citation should parse");
|
||||
|
||||
assert_eq!(
|
||||
parsed
|
||||
.entries
|
||||
.iter()
|
||||
.map(|entry| (
|
||||
entry.path.clone(),
|
||||
entry.line_start,
|
||||
entry.line_end,
|
||||
entry.note.clone(),
|
||||
))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
("MEMORY.md".to_string(), 1, 2, "summary".to_string()),
|
||||
(
|
||||
"rollout_summaries/foo.md".to_string(),
|
||||
10,
|
||||
12,
|
||||
"details".to_string()
|
||||
),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
parsed.rollout_ids,
|
||||
vec![first.to_string(), second.to_string()]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ async fn recorder_materializes_only_after_explicit_persist() -> std::io::Result<
|
|||
AgentMessageEvent {
|
||||
message: "buffered-event".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
))])
|
||||
.await?;
|
||||
|
|
@ -201,6 +202,7 @@ async fn metadata_irrelevant_events_touch_state_db_updated_at() -> std::io::Resu
|
|||
AgentMessageEvent {
|
||||
message: "assistant text".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
))])
|
||||
.await?;
|
||||
|
|
@ -251,6 +253,7 @@ async fn metadata_irrelevant_events_fall_back_to_upsert_when_thread_missing() ->
|
|||
AgentMessageEvent {
|
||||
message: "assistant text".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
))];
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use crate::error::CodexErr;
|
|||
use crate::error::Result;
|
||||
use crate::function_tool::FunctionCallError;
|
||||
use crate::memories::citations::get_thread_id_from_citations;
|
||||
use crate::memories::citations::parse_memory_citation;
|
||||
use crate::parse_turn_item;
|
||||
use crate::state_db;
|
||||
use crate::tools::parallel::ToolCallRuntime;
|
||||
|
|
@ -38,6 +39,22 @@ fn strip_hidden_assistant_markup(text: &str, plan_mode: bool) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn strip_hidden_assistant_markup_and_parse_memory_citation(
|
||||
text: &str,
|
||||
plan_mode: bool,
|
||||
) -> (
|
||||
String,
|
||||
Option<codex_protocol::memory_citation::MemoryCitation>,
|
||||
) {
|
||||
let (without_citations, citations) = strip_citations(text);
|
||||
let visible_text = if plan_mode {
|
||||
strip_proposed_plan_blocks(&without_citations)
|
||||
} else {
|
||||
without_citations
|
||||
};
|
||||
(visible_text, parse_memory_citation(citations))
|
||||
}
|
||||
|
||||
pub(crate) fn raw_assistant_output_text_from_item(item: &ResponseItem) -> Option<String> {
|
||||
if let ResponseItem::Message { role, content, .. } = item
|
||||
&& role == "assistant"
|
||||
|
|
@ -297,9 +314,11 @@ pub(crate) async fn handle_non_tool_response_item(
|
|||
codex_protocol::items::AgentMessageContent::Text { text } => text.as_str(),
|
||||
})
|
||||
.collect::<String>();
|
||||
let stripped = strip_hidden_assistant_markup(&combined, plan_mode);
|
||||
let (stripped, memory_citation) =
|
||||
strip_hidden_assistant_markup_and_parse_memory_citation(&combined, plan_mode);
|
||||
agent_message.content =
|
||||
vec![codex_protocol::items::AgentMessageContent::Text { text: stripped }];
|
||||
agent_message.memory_citation = memory_citation;
|
||||
}
|
||||
if let TurnItem::ImageGeneration(image_item) = &mut turn_item {
|
||||
match save_image_generation_result(&image_item.id, &image_item.result).await {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ fn assistant_output_text(text: &str) -> ResponseItem {
|
|||
#[tokio::test]
|
||||
async fn handle_non_tool_response_item_strips_citations_from_assistant_message() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
let item = assistant_output_text("hello<oai-mem-citation>doc1</oai-mem-citation> world");
|
||||
let item = assistant_output_text(
|
||||
"hello<oai-mem-citation><citation_entries>\nMEMORY.md:1-2|note=[x]\n</citation_entries>\n<rollout_ids>\n019cc2ea-1dff-7902-8d40-c8f6e5d83cc4\n</rollout_ids></oai-mem-citation> world",
|
||||
);
|
||||
|
||||
let turn_item = handle_non_tool_response_item(&session, &turn_context, &item, false)
|
||||
.await
|
||||
|
|
@ -40,6 +42,15 @@ async fn handle_non_tool_response_item_strips_citations_from_assistant_message()
|
|||
})
|
||||
.collect::<String>();
|
||||
assert_eq!(text, "hello world");
|
||||
let memory_citation = agent_message
|
||||
.memory_citation
|
||||
.expect("memory citation should be parsed");
|
||||
assert_eq!(memory_citation.entries.len(), 1);
|
||||
assert_eq!(memory_citation.entries[0].path, "MEMORY.md");
|
||||
assert_eq!(
|
||||
memory_citation.rollout_ids,
|
||||
vec!["019cc2ea-1dff-7902-8d40-c8f6e5d83cc4".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ async fn turn_timing_state_records_ttfm_independently_of_ttft() {
|
|||
id: "msg-1".to_string(),
|
||||
content: Vec::new(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}))
|
||||
.await
|
||||
.is_some()
|
||||
|
|
@ -68,6 +69,7 @@ async fn turn_timing_state_records_ttfm_independently_of_ttft() {
|
|||
id: "msg-2".to_string(),
|
||||
content: Vec::new(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}))
|
||||
.await,
|
||||
None
|
||||
|
|
|
|||
|
|
@ -749,6 +749,7 @@ fn agent_message_produces_item_completed_agent_message() {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "hello".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
);
|
||||
let out = ep.collect_thread_events(&ev);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::memory_citation::MemoryCitation;
|
||||
use crate::models::MessagePhase;
|
||||
use crate::models::WebSearchAction;
|
||||
use crate::protocol::AgentMessageEvent;
|
||||
|
|
@ -58,6 +59,9 @@ pub struct AgentMessageItem {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub phase: Option<MessagePhase>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub memory_citation: Option<MemoryCitation>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
|
||||
|
|
@ -201,6 +205,7 @@ impl AgentMessageItem {
|
|||
id: uuid::Uuid::new_v4().to_string(),
|
||||
content: content.to_vec(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +216,7 @@ impl AgentMessageItem {
|
|||
AgentMessageContent::Text { text } => EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: text.clone(),
|
||||
phase: self.phase.clone(),
|
||||
memory_citation: self.memory_citation.clone(),
|
||||
}),
|
||||
})
|
||||
.collect()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub mod custom_prompts;
|
|||
pub mod dynamic_tools;
|
||||
pub mod items;
|
||||
pub mod mcp;
|
||||
pub mod memory_citation;
|
||||
pub mod message_history;
|
||||
pub mod models;
|
||||
pub mod num_format;
|
||||
|
|
|
|||
20
codex-rs/protocol/src/memory_citation.rs
Normal file
20
codex-rs/protocol/src/memory_citation.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MemoryCitation {
|
||||
pub entries: Vec<MemoryCitationEntry>,
|
||||
pub rollout_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MemoryCitationEntry {
|
||||
pub path: String,
|
||||
pub line_start: u32,
|
||||
pub line_end: u32,
|
||||
pub note: String,
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ use crate::mcp::RequestId;
|
|||
use crate::mcp::Resource as McpResource;
|
||||
use crate::mcp::ResourceTemplate as McpResourceTemplate;
|
||||
use crate::mcp::Tool as McpTool;
|
||||
use crate::memory_citation::MemoryCitation;
|
||||
use crate::message_history::HistoryEntry;
|
||||
use crate::models::BaseInstructions;
|
||||
use crate::models::ContentItem;
|
||||
|
|
@ -1996,6 +1997,8 @@ pub struct AgentMessageEvent {
|
|||
pub message: String,
|
||||
#[serde(default)]
|
||||
pub phase: Option<MessagePhase>,
|
||||
#[serde(default)]
|
||||
pub memory_citation: Option<MemoryCitation>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ async fn resumed_initial_messages_render_history() {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "assistant reply".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
]),
|
||||
network_proxy: None,
|
||||
|
|
@ -251,6 +252,7 @@ async fn thread_snapshot_replay_does_not_duplicate_agent_message_history() {
|
|||
text: "assistant reply".to_string(),
|
||||
}],
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
@ -259,6 +261,7 @@ async fn thread_snapshot_replay_does_not_duplicate_agent_message_history() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "assistant reply".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -1547,6 +1550,7 @@ async fn live_agent_message_renders_during_review_mode() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Review progress update".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -1573,6 +1577,7 @@ async fn thread_snapshot_replay_preserves_agent_message_during_review_mode() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Review progress update".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -3551,6 +3556,7 @@ fn complete_assistant_message(
|
|||
text: text.to_string(),
|
||||
}],
|
||||
phase,
|
||||
memory_citation: None,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
@ -4146,6 +4152,7 @@ async fn live_legacy_agent_message_after_item_completed_does_not_duplicate_assis
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "hello".into(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -6010,6 +6017,7 @@ async fn slash_copy_is_unavailable_when_legacy_agent_message_is_not_repeated_on_
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Legacy final message".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
|
|
@ -10855,6 +10863,7 @@ async fn deltas_then_same_final_message_are_rendered_snapshot() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Here is the result.".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -7007,6 +7007,7 @@ guardian_approval = true
|
|||
id: "assistant-1".to_string(),
|
||||
text: "restored response".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
],
|
||||
status: TurnStatus::Completed,
|
||||
|
|
@ -7120,6 +7121,7 @@ guardian_approval = true
|
|||
id: "assistant-1".to_string(),
|
||||
text: "restored response".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
],
|
||||
status: TurnStatus::Completed,
|
||||
|
|
|
|||
|
|
@ -668,13 +668,33 @@ fn thread_item_to_core(item: &ThreadItem) -> Option<TurnItem> {
|
|||
.map(codex_app_server_protocol::UserInput::into_core)
|
||||
.collect(),
|
||||
})),
|
||||
ThreadItem::AgentMessage { id, text, phase } => {
|
||||
Some(TurnItem::AgentMessage(AgentMessageItem {
|
||||
id: id.clone(),
|
||||
content: vec![AgentMessageContent::Text { text: text.clone() }],
|
||||
phase: phase.clone(),
|
||||
}))
|
||||
}
|
||||
ThreadItem::AgentMessage {
|
||||
id,
|
||||
text,
|
||||
phase,
|
||||
memory_citation,
|
||||
} => Some(TurnItem::AgentMessage(AgentMessageItem {
|
||||
id: id.clone(),
|
||||
content: vec![AgentMessageContent::Text { text: text.clone() }],
|
||||
phase: phase.clone(),
|
||||
memory_citation: memory_citation.clone().map(|citation| {
|
||||
codex_protocol::memory_citation::MemoryCitation {
|
||||
entries: citation
|
||||
.entries
|
||||
.into_iter()
|
||||
.map(
|
||||
|entry| codex_protocol::memory_citation::MemoryCitationEntry {
|
||||
path: entry.path,
|
||||
line_start: entry.line_start,
|
||||
line_end: entry.line_end,
|
||||
note: entry.note,
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
rollout_ids: citation.thread_ids,
|
||||
}
|
||||
}),
|
||||
})),
|
||||
ThreadItem::Plan { id, text } => Some(TurnItem::Plan(PlanItem {
|
||||
id: id.clone(),
|
||||
text: text.clone(),
|
||||
|
|
@ -897,6 +917,7 @@ mod tests {
|
|||
id: item_id,
|
||||
text: "Hello from your coding assistant.".to_string(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
},
|
||||
thread_id: thread_id.clone(),
|
||||
turn_id: turn_id.clone(),
|
||||
|
|
@ -921,13 +942,19 @@ mod tests {
|
|||
);
|
||||
assert_eq!(completed.turn_id, turn_id);
|
||||
match &completed.item {
|
||||
TurnItem::AgentMessage(AgentMessageItem { id, content, phase }) => {
|
||||
TurnItem::AgentMessage(AgentMessageItem {
|
||||
id,
|
||||
content,
|
||||
phase,
|
||||
memory_citation,
|
||||
}) => {
|
||||
assert_eq!(id, "msg_123");
|
||||
let [AgentMessageContent::Text { text }] = content.as_slice() else {
|
||||
panic!("expected a single text content item");
|
||||
};
|
||||
assert_eq!(text, "Hello from your coding assistant.");
|
||||
assert_eq!(*phase, Some(MessagePhase::FinalAnswer));
|
||||
assert_eq!(*memory_citation, None);
|
||||
}
|
||||
_ => panic!("expected bridged agent message item"),
|
||||
}
|
||||
|
|
@ -1111,6 +1138,7 @@ mod tests {
|
|||
id: "assistant-1".to_string(),
|
||||
text: "hi".to_string(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
},
|
||||
],
|
||||
status: TurnStatus::Completed,
|
||||
|
|
|
|||
|
|
@ -1117,6 +1117,7 @@ mod tests {
|
|||
id: "assistant-1".to_string(),
|
||||
text: "assistant reply".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
},
|
||||
],
|
||||
status: TurnStatus::Completed,
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ async fn resumed_initial_messages_render_history() {
|
|||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "assistant reply".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
]),
|
||||
network_proxy: None,
|
||||
|
|
@ -250,6 +251,7 @@ async fn thread_snapshot_replay_does_not_duplicate_agent_message_history() {
|
|||
text: "assistant reply".to_string(),
|
||||
}],
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
@ -258,6 +260,7 @@ async fn thread_snapshot_replay_does_not_duplicate_agent_message_history() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "assistant reply".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -1546,6 +1549,7 @@ async fn live_agent_message_renders_during_review_mode() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Review progress update".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -1572,6 +1576,7 @@ async fn thread_snapshot_replay_preserves_agent_message_during_review_mode() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Review progress update".to_string(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -3521,6 +3526,7 @@ fn complete_assistant_message(
|
|||
text: text.to_string(),
|
||||
}],
|
||||
phase,
|
||||
memory_citation: None,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
@ -4110,6 +4116,7 @@ async fn live_legacy_agent_message_after_item_completed_does_not_duplicate_assis
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "hello".into(),
|
||||
phase: Some(MessagePhase::FinalAnswer),
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -5958,6 +5965,7 @@ async fn slash_copy_is_unavailable_when_legacy_agent_message_is_not_repeated_on_
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Legacy final message".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
|
|
@ -8497,11 +8505,8 @@ async fn permissions_selection_history_snapshot_full_access_to_default() {
|
|||
.approval_policy
|
||||
.set(AskForApproval::Never)
|
||||
.expect("set approval policy");
|
||||
chat.config
|
||||
.permissions
|
||||
.sandbox_policy
|
||||
.set(SandboxPolicy::DangerFullAccess)
|
||||
.expect("set sandbox policy");
|
||||
chat.config.permissions.sandbox_policy =
|
||||
Constrained::allow_any(SandboxPolicy::DangerFullAccess);
|
||||
|
||||
chat.open_permissions_popup();
|
||||
let popup = render_bottom_popup(&chat, 120);
|
||||
|
|
@ -10810,6 +10815,7 @@ async fn deltas_then_same_final_message_are_rendered_snapshot() {
|
|||
msg: EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "Here is the result.".into(),
|
||||
phase: None,
|
||||
memory_citation: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue