@nylorun/runtime 0.43.0-beta → 0.44.1-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/api/a2a/endpoint.js +1 -1
- package/dist/api/a2a/push.js +14 -1
- package/dist/api/a2a/routes.js +40 -26
- package/dist/api/a2a/tasks.d.ts +14 -0
- package/dist/api/a2a/tasks.js +42 -0
- package/dist/api/components.d.ts +1158 -280
- package/dist/artifacts/disk.js +7 -0
- package/dist/harness/main.js +8 -4
- package/dist/management-openapi.json +14 -4
- package/dist/openapi.json +433 -3
- package/dist/sandbox/pods/lifecycle.d.ts +5 -1
- package/dist/sandbox/pods/lifecycle.js +8 -0
- package/dist/sandbox/pods/network-gate.d.ts +6 -0
- package/dist/sandbox/pods/network-gate.js +20 -4
- package/dist/store/postgres/store.js +11 -0
- package/dist/store/types.d.ts +11 -1
- package/dist/tenant/agent-versions.d.ts +5 -1
- package/dist/tenant/agent-versions.js +8 -1
- package/dist/tenant/commands.d.ts +36 -7
- package/dist/tenant/commands.js +158 -40
- package/dist/tenant/context.d.ts +11 -0
- package/dist/tenant/sweep.js +44 -15
- package/dist/tuning.d.ts +3 -0
- package/dist/tuning.js +12 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.2.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Nylorun Runtime API",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.44.1-beta",
|
|
6
6
|
"x-nylorun-protocol": {
|
|
7
7
|
"min": 16,
|
|
8
8
|
"max": 18,
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"secret-routing",
|
|
45
45
|
"remove-tools",
|
|
46
46
|
"agent-triggers",
|
|
47
|
-
"steer"
|
|
47
|
+
"steer",
|
|
48
|
+
"queue-recovery"
|
|
48
49
|
]
|
|
49
50
|
},
|
|
50
51
|
"description": "For developers: agent manifests, Agents, sessions (with AG-UI and A2A) and artifacts, through `@nylorun/agents`. Every Tenant serves it on its one URL, beside the Management API (`/openapi/management.json`). Every request sends `Nylorun-Protocol`. Who may call each operation is its `security` and its `x-nylorun-credentials` and `x-nylorun-scopes` (the subject scopes that reach it) fields: an application key (servers) or a trusted issuer's token (browsers and apps)."
|
|
@@ -9341,6 +9342,12 @@
|
|
|
9341
9342
|
{
|
|
9342
9343
|
"$ref": "#/components/schemas/QueueTakenEvent"
|
|
9343
9344
|
},
|
|
9345
|
+
{
|
|
9346
|
+
"$ref": "#/components/schemas/QueueFailedEvent"
|
|
9347
|
+
},
|
|
9348
|
+
{
|
|
9349
|
+
"$ref": "#/components/schemas/QueueCancelledEvent"
|
|
9350
|
+
},
|
|
9344
9351
|
{
|
|
9345
9352
|
"$ref": "#/components/schemas/WakeBookedEvent"
|
|
9346
9353
|
},
|
|
@@ -9437,6 +9444,8 @@
|
|
|
9437
9444
|
"session.model": "#/components/schemas/SessionModelEvent",
|
|
9438
9445
|
"message.queued": "#/components/schemas/MessageQueuedEvent",
|
|
9439
9446
|
"queue.taken": "#/components/schemas/QueueTakenEvent",
|
|
9447
|
+
"queue.failed": "#/components/schemas/QueueFailedEvent",
|
|
9448
|
+
"queue.cancelled": "#/components/schemas/QueueCancelledEvent",
|
|
9440
9449
|
"wake.booked": "#/components/schemas/WakeBookedEvent",
|
|
9441
9450
|
"wake.cancelled": "#/components/schemas/WakeCancelledEvent",
|
|
9442
9451
|
"memory.updated": "#/components/schemas/MemoryUpdatedEvent",
|
|
@@ -12110,6 +12119,421 @@
|
|
|
12110
12119
|
"payload"
|
|
12111
12120
|
]
|
|
12112
12121
|
},
|
|
12122
|
+
"QueueFailedEvent": {
|
|
12123
|
+
"type": "object",
|
|
12124
|
+
"properties": {
|
|
12125
|
+
"schema": {
|
|
12126
|
+
"type": "string",
|
|
12127
|
+
"enum": [
|
|
12128
|
+
"nylorun.event/2"
|
|
12129
|
+
]
|
|
12130
|
+
},
|
|
12131
|
+
"eventId": {
|
|
12132
|
+
"type": "string"
|
|
12133
|
+
},
|
|
12134
|
+
"tenantId": {
|
|
12135
|
+
"type": "string",
|
|
12136
|
+
"minLength": 1
|
|
12137
|
+
},
|
|
12138
|
+
"sessionId": {
|
|
12139
|
+
"type": "string"
|
|
12140
|
+
},
|
|
12141
|
+
"runId": {
|
|
12142
|
+
"type": [
|
|
12143
|
+
"string",
|
|
12144
|
+
"null"
|
|
12145
|
+
]
|
|
12146
|
+
},
|
|
12147
|
+
"turnId": {
|
|
12148
|
+
"type": [
|
|
12149
|
+
"string",
|
|
12150
|
+
"null"
|
|
12151
|
+
]
|
|
12152
|
+
},
|
|
12153
|
+
"incarnation": {
|
|
12154
|
+
"type": "integer",
|
|
12155
|
+
"minimum": 0
|
|
12156
|
+
},
|
|
12157
|
+
"epoch": {
|
|
12158
|
+
"type": "integer",
|
|
12159
|
+
"minimum": 0
|
|
12160
|
+
},
|
|
12161
|
+
"seq": {
|
|
12162
|
+
"type": "integer",
|
|
12163
|
+
"minimum": 0
|
|
12164
|
+
},
|
|
12165
|
+
"cursor": {
|
|
12166
|
+
"type": "string"
|
|
12167
|
+
},
|
|
12168
|
+
"time": {
|
|
12169
|
+
"type": "string"
|
|
12170
|
+
},
|
|
12171
|
+
"schemaVersion": {
|
|
12172
|
+
"type": "integer",
|
|
12173
|
+
"exclusiveMinimum": 0
|
|
12174
|
+
},
|
|
12175
|
+
"source": {
|
|
12176
|
+
"type": "object",
|
|
12177
|
+
"properties": {
|
|
12178
|
+
"kind": {
|
|
12179
|
+
"type": "string",
|
|
12180
|
+
"enum": [
|
|
12181
|
+
"client",
|
|
12182
|
+
"core",
|
|
12183
|
+
"model-gate",
|
|
12184
|
+
"tool-gate",
|
|
12185
|
+
"egress-gate",
|
|
12186
|
+
"sandboxes",
|
|
12187
|
+
"edge",
|
|
12188
|
+
"init",
|
|
12189
|
+
"controller",
|
|
12190
|
+
"loop",
|
|
12191
|
+
"supervisor",
|
|
12192
|
+
"harness",
|
|
12193
|
+
"evidence",
|
|
12194
|
+
"operator",
|
|
12195
|
+
"human",
|
|
12196
|
+
"api"
|
|
12197
|
+
]
|
|
12198
|
+
},
|
|
12199
|
+
"id": {
|
|
12200
|
+
"type": "string"
|
|
12201
|
+
}
|
|
12202
|
+
},
|
|
12203
|
+
"required": [
|
|
12204
|
+
"kind",
|
|
12205
|
+
"id"
|
|
12206
|
+
]
|
|
12207
|
+
},
|
|
12208
|
+
"evidence": {
|
|
12209
|
+
"type": "string",
|
|
12210
|
+
"enum": [
|
|
12211
|
+
"observed",
|
|
12212
|
+
"measured",
|
|
12213
|
+
"attested",
|
|
12214
|
+
"claimed",
|
|
12215
|
+
"asserted"
|
|
12216
|
+
]
|
|
12217
|
+
},
|
|
12218
|
+
"principal": {
|
|
12219
|
+
"type": "object",
|
|
12220
|
+
"properties": {
|
|
12221
|
+
"kind": {
|
|
12222
|
+
"type": "string",
|
|
12223
|
+
"enum": [
|
|
12224
|
+
"application",
|
|
12225
|
+
"subject",
|
|
12226
|
+
"flow-host",
|
|
12227
|
+
"core",
|
|
12228
|
+
"trigger"
|
|
12229
|
+
]
|
|
12230
|
+
},
|
|
12231
|
+
"id": {
|
|
12232
|
+
"type": "string"
|
|
12233
|
+
}
|
|
12234
|
+
},
|
|
12235
|
+
"required": [
|
|
12236
|
+
"kind",
|
|
12237
|
+
"id"
|
|
12238
|
+
],
|
|
12239
|
+
"additionalProperties": false
|
|
12240
|
+
},
|
|
12241
|
+
"trace": {
|
|
12242
|
+
"type": "object",
|
|
12243
|
+
"properties": {
|
|
12244
|
+
"traceId": {
|
|
12245
|
+
"type": "string"
|
|
12246
|
+
},
|
|
12247
|
+
"spanId": {
|
|
12248
|
+
"type": "string"
|
|
12249
|
+
},
|
|
12250
|
+
"parentSpanId": {
|
|
12251
|
+
"type": "string"
|
|
12252
|
+
}
|
|
12253
|
+
},
|
|
12254
|
+
"required": [
|
|
12255
|
+
"traceId",
|
|
12256
|
+
"spanId"
|
|
12257
|
+
]
|
|
12258
|
+
},
|
|
12259
|
+
"visibility": {
|
|
12260
|
+
"type": "string",
|
|
12261
|
+
"enum": [
|
|
12262
|
+
"public",
|
|
12263
|
+
"internal",
|
|
12264
|
+
"restricted"
|
|
12265
|
+
]
|
|
12266
|
+
},
|
|
12267
|
+
"retention": {
|
|
12268
|
+
"type": "string",
|
|
12269
|
+
"enum": [
|
|
12270
|
+
"full",
|
|
12271
|
+
"metadata"
|
|
12272
|
+
]
|
|
12273
|
+
},
|
|
12274
|
+
"type": {
|
|
12275
|
+
"type": "string",
|
|
12276
|
+
"enum": [
|
|
12277
|
+
"queue.failed"
|
|
12278
|
+
]
|
|
12279
|
+
},
|
|
12280
|
+
"payload": {
|
|
12281
|
+
"type": "object",
|
|
12282
|
+
"properties": {
|
|
12283
|
+
"queuedMessageIds": {
|
|
12284
|
+
"type": "array",
|
|
12285
|
+
"items": {
|
|
12286
|
+
"type": "string"
|
|
12287
|
+
},
|
|
12288
|
+
"minItems": 1
|
|
12289
|
+
},
|
|
12290
|
+
"error": {
|
|
12291
|
+
"type": "object",
|
|
12292
|
+
"properties": {
|
|
12293
|
+
"code": {
|
|
12294
|
+
"type": "string"
|
|
12295
|
+
},
|
|
12296
|
+
"message": {
|
|
12297
|
+
"type": "string"
|
|
12298
|
+
},
|
|
12299
|
+
"reason": {
|
|
12300
|
+
"type": "string"
|
|
12301
|
+
}
|
|
12302
|
+
},
|
|
12303
|
+
"required": [
|
|
12304
|
+
"code",
|
|
12305
|
+
"message"
|
|
12306
|
+
],
|
|
12307
|
+
"additionalProperties": {}
|
|
12308
|
+
}
|
|
12309
|
+
},
|
|
12310
|
+
"required": [
|
|
12311
|
+
"queuedMessageIds",
|
|
12312
|
+
"error"
|
|
12313
|
+
],
|
|
12314
|
+
"additionalProperties": {}
|
|
12315
|
+
}
|
|
12316
|
+
},
|
|
12317
|
+
"required": [
|
|
12318
|
+
"schema",
|
|
12319
|
+
"eventId",
|
|
12320
|
+
"tenantId",
|
|
12321
|
+
"sessionId",
|
|
12322
|
+
"runId",
|
|
12323
|
+
"turnId",
|
|
12324
|
+
"incarnation",
|
|
12325
|
+
"epoch",
|
|
12326
|
+
"seq",
|
|
12327
|
+
"cursor",
|
|
12328
|
+
"time",
|
|
12329
|
+
"schemaVersion",
|
|
12330
|
+
"source",
|
|
12331
|
+
"evidence",
|
|
12332
|
+
"visibility",
|
|
12333
|
+
"retention",
|
|
12334
|
+
"type",
|
|
12335
|
+
"payload"
|
|
12336
|
+
]
|
|
12337
|
+
},
|
|
12338
|
+
"QueueCancelledEvent": {
|
|
12339
|
+
"type": "object",
|
|
12340
|
+
"properties": {
|
|
12341
|
+
"schema": {
|
|
12342
|
+
"type": "string",
|
|
12343
|
+
"enum": [
|
|
12344
|
+
"nylorun.event/2"
|
|
12345
|
+
]
|
|
12346
|
+
},
|
|
12347
|
+
"eventId": {
|
|
12348
|
+
"type": "string"
|
|
12349
|
+
},
|
|
12350
|
+
"tenantId": {
|
|
12351
|
+
"type": "string",
|
|
12352
|
+
"minLength": 1
|
|
12353
|
+
},
|
|
12354
|
+
"sessionId": {
|
|
12355
|
+
"type": "string"
|
|
12356
|
+
},
|
|
12357
|
+
"runId": {
|
|
12358
|
+
"type": [
|
|
12359
|
+
"string",
|
|
12360
|
+
"null"
|
|
12361
|
+
]
|
|
12362
|
+
},
|
|
12363
|
+
"turnId": {
|
|
12364
|
+
"type": [
|
|
12365
|
+
"string",
|
|
12366
|
+
"null"
|
|
12367
|
+
]
|
|
12368
|
+
},
|
|
12369
|
+
"incarnation": {
|
|
12370
|
+
"type": "integer",
|
|
12371
|
+
"minimum": 0
|
|
12372
|
+
},
|
|
12373
|
+
"epoch": {
|
|
12374
|
+
"type": "integer",
|
|
12375
|
+
"minimum": 0
|
|
12376
|
+
},
|
|
12377
|
+
"seq": {
|
|
12378
|
+
"type": "integer",
|
|
12379
|
+
"minimum": 0
|
|
12380
|
+
},
|
|
12381
|
+
"cursor": {
|
|
12382
|
+
"type": "string"
|
|
12383
|
+
},
|
|
12384
|
+
"time": {
|
|
12385
|
+
"type": "string"
|
|
12386
|
+
},
|
|
12387
|
+
"schemaVersion": {
|
|
12388
|
+
"type": "integer",
|
|
12389
|
+
"exclusiveMinimum": 0
|
|
12390
|
+
},
|
|
12391
|
+
"source": {
|
|
12392
|
+
"type": "object",
|
|
12393
|
+
"properties": {
|
|
12394
|
+
"kind": {
|
|
12395
|
+
"type": "string",
|
|
12396
|
+
"enum": [
|
|
12397
|
+
"client",
|
|
12398
|
+
"core",
|
|
12399
|
+
"model-gate",
|
|
12400
|
+
"tool-gate",
|
|
12401
|
+
"egress-gate",
|
|
12402
|
+
"sandboxes",
|
|
12403
|
+
"edge",
|
|
12404
|
+
"init",
|
|
12405
|
+
"controller",
|
|
12406
|
+
"loop",
|
|
12407
|
+
"supervisor",
|
|
12408
|
+
"harness",
|
|
12409
|
+
"evidence",
|
|
12410
|
+
"operator",
|
|
12411
|
+
"human",
|
|
12412
|
+
"api"
|
|
12413
|
+
]
|
|
12414
|
+
},
|
|
12415
|
+
"id": {
|
|
12416
|
+
"type": "string"
|
|
12417
|
+
}
|
|
12418
|
+
},
|
|
12419
|
+
"required": [
|
|
12420
|
+
"kind",
|
|
12421
|
+
"id"
|
|
12422
|
+
]
|
|
12423
|
+
},
|
|
12424
|
+
"evidence": {
|
|
12425
|
+
"type": "string",
|
|
12426
|
+
"enum": [
|
|
12427
|
+
"observed",
|
|
12428
|
+
"measured",
|
|
12429
|
+
"attested",
|
|
12430
|
+
"claimed",
|
|
12431
|
+
"asserted"
|
|
12432
|
+
]
|
|
12433
|
+
},
|
|
12434
|
+
"principal": {
|
|
12435
|
+
"type": "object",
|
|
12436
|
+
"properties": {
|
|
12437
|
+
"kind": {
|
|
12438
|
+
"type": "string",
|
|
12439
|
+
"enum": [
|
|
12440
|
+
"application",
|
|
12441
|
+
"subject",
|
|
12442
|
+
"flow-host",
|
|
12443
|
+
"core",
|
|
12444
|
+
"trigger"
|
|
12445
|
+
]
|
|
12446
|
+
},
|
|
12447
|
+
"id": {
|
|
12448
|
+
"type": "string"
|
|
12449
|
+
}
|
|
12450
|
+
},
|
|
12451
|
+
"required": [
|
|
12452
|
+
"kind",
|
|
12453
|
+
"id"
|
|
12454
|
+
],
|
|
12455
|
+
"additionalProperties": false
|
|
12456
|
+
},
|
|
12457
|
+
"trace": {
|
|
12458
|
+
"type": "object",
|
|
12459
|
+
"properties": {
|
|
12460
|
+
"traceId": {
|
|
12461
|
+
"type": "string"
|
|
12462
|
+
},
|
|
12463
|
+
"spanId": {
|
|
12464
|
+
"type": "string"
|
|
12465
|
+
},
|
|
12466
|
+
"parentSpanId": {
|
|
12467
|
+
"type": "string"
|
|
12468
|
+
}
|
|
12469
|
+
},
|
|
12470
|
+
"required": [
|
|
12471
|
+
"traceId",
|
|
12472
|
+
"spanId"
|
|
12473
|
+
]
|
|
12474
|
+
},
|
|
12475
|
+
"visibility": {
|
|
12476
|
+
"type": "string",
|
|
12477
|
+
"enum": [
|
|
12478
|
+
"public",
|
|
12479
|
+
"internal",
|
|
12480
|
+
"restricted"
|
|
12481
|
+
]
|
|
12482
|
+
},
|
|
12483
|
+
"retention": {
|
|
12484
|
+
"type": "string",
|
|
12485
|
+
"enum": [
|
|
12486
|
+
"full",
|
|
12487
|
+
"metadata"
|
|
12488
|
+
]
|
|
12489
|
+
},
|
|
12490
|
+
"type": {
|
|
12491
|
+
"type": "string",
|
|
12492
|
+
"enum": [
|
|
12493
|
+
"queue.cancelled"
|
|
12494
|
+
]
|
|
12495
|
+
},
|
|
12496
|
+
"payload": {
|
|
12497
|
+
"type": "object",
|
|
12498
|
+
"properties": {
|
|
12499
|
+
"queuedMessageIds": {
|
|
12500
|
+
"type": "array",
|
|
12501
|
+
"items": {
|
|
12502
|
+
"type": "string"
|
|
12503
|
+
},
|
|
12504
|
+
"minItems": 1
|
|
12505
|
+
},
|
|
12506
|
+
"reason": {
|
|
12507
|
+
"type": "string"
|
|
12508
|
+
}
|
|
12509
|
+
},
|
|
12510
|
+
"required": [
|
|
12511
|
+
"queuedMessageIds"
|
|
12512
|
+
],
|
|
12513
|
+
"additionalProperties": {}
|
|
12514
|
+
}
|
|
12515
|
+
},
|
|
12516
|
+
"required": [
|
|
12517
|
+
"schema",
|
|
12518
|
+
"eventId",
|
|
12519
|
+
"tenantId",
|
|
12520
|
+
"sessionId",
|
|
12521
|
+
"runId",
|
|
12522
|
+
"turnId",
|
|
12523
|
+
"incarnation",
|
|
12524
|
+
"epoch",
|
|
12525
|
+
"seq",
|
|
12526
|
+
"cursor",
|
|
12527
|
+
"time",
|
|
12528
|
+
"schemaVersion",
|
|
12529
|
+
"source",
|
|
12530
|
+
"evidence",
|
|
12531
|
+
"visibility",
|
|
12532
|
+
"retention",
|
|
12533
|
+
"type",
|
|
12534
|
+
"payload"
|
|
12535
|
+
]
|
|
12536
|
+
},
|
|
12113
12537
|
"WakeBookedEvent": {
|
|
12114
12538
|
"type": "object",
|
|
12115
12539
|
"properties": {
|
|
@@ -34455,6 +34879,12 @@
|
|
|
34455
34879
|
{
|
|
34456
34880
|
"$ref": "#/components/schemas/QueueTakenEvent"
|
|
34457
34881
|
},
|
|
34882
|
+
{
|
|
34883
|
+
"$ref": "#/components/schemas/QueueFailedEvent"
|
|
34884
|
+
},
|
|
34885
|
+
{
|
|
34886
|
+
"$ref": "#/components/schemas/QueueCancelledEvent"
|
|
34887
|
+
},
|
|
34458
34888
|
{
|
|
34459
34889
|
"$ref": "#/components/schemas/WakeBookedEvent"
|
|
34460
34890
|
},
|
|
@@ -36887,7 +37317,7 @@
|
|
|
36887
37317
|
"A2A"
|
|
36888
37318
|
],
|
|
36889
37319
|
"summary": "Call an agent over A2A",
|
|
36890
|
-
"description": "A2A 1.0 JSON-RPC, for a subject, under the Nylorun profile v2 (Host feature `a2a-profile-v2`). `SendMessage` blocks up to the Runtime limit `a2aWaitMs` (5 minutes by default; then the task is answered still `WORKING`) unless `returnImmediately`; `GetTask` (with `historyLength`), `CancelTask` and `ListTasks`; and the four push notification config methods, plus `configuration.taskPushNotificationConfig` in `SendMessage`: each update is POSTed as one `StreamResponse`, signed with Standard Webhooks (`webhook-id`, `webhook-timestamp`, `webhook-signature` with the Runtime's `a2a.push.secret`) and `X-A2A-Notification-Token`, at least once, retried for up to 24 hours, to hosts the Runtime allows (`a2a.push.allowHosts` for private ones). A message to a busy context is queued and answered with the task that will take it (`TASK_STATE_SUBMITTED`); `message.metadata.delivery: \"reject\"` asks for `UnsupportedOperationError` (reason `CONTEXT_BUSY`) instead. `message.metadata.removeTools` (Host feature `remove-tools`) names the tools a new message's turn may not use, as a session message's `removeTools`. A message is text, one data part, or text with `raw` files (stored as artifacts of the context's session) and `url` files (fetched by the Runtime), each at most the Runtime limit `inlineFileBytes` (20 MiB by default). An approval, question or connection the task waits for (`AUTH_REQUIRED` or `INPUT_REQUIRED`) is shown under `interactions/v1` and answered on the same task with `{ interactionId, approved }` or `{ interactionId, value }` under that URI in the message's `metadata`; text never approves. Artifacts carry the turn's output and the files it wrote, as `url` parts at `/v1/a2a/files/…` with `files/v1`; the task's metadata carries `progress/v1`, `telemetry/v1` and `effects/v1`. Extension data is answered only for the extensions activated with `A2A-Extensions`. A context is one session per subject, agent and `contextId`; a task is one turn. JSON-RPC errors are answered with 200; limits, scopes and unavailable streams stay HTTP errors. Not served: streaming, `GetExtendedAgentCard`.",
|
|
37320
|
+
"description": "A2A 1.0 JSON-RPC, for a subject, under the Nylorun profile v2 (Host feature `a2a-profile-v2`). `SendMessage` blocks up to the Runtime limit `a2aWaitMs` (5 minutes by default; then the task is answered still `WORKING`) unless `returnImmediately`; `GetTask` (with `historyLength`), `CancelTask` and `ListTasks`; and the four push notification config methods, plus `configuration.taskPushNotificationConfig` in `SendMessage`: each update is POSTed as one `StreamResponse`, signed with Standard Webhooks (`webhook-id`, `webhook-timestamp`, `webhook-signature` with the Runtime's `a2a.push.secret`) and `X-A2A-Notification-Token`, at least once, retried for up to 24 hours, to hosts the Runtime allows (`a2a.push.allowHosts` for private ones). A message to a busy context is queued and answered with the task that will take it (`TASK_STATE_SUBMITTED`); `message.metadata.delivery: \"reject\"` asks for `UnsupportedOperationError` (reason `CONTEXT_BUSY`) instead. A queued task never waits for good (Host feature `queue-recovery`): when its Agent refuses its turn's start (a disk copy, a lost pod), the start is tried again until the Runtime limit `queuedStartMs` (15 minutes by default), and then, or at once for a refusal no retry changes, the task is `TASK_STATE_FAILED` with a status message saying why; `CancelTask` on a queued task takes it out of the queue, a task running in the context or not, and answers `TASK_STATE_CANCELED`. Both are pushed. `message.metadata.removeTools` (Host feature `remove-tools`) names the tools a new message's turn may not use, as a session message's `removeTools`. A message is text, one data part, or text with `raw` files (stored as artifacts of the context's session) and `url` files (fetched by the Runtime), each at most the Runtime limit `inlineFileBytes` (20 MiB by default). An approval, question or connection the task waits for (`AUTH_REQUIRED` or `INPUT_REQUIRED`) is shown under `interactions/v1` and answered on the same task with `{ interactionId, approved }` or `{ interactionId, value }` under that URI in the message's `metadata`; text never approves. Artifacts carry the turn's output and the files it wrote, as `url` parts at `/v1/a2a/files/…` with `files/v1`; the task's metadata carries `progress/v1`, `telemetry/v1` and `effects/v1`. Extension data is answered only for the extensions activated with `A2A-Extensions`. A context is one session per subject, agent and `contextId`; a task is one turn. JSON-RPC errors are answered with 200; limits, scopes and unavailable streams stay HTTP errors. Not served: streaming, `GetExtendedAgentCard`.",
|
|
36891
37321
|
"externalDocs": {
|
|
36892
37322
|
"description": "The A2A specification",
|
|
36893
37323
|
"url": "https://a2a-protocol.org/latest/specification/"
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
* is not the row's is applied again.
|
|
15
15
|
* - **Idle** (`trigger: idle`): no turn on a session that names it, and none ended within its
|
|
16
16
|
* `lifecycle.idle` (at most the Tenant's `limits.idle`) → `Suspended` (`agent.suspended`,
|
|
17
|
-
* reason `idle`). The volume is kept; the next turn start asks for `Running` again.
|
|
17
|
+
* reason `idle`). The volume is kept; the next turn start asks for `Running` again. Every
|
|
18
|
+
* running, ready pod has its idle timer armed (at `lastActiveAt` + idle) whenever it is
|
|
19
|
+
* reconciled, whichever path woke it: a turn's end arms it too, but a wake with no turn end
|
|
20
|
+
* (a disk copy's `wakePod`, commands through the session's sandbox route) armed nothing and
|
|
21
|
+
* ran on for days. A timer that fires during a turn looks again one idle period later.
|
|
18
22
|
* - **Lost**: an incarnation that has run (a pod joined) whose Sandbox is gone or whose volume
|
|
19
23
|
* is missing is `lost` (`agent.lost`): its host epoch moves, its Sandbox is deleted, and
|
|
20
24
|
* only a reset brings the Environment back. agent-sandbox recreates a deleted claim empty, so
|
|
@@ -118,6 +118,11 @@ export function decide(facts) {
|
|
|
118
118
|
else
|
|
119
119
|
arm.push({ timer: "idle", at: due });
|
|
120
120
|
}
|
|
121
|
+
else if (facts.trigger === "idle" && desired === "running") {
|
|
122
|
+
// Busy: a turn's end arms the timer again, but look again anyway, so a turn that never ends
|
|
123
|
+
// cleanly doesn't keep the pod running for good.
|
|
124
|
+
arm.push({ timer: "idle", at: now + facts.config.idleMs });
|
|
125
|
+
}
|
|
121
126
|
// An incarnation a pod has joined, whose Sandbox or volume is gone: lost.
|
|
122
127
|
if (pod.podUid !== undefined && (!status.exists || status.deleting || status.volume === "missing")) {
|
|
123
128
|
const reason = !status.exists
|
|
@@ -174,6 +179,9 @@ export function decide(facts) {
|
|
|
174
179
|
const digest = pod.imageDigest === undefined ? imageDigestOf(status.imageID, facts.image) : undefined;
|
|
175
180
|
if (digest !== undefined)
|
|
176
181
|
patch.imageDigest = digest;
|
|
182
|
+
// Whatever woke it, a running pod has an idle timer (the idle trigger armed its own above).
|
|
183
|
+
if (facts.trigger !== "idle")
|
|
184
|
+
arm.push({ timer: "idle", at: Date.parse(pod.lastActiveAt ?? row.createdAt) + facts.config.idleMs });
|
|
177
185
|
return done();
|
|
178
186
|
}
|
|
179
187
|
const startedAt = Date.parse(pod.startedAt ?? row.updatedAt);
|
|
@@ -16,9 +16,15 @@ export interface NetworkGateOptions {
|
|
|
16
16
|
readonly pauseMs?: number;
|
|
17
17
|
/** Consecutive failed connections that prove an address blocked. Default `harness.networkConfirmations` (3). */
|
|
18
18
|
readonly confirmations?: number;
|
|
19
|
+
/**
|
|
20
|
+
* The pod starts on a disk an earlier pod of this sandbox used (a wake): check quickly, with
|
|
21
|
+
* `harness.wakeNetworkProbeMs` and `harness.wakeNetworkConfirmations`, until an address answers.
|
|
22
|
+
*/
|
|
23
|
+
readonly wake?: boolean;
|
|
19
24
|
readonly log?: (message: string, fields: Record<string, unknown>) => void;
|
|
20
25
|
}
|
|
21
26
|
/** Resolves once every address is blocked; rejects past the timeout. */
|
|
22
27
|
export declare function awaitNetworkPolicy(options: NetworkGateOptions): Promise<{
|
|
23
28
|
waitedMs: number;
|
|
29
|
+
check: "full" | "wake";
|
|
24
30
|
}>;
|
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
* `KUBERNETES_SERVICE_HOST:KUBERNETES_SERVICE_PORT`, which the kubelet always sets) until each
|
|
7
7
|
* fails `harness.networkConfirmations` times in a row (Host tuning) (refused, unreachable or timed out). A connection that
|
|
8
8
|
* succeeds starts the count again. Past `timeoutMs` the engine exits, and the pod restarts it.
|
|
9
|
+
*
|
|
10
|
+
* A wake (`wake`: the disk already holds the engine's `volume-id`, so a pod of this sandbox ran
|
|
11
|
+
* in this namespace before) starts the pod into a namespace whose policy has long been in force.
|
|
12
|
+
* The gate then takes `harness.wakeNetworkConfirmations` failed probes of
|
|
13
|
+
* `harness.wakeNetworkProbeMs` (1 of 150 ms) instead of three of a second: 152 ms instead of
|
|
14
|
+
* 3.0 s per wake (the A2 wake lab). It trusts a wake's quick check only while nothing answers:
|
|
15
|
+
* once a blocked address connects, the policy is not in force, and the gate goes back to the full
|
|
16
|
+
* check for every address.
|
|
9
17
|
*/
|
|
10
18
|
import { connect } from "node:net";
|
|
11
19
|
import { hostTuning } from "../../tuning.js";
|
|
@@ -47,14 +55,21 @@ export async function awaitNetworkPolicy(options) {
|
|
|
47
55
|
const tuning = hostTuning().harness;
|
|
48
56
|
const started = Date.now();
|
|
49
57
|
const deadline = started + (options.timeoutMs ?? tuning.networkPolicyTimeoutMs);
|
|
50
|
-
const
|
|
58
|
+
const full = {
|
|
59
|
+
needed: options.confirmations ?? tuning.networkConfirmations,
|
|
60
|
+
attemptMs: options.attemptMs ?? tuning.networkProbeMs,
|
|
61
|
+
};
|
|
62
|
+
const quick = { needed: tuning.wakeNetworkConfirmations, attemptMs: tuning.wakeNetworkProbeMs };
|
|
63
|
+
let check = options.wake ? "wake" : "full";
|
|
51
64
|
for (const address of options.addresses) {
|
|
52
65
|
let failures = 0;
|
|
53
66
|
let opened = 0;
|
|
54
|
-
while (failures < needed) {
|
|
67
|
+
while (failures < (check === "wake" ? quick : full).needed) {
|
|
55
68
|
if (Date.now() > deadline)
|
|
56
69
|
throw new Error(`The pod's NetworkPolicy is not in force: ${address.host}:${address.port} still answered ${opened} time(s)`);
|
|
57
|
-
if (await opens(address,
|
|
70
|
+
if (await opens(address, (check === "wake" ? quick : full).attemptMs)) {
|
|
71
|
+
// An address the policy blocks answered: whatever the disk says, check in full.
|
|
72
|
+
check = "full";
|
|
58
73
|
failures = 0;
|
|
59
74
|
opened += 1;
|
|
60
75
|
await new Promise((resolve) => setTimeout(resolve, options.pauseMs ?? tuning.networkPauseMs));
|
|
@@ -65,7 +80,8 @@ export async function awaitNetworkPolicy(options) {
|
|
|
65
80
|
options.log?.("sandbox_network_policy_checked", {
|
|
66
81
|
address: `${address.host}:${address.port}`,
|
|
67
82
|
openedBefore: opened,
|
|
83
|
+
check,
|
|
68
84
|
});
|
|
69
85
|
}
|
|
70
|
-
return { waitedMs: Date.now() - started };
|
|
86
|
+
return { waitedMs: Date.now() - started, check };
|
|
71
87
|
}
|
|
@@ -1270,6 +1270,17 @@ class PostgresTx {
|
|
|
1270
1270
|
if (ids.length > 0)
|
|
1271
1271
|
await this.db.delete(sessionQueue).where(inArray(sessionQueue.id, [...ids]));
|
|
1272
1272
|
}
|
|
1273
|
+
async queuedSessions(options) {
|
|
1274
|
+
this.check();
|
|
1275
|
+
const rows = await this.db
|
|
1276
|
+
.selectDistinct({ id: sessionQueue.sessionId })
|
|
1277
|
+
.from(sessionQueue)
|
|
1278
|
+
.innerJoin(sessions, eq(sessions.id, sessionQueue.sessionId))
|
|
1279
|
+
.where(and(inArray(sessions.status, [...options.statuses]), options.after === undefined ? undefined : gt(sessionQueue.sessionId, options.after), options.environmentId === undefined ? undefined : eq(sessions.environmentId, options.environmentId)))
|
|
1280
|
+
.orderBy(sessionQueue.sessionId)
|
|
1281
|
+
.limit(options.limit);
|
|
1282
|
+
return rows.map((row) => row.id);
|
|
1283
|
+
}
|
|
1273
1284
|
// --- triggers (track T4) ----------------------------------------------------
|
|
1274
1285
|
async agentTriggers(agentId) {
|
|
1275
1286
|
this.check();
|
package/dist/store/types.d.ts
CHANGED
|
@@ -733,8 +733,18 @@ export interface Tx {
|
|
|
733
733
|
/** A session's queued messages, first to go first. */
|
|
734
734
|
queuedMessages(sessionId: string): Promise<QueuedMessageRow[]>;
|
|
735
735
|
countQueuedMessages(sessionId: string): Promise<number>;
|
|
736
|
-
/** Removes queued messages a turn took. */
|
|
736
|
+
/** Removes queued messages: a turn took them, or they failed or were cancelled. */
|
|
737
737
|
deleteQueuedMessages(ids: readonly string[]): Promise<void>;
|
|
738
|
+
/**
|
|
739
|
+
* The ids of sessions with queued messages whose status is one of `statuses` (no turn holds
|
|
740
|
+
* them), by id after `after`, optionally on one Environment: queues a refused start left waiting.
|
|
741
|
+
*/
|
|
742
|
+
queuedSessions(options: {
|
|
743
|
+
statuses: readonly string[];
|
|
744
|
+
limit: number;
|
|
745
|
+
after?: string;
|
|
746
|
+
environmentId?: string;
|
|
747
|
+
}): Promise<string[]>;
|
|
738
748
|
agentTriggers(agentId: string): Promise<AgentTriggerRow[]>;
|
|
739
749
|
/** One trigger's state; with `lock`, its row is locked until the transaction ends. */
|
|
740
750
|
agentTrigger(agentId: string, triggerId: string, options?: {
|
|
@@ -117,7 +117,11 @@ export declare function waitingFor(agent: Pick<Environment, "targetVersion" | "a
|
|
|
117
117
|
export declare function idleMsOf(config: TenantSandboxConfig, agent: Environment): number;
|
|
118
118
|
/**
|
|
119
119
|
* The harness of pod Agent `id` joined at host epoch `epoch` (its `hello`): a start on a new
|
|
120
|
-
* version succeeded, setup included. Clears the start check and the failed version
|
|
120
|
+
* version succeeded, setup included. Clears the start check and the failed version, and wakes
|
|
121
|
+
* every session on the Agent with a turn waiting: an advance refuses a segment while its pod
|
|
122
|
+
* starts on a new version (`segment.pod.starting`) and tries again only after
|
|
123
|
+
* `tenant.unavailableRetryMs`, so without the wake the turn waits up to that long after its
|
|
124
|
+
* engine is there. The wake's dedupe key is the epoch's: one wake per session per start.
|
|
121
125
|
*/
|
|
122
126
|
export declare function passStartCheck(ctx: TenantContext, id: string, epoch: number): Promise<void>;
|
|
123
127
|
/**
|
|
@@ -334,7 +334,11 @@ export function idleMsOf(config, agent) {
|
|
|
334
334
|
}
|
|
335
335
|
/**
|
|
336
336
|
* The harness of pod Agent `id` joined at host epoch `epoch` (its `hello`): a start on a new
|
|
337
|
-
* version succeeded, setup included. Clears the start check and the failed version
|
|
337
|
+
* version succeeded, setup included. Clears the start check and the failed version, and wakes
|
|
338
|
+
* every session on the Agent with a turn waiting: an advance refuses a segment while its pod
|
|
339
|
+
* starts on a new version (`segment.pod.starting`) and tries again only after
|
|
340
|
+
* `tenant.unavailableRetryMs`, so without the wake the turn waits up to that long after its
|
|
341
|
+
* engine is there. The wake's dedupe key is the epoch's: one wake per session per start.
|
|
338
342
|
*/
|
|
339
343
|
export async function passStartCheck(ctx, id, epoch) {
|
|
340
344
|
await ctx.store.tx(async (t) => {
|
|
@@ -342,6 +346,9 @@ export async function passStartCheck(ctx, id, epoch) {
|
|
|
342
346
|
if (!agent?.startCheck || agent.pod?.hostEpoch !== epoch)
|
|
343
347
|
return;
|
|
344
348
|
await t.updateEnvironment(id, { startCheck: null, failedVersion: null }, new Date().toISOString());
|
|
349
|
+
for (const session of await t.sessionsOnEnvironment(id))
|
|
350
|
+
if (session.activeTurnId !== null)
|
|
351
|
+
await t.wake(session.id, { reason: "recover", dedupeKey: `start:${id}:${epoch}` });
|
|
345
352
|
});
|
|
346
353
|
}
|
|
347
354
|
/**
|