stitchkit 0.70.1 → 0.70.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-runtime/harness-control.d.ts +2 -0
- package/dist/agent-runtime/harness-control.d.ts.map +1 -1
- package/dist/agent-runtime/history-chronology.d.ts +19 -0
- package/dist/agent-runtime/history-chronology.d.ts.map +1 -0
- package/dist/agent-runtime/history.d.ts.map +1 -1
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-status.d.ts.map +1 -1
- package/dist/agent-runtime-browser.js +51 -51
- package/dist/agent-runtime-coding-tools.js +2 -2
- package/dist/agent-runtime-harness.js +60 -16
- package/dist/agent-runtime-openrouter.js +2 -2
- package/dist/agent-runtime-sqlite-bun.js +5 -5
- package/dist/agent-runtime-sqlite-node.js +5 -5
- package/dist/agent-runtime.js +110 -110
- package/dist/application-grammy.js +2 -2
- package/dist/application.js +63 -63
- package/dist/browser/live-state.d.ts +126 -0
- package/dist/browser/live-state.d.ts.map +1 -0
- package/dist/cli.js +5 -5
- package/dist/contract/index.js +20 -20
- package/dist/declaration.d.ts +4 -0
- package/dist/declaration.d.ts.map +1 -1
- package/dist/declaration.js +22 -22
- package/dist/files.js +3 -3
- package/dist/{index-vy5bjy07.js → index-4qfqy0m6.js} +21 -31
- package/dist/{index-10gbbbaa.js → index-9sx8tbz2.js} +1 -1
- package/dist/{index-4g196jmf.js → index-a01jky8m.js} +69 -7
- package/dist/{index-hsabxjz0.js → index-jw81xr75.js} +1 -1
- package/dist/index-y2s6h5bf.js +83 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +667 -56
- package/dist/node.js +26 -26
- package/dist/observability/index.js +22 -22
- package/dist/react.js +2 -2
- package/dist/realtime/contract.d.ts +30 -11
- package/dist/realtime/contract.d.ts.map +1 -1
- package/dist/realtime/index.d.ts +1 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/server/index.js +79 -79
- package/dist/server/multipart.d.ts.map +1 -1
- package/dist/testing/surface-conformance.d.ts +4 -2
- package/dist/testing/surface-conformance.d.ts.map +1 -1
- package/dist/testing.js +122 -111
- package/dist/tools.js +57 -57
- package/llms-full.txt +224 -4
- package/package.json +1 -1
- package/dist/index-es0h4w26.js +0 -63
package/llms-full.txt
CHANGED
|
@@ -1779,6 +1779,14 @@ for a custom raw transport. It uses the same descriptor and returns
|
|
|
1779
1779
|
`{ files, fields, rollback }`; contract endpoints should prefer the automatic
|
|
1780
1780
|
dispatcher path.
|
|
1781
1781
|
|
|
1782
|
+
Both delivery modes preserve UTF-8 `filename` metadata, including browser `FormData` names. For
|
|
1783
|
+
interoperability, a UTF-8 percent-encoded `filename*` parameter takes precedence over `filename`;
|
|
1784
|
+
unsupported charsets or malformed encoding are rejected rather than falling back silently. Literal
|
|
1785
|
+
percent sequences in ordinary `filename` are not decoded. Filenames remain untrusted metadata,
|
|
1786
|
+
not safe filesystem paths. Part headers have a 64 KiB byte limit, are case-insensitive and reject
|
|
1787
|
+
duplicates, folding, invalid header names and control characters. Disposition parameters reject
|
|
1788
|
+
duplicates and unsafe field names; declared part sizes must be nonnegative safe decimal integers.
|
|
1789
|
+
|
|
1782
1790
|
### Rate limiting
|
|
1783
1791
|
|
|
1784
1792
|
```ts
|
|
@@ -4068,6 +4076,12 @@ revalidates the signature/tool call/input before the original direct tool reache
|
|
|
4068
4076
|
fence. Reconnect and SQLite reopen require no promise registry. Remembered policy and a stronger
|
|
4069
4077
|
cross-crash exactly-once guarantee remain application concerns.
|
|
4070
4078
|
|
|
4079
|
+
Approval requests suspend a call; they do not settle its result. History carries exact call and
|
|
4080
|
+
approval identity across assistant/tool records, so an approved result can precede the next signed
|
|
4081
|
+
request in a successor run. Automatic decisions follow the same chronology. Unknown/duplicate
|
|
4082
|
+
responses and results with a different call or tool name are invalid; dropping an invalid active
|
|
4083
|
+
approval input fails the run with a private diagnostic rather than starting a fresh model turn.
|
|
4084
|
+
|
|
4071
4085
|
`stitchkit/agent-runtime/coding-tools` returns ordinary direct runtime tools named `read_file`,
|
|
4072
4086
|
`write_file`, `search_files`, `apply_patch`, `run_command` and optional `read_output`. Every call passes a
|
|
4073
4087
|
required host authorization callback. File paths are relative, bounded and contained after
|
|
@@ -6332,6 +6346,171 @@ The bound handle intentionally has no `connect()` or `disconnect()`. Its
|
|
|
6332
6346
|
`on`/`emit`/`request`, rejection and timeout semantics are exactly the path used
|
|
6333
6347
|
by `createRealtimeClient`; only transport construction/lifecycle differs.
|
|
6334
6348
|
|
|
6349
|
+
## Snapshot + event state synchronization
|
|
6350
|
+
|
|
6351
|
+
`createLiveStateController` is the optional browser-safe state machine between a
|
|
6352
|
+
validated transport binding and any renderer. It solves one problem: install a
|
|
6353
|
+
snapshot and every event after that snapshot's consistency point without a race.
|
|
6354
|
+
It does not create a socket, choose a cursor, retry a transport, store history or
|
|
6355
|
+
invent ordering for the application.
|
|
6356
|
+
|
|
6357
|
+
```ts
|
|
6358
|
+
import {
|
|
6359
|
+
createLiveStateController,
|
|
6360
|
+
type LiveStateEventDecision,
|
|
6361
|
+
type LiveStateSource,
|
|
6362
|
+
} from 'stitchkit'
|
|
6363
|
+
|
|
6364
|
+
type View = { revision: number; rows: readonly Row[] }
|
|
6365
|
+
type Change = { revision: number; row: Row }
|
|
6366
|
+
|
|
6367
|
+
const applyChange = (state: View, event: Change): LiveStateEventDecision<View> => {
|
|
6368
|
+
if (event.revision <= state.revision) return { outcome: 'duplicate' }
|
|
6369
|
+
if (event.revision !== state.revision + 1) return { outcome: 'gap' }
|
|
6370
|
+
return {
|
|
6371
|
+
outcome: 'applied',
|
|
6372
|
+
state: { revision: event.revision, rows: [...state.rows, event.row] },
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6375
|
+
|
|
6376
|
+
const live = createLiveStateController({
|
|
6377
|
+
source,
|
|
6378
|
+
applyEvent: applyChange,
|
|
6379
|
+
maxBufferedEvents: 128,
|
|
6380
|
+
maxBufferedBytes: 256 * 1024,
|
|
6381
|
+
sizeOfEvent: encodedChangeBytes,
|
|
6382
|
+
})
|
|
6383
|
+
|
|
6384
|
+
const unsubscribe = live.subscribe(render)
|
|
6385
|
+
await live.start()
|
|
6386
|
+
// On a gap/overflow or source loss, choose when the UI should resync.
|
|
6387
|
+
const status = live.getSnapshot()
|
|
6388
|
+
if (status.phase === 'resync-required' || status.phase === 'unavailable') {
|
|
6389
|
+
await live.resync()
|
|
6390
|
+
}
|
|
6391
|
+
|
|
6392
|
+
unsubscribe()
|
|
6393
|
+
await live.close()
|
|
6394
|
+
```
|
|
6395
|
+
|
|
6396
|
+
The source boundary is the important part:
|
|
6397
|
+
|
|
6398
|
+
```ts
|
|
6399
|
+
interface LiveStateSource<State, Event> {
|
|
6400
|
+
open(input: {
|
|
6401
|
+
signal: AbortSignal
|
|
6402
|
+
onEvent(event: Event): void
|
|
6403
|
+
onUnavailable(): void
|
|
6404
|
+
}): Promise<{ snapshot: State; close(): void | Promise<void> }>
|
|
6405
|
+
}
|
|
6406
|
+
```
|
|
6407
|
+
|
|
6408
|
+
`onEvent` is available before `open()` begins asynchronous work. By the time
|
|
6409
|
+
`open()` resolves, the source guarantees that every event after the returned
|
|
6410
|
+
snapshot's consistency point has already been or will be passed to that callback.
|
|
6411
|
+
The controller buffers early events within both explicit limits, installs the
|
|
6412
|
+
snapshot, drains in order, then becomes `live`. A late result from an earlier
|
|
6413
|
+
`resync()` generation is fenced. Non-cooperative caller-owned cleanup is asked to
|
|
6414
|
+
stop but cannot hold controller settlement.
|
|
6415
|
+
|
|
6416
|
+
`subscribe()` listeners are synchronous external-store notifications: read the
|
|
6417
|
+
published snapshot and schedule rendering elsewhere. A listener that returns a
|
|
6418
|
+
Promise is removed after its first call, preventing unresolved UI work from
|
|
6419
|
+
accumulating per event. Source `close()` must be idempotent because an abort-aware
|
|
6420
|
+
binding may have started cleanup before the controller calls it.
|
|
6421
|
+
|
|
6422
|
+
At most two physical source `open()` / `close()` operations in total may remain
|
|
6423
|
+
unsettled. If a caller-owned source ignores cancellation beyond that operation
|
|
6424
|
+
bound, `resync()` returns
|
|
6425
|
+
`unavailable/controller-capacity` without opening another generation. When a slot
|
|
6426
|
+
settles, the controller publishes `resync-required/controller-capacity`; the host
|
|
6427
|
+
may retry explicitly. This bounds controller-retained work without inventing a
|
|
6428
|
+
transport retry loop.
|
|
6429
|
+
|
|
6430
|
+
### Socket.IO binding
|
|
6431
|
+
|
|
6432
|
+
Use an acknowledged operation whose server handler establishes the subscription
|
|
6433
|
+
before it captures/returns the snapshot. For example, the server can join the
|
|
6434
|
+
socket to the resource room, capture revision `N`, then acknowledge that snapshot;
|
|
6435
|
+
ordered Socket.IO frames after that point reach the already-installed handler:
|
|
6436
|
+
|
|
6437
|
+
```ts
|
|
6438
|
+
const source: LiveStateSource<View, Change> = {
|
|
6439
|
+
async open({ signal, onEvent, onUnavailable }) {
|
|
6440
|
+
const offEvent = socket.on('view:changed', onEvent)
|
|
6441
|
+
const offConnection = socket.onConnectionChange((connected) => {
|
|
6442
|
+
if (!connected) onUnavailable()
|
|
6443
|
+
})
|
|
6444
|
+
let closed = false
|
|
6445
|
+
const close = () => {
|
|
6446
|
+
if (closed) return
|
|
6447
|
+
closed = true
|
|
6448
|
+
offEvent()
|
|
6449
|
+
offConnection()
|
|
6450
|
+
}
|
|
6451
|
+
signal.addEventListener('abort', close, { once: true })
|
|
6452
|
+
|
|
6453
|
+
try {
|
|
6454
|
+
const snapshot = await socket.request('view:open', { timeoutMs: 5_000 })
|
|
6455
|
+
return { snapshot, close }
|
|
6456
|
+
} catch (error) {
|
|
6457
|
+
close()
|
|
6458
|
+
throw error
|
|
6459
|
+
}
|
|
6460
|
+
},
|
|
6461
|
+
}
|
|
6462
|
+
```
|
|
6463
|
+
|
|
6464
|
+
Socket.IO still owns physical reconnect. A reconnected transport only means the
|
|
6465
|
+
connection is open; call `resync()` when application state needs a fresh
|
|
6466
|
+
generation. If the application has replay, its source may resume from its opaque
|
|
6467
|
+
cursor and return an accepted consistency point. If history expired or a cursor is
|
|
6468
|
+
incompatible, the source must acquire a fresh authoritative snapshot or reject the
|
|
6469
|
+
open; the controller does not classify or compare opaque cursors itself.
|
|
6470
|
+
|
|
6471
|
+
### One-way HTTP stream binding
|
|
6472
|
+
|
|
6473
|
+
NDJSON/SSE can use the same receiver semantics when **one response generation**
|
|
6474
|
+
starts with a schema-validated snapshot frame and every later frame is a validated
|
|
6475
|
+
event. Attach `parseNDJSON` or the typed contract-stream reader, parse the first
|
|
6476
|
+
frame before resolving `open()`, and pump remaining frames into `onEvent`. Abort
|
|
6477
|
+
that response in `close()`.
|
|
6478
|
+
|
|
6479
|
+
A separate `GET /snapshot` followed by `GET /events` is not this boundary: a
|
|
6480
|
+
change can land between the two requests and disappear unless the application
|
|
6481
|
+
supplies a watermark/replay protocol. The controller intentionally cannot make
|
|
6482
|
+
that uncoordinated recipe safe.
|
|
6483
|
+
|
|
6484
|
+
### Rendering, cache and process lifecycle
|
|
6485
|
+
|
|
6486
|
+
For replaceable progress, let the reducer replace the absolute view at each
|
|
6487
|
+
accepted revision. For ordered records, append only the exact next revision and
|
|
6488
|
+
return `gap` otherwise. Both use the same controller; their ordering policy stays
|
|
6489
|
+
in their reducers. `getSnapshot()` + `subscribe()` works headlessly and with
|
|
6490
|
+
`useSyncExternalStore`. A React Query application can update its existing query
|
|
6491
|
+
cache from a subscriber after `phase === 'live'`; no second hook or store adapter
|
|
6492
|
+
is required. Cache `markFresh` windows suppress local echoes, while revision/cursor
|
|
6493
|
+
classification detects duplicates—those are different policies.
|
|
6494
|
+
|
|
6495
|
+
A server process that owns such a receiver can place `start()` and `close()` in
|
|
6496
|
+
an existing `defineManagedResource` and include it in `createApplication`.
|
|
6497
|
+
Readiness follows a successful `live` snapshot; shutdown calls `close()`. Stitchkit
|
|
6498
|
+
does not add another supervisor, reconnect loop or durable event database.
|
|
6499
|
+
|
|
6500
|
+
When migrating a hand-written receiver, remove only the superseded attach/snapshot
|
|
6501
|
+
race loop, retry timer and listener bookkeeping. Keep the application's schemas,
|
|
6502
|
+
authorization, reducer, cursor/replay policy and durable storage. Development
|
|
6503
|
+
proxying and Vite HMR remain frontend tooling; they are described in
|
|
6504
|
+
[frontend integrations](./frontend-integrations.md) and never travel through live
|
|
6505
|
+
application event envelopes.
|
|
6506
|
+
|
|
6507
|
+
The Agent harness control server follows the same ordering: it installs the
|
|
6508
|
+
conversation attachment before awaiting the authoritative snapshot and rolls the
|
|
6509
|
+
attachment back if that read fails. A host adapter installs its delivery callback,
|
|
6510
|
+
issues `attach`, and supplies the returned snapshot through its live-state source;
|
|
6511
|
+
the existing Agent cursor and view reducers still own runtime epochs, durable
|
|
6512
|
+
versions and transcript projection.
|
|
6513
|
+
|
|
6335
6514
|
### Request-response over realtime
|
|
6336
6515
|
|
|
6337
6516
|
For an event with an `ack` schema, `request()` is the Promise form of the same
|
|
@@ -11271,7 +11450,7 @@ description: One machine-readable statement a repository makes about itself —
|
|
|
11271
11450
|
type: architecture
|
|
11272
11451
|
status: active
|
|
11273
11452
|
created: 2026-08-25
|
|
11274
|
-
updated: 2026-08-
|
|
11453
|
+
updated: 2026-08-30
|
|
11275
11454
|
---
|
|
11276
11455
|
|
|
11277
11456
|
# Project declaration
|
|
@@ -11306,6 +11485,32 @@ mode that produces a running, wrong deployment rather than an error.
|
|
|
11306
11485
|
|
|
11307
11486
|
## Why declare yourself
|
|
11308
11487
|
|
|
11488
|
+
### Identity is not product membership
|
|
11489
|
+
|
|
11490
|
+
The exported names `ProjectDeclaration` and `ProjectIdentity` describe the buildable source/artifact
|
|
11491
|
+
declared by a repository. A singular `identity` does **not** make a product project and a repository
|
|
11492
|
+
the same entity, nor does it identify a local checkout or a harness session.
|
|
11493
|
+
|
|
11494
|
+
| Entity | Meaning and owner |
|
|
11495
|
+
| --- | --- |
|
|
11496
|
+
| Product project | A product boundary whose repository membership is explicitly maintained outside this declaration |
|
|
11497
|
+
| Repository | Versioned source; its declaration describes roles, build outputs and release requirements |
|
|
11498
|
+
| Checkout | A local working copy of a repository revision; local paths and credentials belong to its host |
|
|
11499
|
+
| Harness workspace | The host-selected working scope for a session, not an implied product or membership registry |
|
|
11500
|
+
|
|
11501
|
+
Membership is many-to-many. For example, an external registry may declare product A includes
|
|
11502
|
+
repositories `service-a` and `shared-library`, while product B includes `service-b` and the same
|
|
11503
|
+
`shared-library`. Both products can read the library's unchanged declaration. Installing that library
|
|
11504
|
+
as a dependency, placing a checkout beside another, or naming a harness workspace does not create
|
|
11505
|
+
membership. The embedding product/registry owns these explicit relationships and their access policy.
|
|
11506
|
+
|
|
11507
|
+
A private companion repository can be part of a product without becoming a separate product. Its
|
|
11508
|
+
relationship and working context stay in an authorized private registry, never in a potentially public
|
|
11509
|
+
library declaration. No registry or membership fields are required here; the declaration remains
|
|
11510
|
+
optional. Existing exports and schema version 1 are unchanged.
|
|
11511
|
+
|
|
11512
|
+
### One statement, several readers
|
|
11513
|
+
|
|
11309
11514
|
Because the statements exist either way, and without a schema they exist three
|
|
11310
11515
|
times. A repository already says how many roles it runs (in a process file),
|
|
11311
11516
|
which variables it needs (in a Zod schema), what it builds (in a script) and
|
|
@@ -11501,6 +11706,16 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
11501
11706
|
| `defineRealtimeContract` | function | Zod-first shared Socket.IO event contract — [guide](../guide/realtime.md#zod-first-event-contract) |
|
|
11502
11707
|
| `createRealtimeClient` | function | inferred, runtime-validated Socket.IO client — [guide](../guide/realtime.md#client--createrealtimeclient) |
|
|
11503
11708
|
| `bindRealtimeClient` | function | bind contract validation and typed acknowledgements to an existing Stitchkit client transport without owning its lifecycle |
|
|
11709
|
+
| `createLiveStateController` | function | keep typed application state current across one source-owned snapshot/event generation with finite pre-snapshot buffering, generation fencing and explicit resync — [guide](../guide/realtime.md#snapshot--event-state-synchronization) |
|
|
11710
|
+
| `LiveStateController` | _type_ | renderer-neutral `start` / `resync` / `getSnapshot` / `subscribe` / `close` handle |
|
|
11711
|
+
| `LiveStateControllerConfig` | _type_ | typed source, reducer, explicit event/byte bounds, event sizing and isolated error hooks |
|
|
11712
|
+
| `LiveStateControllerSnapshot` / `LiveStateControllerStatus` | _types_ | current value plus phase, generation, buffer and application/duplicate/gap/refusal counters |
|
|
11713
|
+
| `LiveStateControllerStatusSchema` | schema | strict runtime validation for controller status metadata |
|
|
11714
|
+
| `LiveStatePhaseSchema` / `LiveStatePhase` | schema / _type_ | `idle`, `opening`, `live`, `resync-required`, `unavailable` or `closed` |
|
|
11715
|
+
| `LiveStateStopReasonSchema` / `LiveStateStopReason` | schema / _type_ | explicit gap, overflow, source loss, controller failure and bounded `controller-capacity` reasons |
|
|
11716
|
+
| `LiveStateEventDecision` | _type_ | provider-owned reducer result: applied state, duplicate or gap |
|
|
11717
|
+
| `LiveStateSource` / `LiveStateSourceOpenInput` / `LiveStateSourceOpenResult` | _types_ | host binding for one continuous snapshot/event boundary; transport retry and cursor semantics remain host-owned |
|
|
11718
|
+
| `LiveStateControllerError` / `LiveStateSubscriberError` | _types_ | isolated observer failure payloads that do not change source or subscriber truth |
|
|
11504
11719
|
| `createRetainedTopics` | function | retained last-value store for sticky events — [guide](../guide/realtime.md#sticky-events) |
|
|
11505
11720
|
| `parseSSE` | function | parse an SSE `Response` into an async generator — [guide](../guide/client.md#sse) |
|
|
11506
11721
|
| `parseNDJSON` | function | parse bounded fatal-UTF-8 NDJSON; blank keep-alives are skipped and `finalLine: 'require-newline'` can make the delimiter mandatory — [guide](../guide/client.md#ndjson) |
|
|
@@ -11540,7 +11755,7 @@ The browser-and-server entrypoint. Re-exports everything from
|
|
|
11540
11755
|
| `RealtimeEmitArguments` | _type_ | emit arguments including an inferred acknowledgement callback |
|
|
11541
11756
|
| `RealtimeEventHandler` | _type_ | handler inferred from an event definition |
|
|
11542
11757
|
| `InferRealtimeEventMap` | _type_ | inferred Socket.IO-compatible event map |
|
|
11543
|
-
| `RealtimeRejectDirection` |
|
|
11758
|
+
| `RealtimeRejectDirection` / `RealtimeRejectPhase` / `RealtimeRejectReason` / `RealtimeRejectFault` | _types_ | canonical inferred rejection direction, validation phase, reason and fault classification |
|
|
11544
11759
|
| `RealtimeRejectedEvent` | _type_ | structured rejected event with event, direction, phase, reason and fault |
|
|
11545
11760
|
| `RealtimeRejectedEventHook` | _type_ | sync/async observer for structured realtime rejections |
|
|
11546
11761
|
| `ValidatedRealtimeSocket` | _type_ | runtime-validating `on`/`emit` surface inferred from registries; `emit` returns "accepted by the transport" (`false` only for a client-side disconnected drop) |
|
|
@@ -12238,7 +12453,7 @@ and introduces no store, queue or model-provider implementation of its own.
|
|
|
12238
12453
|
| `AgentHarnessFileResources` | _type_ | loader plus direct `read_resource` definition for lazy exact content |
|
|
12239
12454
|
| `createAgentHarnessControlServer` | function | transport-neutral correlated requests, observer attachments and exclusive controller leases |
|
|
12240
12455
|
| `AgentHarnessControlServer` / `AgentHarnessControlConnection` | _type_ | host server and detachable connection lifecycle; `deliver` is serialized, while required out-of-band `onOverflow` closes/aborts a slow transport before reconnect |
|
|
12241
|
-
| `AgentHarnessControlServerConfig` | _type_ | explicit per-connection pending-event
|
|
12456
|
+
| `AgentHarnessControlServerConfig` | _type_ | explicit per-connection pending-event and server-wide concurrent attachment-snapshot bounds for failure-isolated control delivery |
|
|
12242
12457
|
| `AgentHarnessPendingApproval` / `AgentHarnessApprovalDecision` | _type_ | exact durable pending request and allow/deny successor input |
|
|
12243
12458
|
|
|
12244
12459
|
Resources default to at most 64 entries, 1 MiB of total UTF-8 text and 128 diagnostics. Duplicate
|
|
@@ -12733,7 +12948,7 @@ handler pipeline without opening a TCP port.
|
|
|
12733
12948
|
| `DefineRealtimeProbeConfig` | _type_ | name, canonical scenario, explicit fixture and expected realtime outcome |
|
|
12734
12949
|
| `CreateRealtimeProbeDriverConfig` | _type_ | per-scenario foreign-transport binder and optional handler-call counter |
|
|
12735
12950
|
| `RealtimeProbeAdapter` | _type_ | connected-state observation, scenario invocation and subscription-only cleanup |
|
|
12736
|
-
| `RealtimeProbeFixture` / `RealtimeProbeScenario` | _type_ | driver input and supported event/ack/invalid/disconnect/timeout scenario vocabulary |
|
|
12951
|
+
| `RealtimeProbeFixture` / `RealtimeProbeScenario` | _type_ | driver input and supported event/ack/local-invalid/peer-refusal/disconnect/timeout scenario vocabulary |
|
|
12737
12952
|
| `RealtimeRejectionObservation` | _type_ | parsed structured realtime rejection observation |
|
|
12738
12953
|
| `RealtimeDisconnectObservation` | _type_ | normalized physical timing of a realtime disconnect |
|
|
12739
12954
|
| `TransportObservation` | _type_ | validated normalized driver result |
|
|
@@ -12784,6 +12999,11 @@ by the scaffolder that writes the first copy, and by whatever builds a source an
|
|
|
12784
12999
|
binds the artifact into a deployment. It ships from the framework so those
|
|
12785
13000
|
readers cannot hold different copies of the same schema.
|
|
12786
13001
|
|
|
13002
|
+
`identity` identifies the repository-local buildable source/artifact, not a product project, checkout
|
|
13003
|
+
or harness workspace. Product↔repository membership is explicit and many-to-many, owned by an
|
|
13004
|
+
external registry; dependency edges do not establish membership. Private companion context is never
|
|
13005
|
+
required in this public schema. See [identity boundaries](../guide/declaration.md#identity-is-not-product-membership).
|
|
13006
|
+
|
|
12787
13007
|
**Declaring yourself is optional.** A project with no `project.json` is a
|
|
12788
13008
|
complete project: nothing else in the framework imports this entrypoint, no
|
|
12789
13009
|
build, test or start path looks for a declaration, and its absence is never an
|
package/package.json
CHANGED
package/dist/index-es0h4w26.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// src/agent-runtime/terminal-status.ts
|
|
2
|
-
function isSpeakableAssistantStatus(status) {
|
|
3
|
-
return status === "completed" || status === "interrupted" || status === "committed";
|
|
4
|
-
}
|
|
5
|
-
function isAssistantHistoryEvidence(status, policy) {
|
|
6
|
-
return isSpeakableAssistantStatus(status) || status === "failed" && policy?.failedAssistant === "assistant-marked";
|
|
7
|
-
}
|
|
8
|
-
function isCompleteAgentHistoryTurn(messages, policy) {
|
|
9
|
-
if (messages[0]?.role !== "user")
|
|
10
|
-
return false;
|
|
11
|
-
const calls = new Set;
|
|
12
|
-
const completed = new Set;
|
|
13
|
-
const approvals = new Map;
|
|
14
|
-
let assistantCount = 0;
|
|
15
|
-
for (const message of messages) {
|
|
16
|
-
if (message.role === "assistant") {
|
|
17
|
-
if (!isAssistantHistoryEvidence(message.status, policy))
|
|
18
|
-
return false;
|
|
19
|
-
assistantCount += 1;
|
|
20
|
-
}
|
|
21
|
-
for (const part of message.parts) {
|
|
22
|
-
if (part.type === "tool-call") {
|
|
23
|
-
if (calls.has(part.callId))
|
|
24
|
-
return false;
|
|
25
|
-
calls.add(part.callId);
|
|
26
|
-
} else if (part.type === "tool-approval-request") {
|
|
27
|
-
if (!calls.has(part.callId) || completed.has(part.callId) || approvals.has(part.approvalId))
|
|
28
|
-
return false;
|
|
29
|
-
if ([...approvals.values()].some((approval) => approval.callId === part.callId))
|
|
30
|
-
return false;
|
|
31
|
-
approvals.set(part.approvalId, { callId: part.callId, answered: false });
|
|
32
|
-
} else if (part.type === "tool-approval-response") {
|
|
33
|
-
const approval = approvals.get(part.approvalId);
|
|
34
|
-
if (!approval || approval.answered)
|
|
35
|
-
return false;
|
|
36
|
-
approval.answered = true;
|
|
37
|
-
} else if (part.type === "tool-result") {
|
|
38
|
-
if (!calls.has(part.callId) || completed.has(part.callId))
|
|
39
|
-
return false;
|
|
40
|
-
const approval = [...approvals.values()].find((entry) => entry.callId === part.callId);
|
|
41
|
-
if (approval && !approval.answered)
|
|
42
|
-
return false;
|
|
43
|
-
completed.add(part.callId);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return assistantCount > 0 && calls.size === completed.size && [...approvals.values()].every((approval) => approval.answered);
|
|
48
|
-
}
|
|
49
|
-
function assistantStatus(reason) {
|
|
50
|
-
if (reason === "success" || reason === "policy_stop" || reason === "provider_stop") {
|
|
51
|
-
return "completed";
|
|
52
|
-
}
|
|
53
|
-
if (reason === "superseded")
|
|
54
|
-
return "superseded";
|
|
55
|
-
if (reason === "absorbed")
|
|
56
|
-
return "superseded";
|
|
57
|
-
if (reason === "interrupted" || reason === "cancelled" || reason === "shutdown") {
|
|
58
|
-
return "interrupted";
|
|
59
|
-
}
|
|
60
|
-
return "failed";
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export { isAssistantHistoryEvidence, isCompleteAgentHistoryTurn, assistantStatus };
|